MCP Bridge — Model Context Protocol Tool Bridging

Focus Deep-Dive

MCP server discovery, configuration extraction, and tool serving for bundled plugins

6 Core Files 3 Server Formats ~800 LOC TypeScript

🔵 MCP Protocol 🟢 Stdio Servers 🟡 Config Merging 🔴 Runtime Support

📚 What is this & why does it matter?

The MCP Bridge sub-module connects OpenClaw’s plugin system with the Model Context Protocol (MCP). MCP defines a standard for AI assistants to discover and invoke tools from external servers. When a bundled plugin declares MCP servers in its manifest or .mcp.json file, this module extracts the server configurations, resolves paths, and determines runtime support. The bridge enables plugins originally built for Claude, Codex, or Cursor to expose their MCP tools to OpenClaw’s agent system.

💡 Real-world analogy

Think of the MCP Bridge as a USB hub that translates different device protocols into a universal interface. Each MCP server is a USB device with its own communication protocol. The bridge reads the device descriptor (server config), checks if the host supports it (stdio server check), and exposes the device’s capabilities (tools) through a standard API that the agent can call just like any other tool.

Contents

Architecture

flowchart TD
  subgraph Config["Configuration Sources"]
    MCPJson[".mcp.json files"]
    BundleManifest["Bundle Manifest"]
    MCPDeclared["Declared mcpServers paths"]
  end
  subgraph Extract["Config Extraction"]
    Resolve["resolveBundleMcpConfigPaths()"]
    Read["readBundleJsonObject()"]
    ExtractMap["extractMcpServerMap()"]
    MergePatch["applyMergePatch()"]
  end
  subgraph Runtime["Runtime Support"]
    Inspect["inspectBundleMcpRuntimeSupport()"]
    StdioCheck["hasSupportedStdioServer"]
    ServerNames["supported/unsupported names"]
    Diagnostics["diagnostic messages"]
  end
  subgraph Serve["Tool Serving"]
    MCPConfig["BundleMcpConfig"]
    ToolFactory["Plugin Tool Factory"]
    AgentTools["Agent Tool Registry"]
  end
  MCPJson --> Resolve
  BundleManifest --> Resolve
  MCPDeclared --> Resolve
  Resolve --> Read
  Read --> ExtractMap
  ExtractMap --> MergePatch
  MergePatch --> MCPConfig
  MCPConfig --> Inspect
  Inspect --> StdioCheck
  Inspect --> ServerNames
  Inspect --> Diagnostics
  MCPConfig --> ToolFactory
  ToolFactory --> AgentTools

Configuration flows from three sources (.mcp.json files, bundle manifests, and declared server paths) through extraction and merging, then into runtime support inspection and tool serving. The bridge resolves all config paths, extracts server maps, applies merge patches, and finally exposes validated tools to the agent registry.

Key Types

NameFileTypeDescription
BundleMcpServerConfigbundle-mcp.tsTypeArbitrary MCP server configuration (Record<string, unknown>)
BundleMcpConfigbundle-mcp.tsTypeCollection of MCP servers keyed by name
BundleMcpDiagnosticbundle-mcp.tsTypeDiagnostic message with pluginId and message string
EnabledBundleMcpConfigResultbundle-mcp.tsTypeLoaded config with diagnostics array
BundleMcpRuntimeSupportbundle-mcp.tsTypeRuntime support check: supported stdio servers, diagnostics
PluginBundleFormattypes.tsUnion‘claude’ | ‘codex’ | ‘cursor’ bundle format

MCP Config Resolution

The resolution process loads, merges, and validates MCP server configurations from multiple sources, replacing placeholders and accumulating diagnostics along the way:

sequenceDiagram
  participant Loader as Plugin Loader
  participant MCP as bundle-mcp.ts
  participant FS as File System
  participant Shared as bundle-config-shared.ts
  Loader->>MCP: loadEnabledBundleMcpConfig(rootDir, config)
  MCP->>MCP: resolveBundleMcpConfigPaths(raw, rootDir, format)
  MCP->>FS: Check .mcp.json exists
  MCP->>MCP: mergeBundlePathLists(defaults, declared)
  loop Each config path
    MCP->>Shared: readBundleJsonObject(path)
    Shared->>FS: openBoundaryFileSync(path)
    FS-->>Shared: file contents
    Shared-->>MCP: parsed JSON
    MCP->>MCP: extractMcpServerMap(raw)
    MCP->>MCP: Replace ${CLAUDE_PLUGIN_ROOT} placeholders
  end
  MCP->>MCP: applyMergePatch(accumulated, newConfig)
  MCP-->>Loader: EnabledBundleMcpConfigResult
  Loader->>MCP: inspectBundleMcpRuntimeSupport(config)
  MCP->>MCP: Check for stdio transport
  MCP-->>Loader: BundleMcpRuntimeSupport
Key detail: The ${CLAUDE_PLUGIN_ROOT} placeholder in server configs is replaced with the actual bundle root directory at resolution time. This allows .mcp.json files to use relative paths that resolve correctly regardless of where the bundle is installed.

Deep-Dive Highlights

🔧 Tool Serving

How MCP server tools are exposed to the agent tool registry

🔗 Channel Bridge

Bridging channel-specific plugins with MCP tool capabilities

🛠 Plugin Tools

Tool resolution, allowlists, and conflict management

Directory Map

Source files for MCP Bridge
📁 src/plugins/ (MCP-related files)
├── bundle-mcp.ts                 # MCP server config extraction & merging
├── bundle-config-shared.ts       # Shared bundle config utilities
├── bundle-manifest.ts            # Bundle manifest (MCP paths declared here)
├── tools.ts                      # Plugin tool resolution & serving
├── capability-provider-runtime.ts # Capability-level provider runtime
├── slots.ts                      # Plugin slot assignment
├── bundled-sources.ts            # Bundled plugin source resolution
└── runtime/
    └── gateway-request-scope.ts  # Gateway request scope for plugin tools

Code Examples

Extract and iterate over MCP server configurations from a bundle’s .mcp.json file:

// Extracting MCP server configuration from a bundle
import { extractMcpServerMap } from "./bundle-mcp.js";

const raw = JSON.parse(fs.readFileSync(".mcp.json", "utf-8"));
const servers = extractMcpServerMap(raw);

// servers = {
//   "filesystem": { command: "npx", args: ["-y", "@mcp/filesystem", "/path"] },
//   "github": { command: "npx", args: ["-y", "@mcp/github"], env: { GITHUB_TOKEN: "..." } }
// }

for (const [name, config] of Object.entries(servers)) {
  console.log(`MCP Server: ${name}`, config);
}