Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Model: openai/gpt-5.4
Generated: 2026-04-01
Book: Claude Code VS OpenCode: Architecture, Design and The Road Ahead
Chapter: 7 — MCP: The USB-C of AI
Token Usage: ~12,500 input + ~2,000 output (estimated)

7.2 MCP Implementation Across Three Systems

If Chapter 7.1 explained why MCP matters in theory, this section asks a different question: what does it look like when three real agent systems implement it? OpenCode, Claude Code, and Oh-My-OpenCode (OMO) all treat MCP as strategically important, but they express that importance differently. Reading the code makes the contrast clear. OpenCode aims for a broad, reusable client substrate. Claude Code builds a much deeper, product-grade MCP platform. OMO takes a more creative route by combining built-in remote MCPs, Claude Code compatibility loading, and skill-embedded MCP servers that can travel with reusable skills.

OpenCode: the broad open-source MCP substrate

OpenCode’s MCP implementation lives primarily in packages/opencode/src/mcp/, with index.ts as the center of gravity and auth.ts, oauth-provider.ts, and oauth-callback.ts filling in authentication support. The design is notable for how much standard MCP surface it covers in a relatively compact package.

First, OpenCode is a full MCP client, not a token gesture. It supports multiple transports from the official SDK, including:

  • StdioClientTransport for local subprocess servers
  • SSEClientTransport for remote SSE servers
  • StreamableHTTPClientTransport for streamable HTTP servers

That already gives it strong deployment breadth. A local filesystem MCP, a remote SaaS search MCP, and a streaming web service can all be consumed through the same client layer.

Second, OpenCode actively converts MCP capabilities into its internal tool world. In mcp/index.ts, convertMcpTool() turns an MCP tool definition into an AI SDK dynamic tool. This is an important bridging step. MCP servers speak in JSON Schema terms; OpenCode’s execution pipeline expects tool objects that its runtime and models can consume. So the system normalizes schemas, forces type: "object", disables unexpected extra properties, and wraps execution in a call to client.callTool(...). This is a classic adapter pattern: MCP becomes a native citizen inside the host runtime rather than an alien subsystem.

Third, OpenCode manages more than tools. It also fetches prompts and resources through listPrompts() and listResources(), caches metadata, and publishes events when tool lists change. That matters because a serious MCP client cannot stop at “tool calls work.” MCP is a richer protocol, and OpenCode respects that richness.

Fourth, OpenCode includes meaningful OAuth support. The code in auth.ts stores access tokens, refresh tokens, client information, code verifier state, and OAuth state in mcp-auth.json. oauth-provider.ts implements an MCP OAuth client provider, while oauth-callback.ts runs the callback server and validates state to reduce CSRF risk. This is not enterprise-scale auth machinery, but it is enough to make real remote MCP usage practical instead of theoretical.

The result is that OpenCode has excellent breadth. It covers most of the protocol surface an open-source host needs: tools, resources, prompts, local and remote transports, OAuth-aware remote flows, dynamic conversion into the host’s tool runtime, and lifecycle cleanup. It feels like infrastructure meant for others to build upon.

Claude Code: the deep, productized MCP stack

Claude Code’s implementation, centered on src/services/mcp/client.ts, is on another scale entirely. The file is 3,348 lines long, which is a signal in itself. This is not just “MCP support.” It is a full product subsystem with auth, policy, UI integration, transport variations, Claude.ai integration, internal server support, and advanced interaction models.

The first striking difference is transport depth. Claude Code supports stdio, sse, http, ws, and sdk server types in its schemas, plus special internal types such as claudeai-proxy. It also has an explicit InProcessTransport for linked in-process communication and SdkControlTransport for SDK MCP servers that run inside another process boundary but are controlled by Claude Code. That means Claude Code is not just consuming the public MCP ecosystem; it is using MCP as an internal systems boundary as well.

Second, Claude Code goes far beyond basic OAuth. Its MCP auth stack handles OAuth discovery, token refresh, token revocation, cached auth state, callback ports, claude.ai auth interactions, and even XAA-style configurations. The auth.ts implementation is large because remote MCP in a production product is messy: consent flows fail, tokens expire, metadata varies, and users need recovery paths. Claude Code embraces that complexity rather than hiding from it.

Third, Claude Code integrates MCP into the product’s broader UX and governance model. There is explicit support for elicitation, where an MCP server can request structured user input or URL-based confirmation and the client can queue, render, and complete that interaction through the app state. elicitationHandler.ts is a good example: the client registers request handlers, waits for user response, emits analytics, and processes completion notifications. In other words, Claude Code does not treat MCP as just tool execution. It treats MCP as interactive product functionality.

Fourth, Claude Code adds channel permissions and policy-aware gating for certain MCP servers. The channelNotification.ts and related files show that some MCP servers are treated as communication channels with specific authentication and allowlist rules. This is an example of commercial hardening: once MCP reaches real users, you need differentiated trust policies, not just generic connectivity.

Fifth, Claude Code includes an official registry layer through officialRegistry.ts, which fetches and caches official MCP URLs from Anthropic’s registry endpoint. This is a subtle but important move. It indicates ecosystem curation, not just raw protocol support. In open ecosystems, discoverability and trust become product problems.

Finally, Claude Code ties MCP to Claude.ai integration and internal SDK servers. It can fetch eligible Claude.ai MCP configs, proxy them as MCP servers, and bridge SDK-side servers through SdkControlClientTransport. That is a very deep use of MCP: one protocol used for external integrations, internal components, product connectors, and ecosystem distribution.

If OpenCode emphasizes breadth, Claude Code emphasizes depth. It is what MCP looks like when a protocol becomes part of a commercial operating environment.

OMO: creative recombination on top of OpenCode

Oh-My-OpenCode approaches MCP differently. It does not try to out-build Claude Code’s full MCP client stack. Instead, it combines several clever ideas.

First, OMO ships three built-in remote MCPs in src/mcp/:

  • websearch via Exa or Tavily
  • context7 for documentation lookup
  • grep_app for GitHub code search

These are small configuration wrappers, but they are strategically chosen. They map directly to recurring agent research needs: web discovery, official docs, and real-world code examples. OMO is not trying to expose every possible MCP server by default. It picks the three that most improve autonomous agent performance.

Second, OMO includes a Claude Code MCP loader in src/features/claude-code-mcp-loader/. It reads .mcp.json configurations from multiple scopes, transforms them, and imports them into OMO/OpenCode format. This is a migration bridge. Instead of telling users to rebuild their MCP setups from scratch, OMO says: bring your Claude Code MCP ecosystem with you.

Third, OMO introduces skill-embedded MCPs. This is arguably the most original idea of the three systems. A skill can ship with its own MCP configuration, and SkillMcpManager manages connections for those servers. The manager supports both stdio and HTTP-style connections, performs env expansion, handles retry/reconnect behavior, manages OAuth providers, and maintains connection pooling/caching keyed by session, skill, and server name. Idle clients are cleaned up automatically. This turns MCP from a global app configuration into a modular capability bundled with reusable expertise.

That design has major implications. In most systems, skills are prompt-level artifacts and MCPs are host-level infrastructure. OMO partially fuses them. A skill is no longer just “instructions for how to think”; it can also carry “private external capability for how to act.” That is an unusually powerful extensibility pattern.

The skill_mcp tool in src/tools/skill-mcp/tools.ts makes this usable. It lets the agent invoke a tool, resource, or prompt from an MCP server declared inside a loaded skill. That means the skill package can ship both behavioral guidance and its own external integration surface. It is an elegant answer to a real problem: specialized expertise often needs specialized tools.

Comparative judgment

We can summarize the three implementations with a simple triad:

  • OpenCode = breadth
  • Claude Code = depth
  • OMO = creativity

OpenCode’s strength is being an open, capable, reusable MCP foundation. Claude Code’s strength is turning MCP into a fully governed product subsystem with auth, registry, permissions, interactive elicitation, in-process bridges, and cloud integration. OMO’s strength is recombination: built-in research MCPs, Claude Code compatibility loading, and skill-embedded MCPs with managed lifecycles.

This comparison also reveals an important lesson for agent architecture. MCP support is not one thing. It has at least three layers:

  1. Protocol coverage: transports, tool calls, resources, prompts, auth
  2. Product integration: permissions, UI, state, recovery, governance
  3. Extensibility design: how MCP fits plugins, skills, and user migration paths

OpenCode is strongest at layer 1. Claude Code dominates layer 2. OMO is the most inventive at layer 3.

And that is exactly why MCP is such a powerful lens for comparing agent systems. It reveals not just whether a system supports a protocol, but what kind of platform the system is trying to become.