| name | using-mcp-servers |
| description | 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. |
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
- 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.
- 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.
- 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.
- Delegate:
delegate validates IDs fail-fast. Unknown or unconfigured
IDs return ok: false before any connection attempt.
- Tool naming: Child gets prefixed tools (
strava_getActivity) when 2+
servers are selected; unprefixed (getActivity) when 1.
- 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
- 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.
- 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.
- 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?
- Disable fails → Surface
willUnlinkFrom, confirm, retry with force: true.