MCP servers are defined in opencode.jsonc under the mcp key, where each server is identified by a unique name used to reference it in prompts.[1] Once added, MCP tools are automatically available to the LLM alongside built-in tools without any additional wiring.[1] Each MCP server adds tokens to the LLM's context window; servers with large tool catalogs (e.g., the GitHub MCP server) can easily exceed the context limit.[1] MCP (Model Context Protocol) is an open standard that lets external tools and services expose callable functions to an LLM through a structured interface; each MCP server hosts one or more such tools the LLM can invoke during a conversation.
opencode mcp add interactively guides adding a local or remote MCP server to the configuration; opencode mcp list shows all configured servers and their connection status.[2] opencode mcp auth <server-name> manually triggers the OAuth browser flow for a specific MCP server; opencode mcp logout <server-name> removes stored credentials.[1] opencode mcp debug <server-name> shows auth status, tests HTTP connectivity, and attempts the OAuth discovery flow to diagnose connection issues.[1]
Local MCP servers require type: "local" and a command array (e.g., ["npx", "-y", "my-mcp-command"]); the cwd, environment, enabled, and timeout fields are optional.[1] For local MCP servers, relative paths in the cwd field resolve from the workspace root.[1] Example: adding the @modelcontextprotocol/server-everything local MCP server and referencing it in a prompt by name.[1]
Remote MCP servers require type: "remote" and a url; optional fields include enabled, headers, oauth, and timeout.[1] The timeout option for both local and remote MCP servers specifies the maximum time in milliseconds to wait when fetching tools, defaulting to 5000 (5 seconds).[1] An MCP server can be temporarily disabled without removing it from the config by setting its enabled field to false.[1] Organizations can publish default MCP server configurations via a .well-known/opencode endpoint; users can override these remote defaults by adding matching entries with enabled: true to their local config.[1]
opencode automatically handles OAuth for remote MCP servers: it detects a 401 response, initiates the OAuth flow using Dynamic Client Registration (RFC 7591) if supported, and stores tokens for future requests.[1] OAuth tokens are stored at ~/.local/share/opencode/mcp-auth.json after completing the browser-based authorization flow.[1] Pre-registered OAuth credentials (clientId, clientSecret, scope) can be supplied via the oauth object; if clientId is omitted, dynamic client registration is attempted automatically.[1] Setting oauth: false on a remote MCP server disables automatic OAuth detection, which is useful for servers that authenticate via API keys in headers instead.[1]
When connecting a remote MCP server, packages/opencode/src/mcp/index.ts attempts StreamableHTTP transport first and falls back to SSE transport, both using the same optional authProvider and headers.[3] On transport connection failure, packages/opencode/src/mcp/index.ts closes the transport via t.close() and ignores any close errors; on success the caller owns the transport and it is not closed.[3] A remote MCP entry with an unparseable URL immediately returns a failed status with the message Invalid MCP URL for "<name>" rather than throwing.[3] Pending OAuth transports are stored in a module-level Map (pendingOAuthTransports) in packages/opencode/src/mcp/index.ts, keyed by server name, so that the finishAuth flow can retrieve and reuse the already-negotiated transport.[3]
Each MCP client is created with roots capability enabled, while sampling, elicitation, and tasks capabilities are explicitly commented out in packages/opencode/src/mcp/index.ts, with issue-tracker links for each pending capability.[3] packages/opencode/src/mcp/index.ts registers a ListRootsRequestSchema handler that responds with the current project directory as a file URL, so MCP servers can discover the workspace root.[3]
packages/opencode/src/mcp/index.ts exports an MCPStatus union (Status) with five discriminated variants: connected, disabled, failed, needs_auth, and needs_client_registration.[3] McpTool in packages/opencode/src/mcp/index.ts holds a shared cached def (the raw MCP tool definition) and the owning client; the doc comment explicitly warns consumers to copy rather than mutate the def.[3] packages/opencode/src/mcp/index.ts wires the MCP Service layer by acquiring ChildProcessSpawner, McpAuth.Service, EventV2Bridge.Service, and McpBrowser.Service as dependencies.[3]
Sources