# Using MCP Servers

> Use when choosing between install, enable, disable, or delete for an MCP server; when an agent needs to discover or delegate to MCP servers; or when MCP tools fail with credential, connection, or prefixing issues.

- Skill: `friday-platform/using-mcp-servers` (Agent Skill)
- Install (CLI): `npx skillmds@latest add friday-platform/using-mcp-servers`
- Raw SKILL.md: https://api.skillmd.com/api/skills/friday-platform/using-mcp-servers/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: friday-platform (https://skillmd.com/u/friday-platform)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/friday-platform/using-mcp-servers

---


# Using MCP Servers

## Overview

There are two contexts for MCP servers: **admin** (changing what exists) and
**chat** (using what exists). Agents in chat discover and use servers directly
from the platform catalog — no workspace enable step required. Workspace
enable/disable only controls `workspace.yml` overrides, not chat visibility.

## When to Use

- User asks to add, remove, enable, disable, or configure an MCP server
- Agent must choose between `search_mcp_servers`, `install_mcp_server`,
  `enable_mcp_server`, `disable_mcp_server`, or `delete_mcp_server`
- Agent needs MCP tools inside a `delegate` sub-agent
- MCP connection fails or tool names collide across servers

## Two contexts

| Context | Who asks | What changes | Key rule |
|---------|----------|--------------|----------|
| Admin | User talking to settings / UI | Catalog or workspace config | `install`/`delete` mutate the catalog; `enable`/`disable` mutate workspace YAML |
| Chat | Agent during a conversation | Nothing — uses existing servers | `list_mcp_servers(scope?)` for the MCP-only inventory; `list_mcp_tools({serverId})` for a server's tool catalog; `describe_mcp_server({id})` for back-references (which agents/jobs use it). `enable` is irrelevant. |

**Critical:** Chat agents do not need `enable_mcp_server` to see or use a
catalog server. `enable` only adds workspace-level overrides or custom
servers to `workspace.yml`.

**Discovery tool selection:** prefer the per-domain `list_mcp_servers` for
"what MCP servers can I use?" — it returns enabled + catalog entries
without bundled-agent noise. `list_capabilities` is the cross-domain router
("I don't know whether this is an agent or an MCP server"); reach for it
only when the question genuinely spans both surfaces.

## Admin path: choosing the right tool

| User says | Tool | Why |
|-----------|------|-----|
| "Install X from the registry" / "Search for X" | `search_mcp_servers` → `install_mcp_server` | Adds to the platform catalog |
| "Add X to this workspace" | If X is in catalog: `enable_mcp_server(X)` | Copies into `workspace.yml` for non-chat uses (FSM jobs, bundled agents) |
| "Remove X from this workspace" | `disable_mcp_server(X)` | Removes from `workspace.yml`. Catalog entry stays. |
| "Delete X entirely" / "Uninstall X" | `delete_mcp_server(X)` | Destructive — removes from catalog. Only for custom/user-created servers. |

- **"Add" is ambiguous.** Ask: add to catalog (`install`) or add to workspace
  YAML (`enable`)? Chat agents don't need either.
- **"Remove" vs "Delete" is ambiguous.** Ask: remove from workspace (`disable`)
  or delete from catalog (`delete`)?
- **Disable is safe by default.** Returns 409 + `willUnlinkFrom` if agents/jobs
  reference it. Surface the list, ask the user, retry with `force: true`.

## Chat path: delegation with MCP tools

1. **Discover:** `list_mcp_servers(scope?)` — `scope=workspace` (default)
   returns enabled + available; `scope=catalog` returns the global catalog
   only; `scope=all` returns both. Each entry's `requiresConfig` empty
   means credentialed. For cross-domain "what can I do here?" questions
   that may resolve to a bundled agent or an MCP server, use
   `list_capabilities` instead.
2. **Connect if needed:** If `requiresConfig` is non-empty and `provider` is
   present (on `mcp_available`), call `connect_service(provider)`. The UI will
   fire `data-credential-linked` when the user finishes.
3. **Auto-continue:** On `data-credential-linked`, re-call `list_mcp_servers`
   to confirm `requiresConfig` is empty, then `delegate` with
   `mcpServers: [id]` and the original goal.
4. **Delegate:** `delegate` validates IDs fail-fast. Unknown or unconfigured
   IDs return `ok: false` before any connection attempt.
5. **Tool naming:** Child gets prefixed tools (`strava_getActivity`) when 2+
   servers are selected; unprefixed (`getActivity`) when 1.
6. **Graceful degradation:** One failed server does not kill the child.
   `serverFailures` surfaces reasons to the parent.

## Setting an MCP server's env vars

A server often needs config beyond a credential — a workspace slug, a region,
a log path, a base URL. Two distinct stores, picked by what the value *is*:

- **Non-secret config** (slug, path, region, URL) → `env_set`. It raises a
  confirmation card and returns `pending_confirmation` — nothing is written
  until the user confirms. Verify with `env_get` on a *later* turn. This is the
  only supported way to touch a workspace's `.env` from chat.
- **Credentials** (API keys, tokens, OAuth) → `connect_service`. Never put a
  real secret through `env_set` — the workspace `.env` is the non-secret store,
  and `env_get` masks secret-looking keys.

Never hand-edit `.env` files through `run_code` (curl/python/sed). It has
corrupted the daemon `.env` in practice. If a `delegate` or `list_mcp_tools`
call fails because a required env var is unset, the fix is `env_set`.

## Common Mistakes

| Mistake | Why it happens | Fix |
|---------|---------------|-----|
| Hand-editing `.env` via `run_code` to set a server's env var | Didn't know `env_set` exists | `env_set` for non-secret config, `connect_service` for credentials. Never curl/python the `.env`. |
| Calling `enable` so chat can use a server | Confusing workspace YAML with chat discovery | Catalog servers are visible to `list_capabilities` (as `kind: "mcp_available"`) without enable. |
| Calling `delete` when user said "remove from workspace" | Confusing catalog deletion with workspace disable | "Remove from workspace" = `disable`. "Delete from catalog" = `delete`. |
| Calling `install` when user said "add to workspace" | Catalog installation does not wire into workspace YAML | Check catalog first. If present, ask: install (catalog) or enable (workspace YAML)? |
| Delegating without calling `list_capabilities` | LLM assumes server IDs from stale prompt | Always list first. Validate IDs server-side. |
| Ignoring non-empty `requiresConfig` | Async credential check is accurate | Prompt user to `connect_service`. Do not attempt connection. |
| Re-enabling a custom server after disable | Custom servers have no catalog backing | Re-enable requires manual YAML editing. Say this explicitly. |

## Quick diagnostic

1. An agent asks for a tool that fails as unknown → do **not** create a tool-access elicitation for the guessed name. Call `list_mcp_servers` to see what's wired, then `list_mcp_tools({ serverId })` for the chosen server, and use the exact runtime-visible tool name.
2. User says "I don't see X" → `list_mcp_servers(scope=all)` to see both enabled and catalog. If it's there but `requiresConfig` is non-empty → `connect_service`.
3. User says "Add X to workspace" → Check if X is in catalog. If yes, ask:
   chat already sees it — do you mean enable for workspace YAML?
4. Disable fails → Surface `willUnlinkFrom`, confirm, retry with `force: true`.

