Skip to content

MCP Integration

The Model Context Protocol (MCP) is an open standard for connecting agents to external tools. CodeBuddy’s MCPService speaks two transports (stdio, SSE), caches tool lists, and isolates failing servers behind per-server circuit breakers.

TransportConfigUse case
stdiocommand + argsLocal CLIs, Node scripts, Python tools — server runs as a child process
SSEurlRemote servers, shared team tools, hosted APIs

The Docker gateway (Docker Desktop’s MCP integration — one endpoint, many tools) isn’t a separate transport: it’s a stdio server entry (conventionally named docker-gateway) that runs the Docker CLI. See Docker integration.

stdio requires modal approval on first launch. MCPApprovalService hashes command + args + env-key names and persists per-workspace consent. Bump the hash → new approval prompt.

SSE requires SSRF validation on the URL. validateOutboundUrlAsync rejects private/reserved IPs and metadata endpoints (169.254.169.254, etc.).

Servers live in the VS Code setting codebuddy.mcp.servers — an object keyed by server name (not an array), in workspace or user settings.json:

{
"codebuddy.mcp.servers": {
"my-database": {
"command": "npx",
"args": ["-y", "@my-org/db-mcp-server"],
"env": { "DATABASE_URL": "postgresql://localhost:5432/mydb" }
},
"custom-api": {
"url": "http://localhost:3001/mcp",
"transport": "sse"
}
}
}

Schema:

// keyed by server name in `codebuddy.mcp.servers`
interface MCPServerConfig {
command?: string; // Executable (stdio)
args?: string[]; // Arguments
env?: Record<string, string>; // Env vars
transport?: "stdio" | "sse"; // Default: stdio
url?: string; // Required for SSE
enabled?: boolean; // Disable without removing
description?: string; // UI label
}
sequenceDiagram participant Agent participant TP as ToolProvider participant MCP as MCPService participant CB as CircuitBreaker participant Cache participant Srv as MCP Server Note over Agent, Srv: Extension activation (non-blocking) TP->>MCP: loadMCPToolsLazy() Note over Agent, Srv: First tool request Agent->>TP: getToolsAsync() TP->>MCP: Await lazy load MCP->>Cache: TTL check (5 min) alt Miss MCP->>CB: Circuit state? alt Closed CB->>Srv: getTools() Srv-->>Cache: List else Open CB-->>MCP: Fail fast else Half-open CB->>Srv: Probe Note over CB: Success → Closed<br/>Failure → Open end else Hit Cache-->>MCP: Cached list end MCP-->>TP: LangChain-wrapped MCP tools (bypass role filtering) TP-->>Agent: Core + MCP

Startup never blocks. If MCP servers are unavailable, the agent runs with core tools only; a warning lands in Output > CodeBuddy.

Per-server. Trips at 3 consecutive failures → OPEN. After 5 min cooldown → HALF_OPEN → single probe → back to CLOSED (success) or OPEN (fail). Prevents one dead server from cascading timeouts across the whole tool system.

Each server gets an MCPClient in one of four states: DISCONNECTED → CONNECTING → CONNECTED → ERROR. Auto-reconnect on unexpected transport closure. Exponential backoff: 1000 × 2^(attempt-1) capped at 30 s, max 3 attempts. Connection-closure detection retries once if the transport drops mid-call.

Tool lists cached per-client, 5-minute TTL. Invalidated on TTL expiry, explicit refreshTools(), or reconnect. Duplicate tool names across servers are disambiguated by serverName metadata on every tool.

Every MCP tool result is wrapped in <mcp_response server="..." tool="..." trust="untrusted">...</mcp_response> before reaching the LLM context. Nested closing tags in the payload are defanged. This is invariant M5 — MCP output is treated as untrusted input to the LLM.

interface MCPTool {
name: string;
description?: string;
inputSchema: { type: "object"; properties?: Record<string, unknown>; required?: string[] };
serverName: string;
metadata?: { category?: string; tags?: string[]; version?: string };
}
interface MCPToolResult {
content: Array<{ type: "text" | "image"; text?: string; data?: string; mimeType?: string }>;
isError?: boolean;
metadata?: { duration?: number; serverName?: string; toolName?: string };
}

If you want to re-approve MCP servers (e.g. after a config change), run:

CodeBuddy: Reset MCP Server Approvals

Use the MCP SDK:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "my-tools", version: "1.0.0" });
server.tool("get_weather", { city: z.string() }, async ({ city }) => {
const data = await fetchWeather(city);
return { content: [{ type: "text", text: JSON.stringify(data) }] };
});

Popular community servers: @modelcontextprotocol/server-filesystem, -github, -postgres, -brave-search.

  • Tools — the core tool list MCP tools sit alongside
  • Architecture — where MCP fits in the graph
  • Skills — higher-level integrations built on tools + MCP