|
1 | | -import { query as claudeQuery, type SDKMessage, type AgentDefinition as SDKAgentDefinition, type ModelInfo as SDKModelInfo, type SdkBeta } from "@anthropic-ai/claude-agent-sdk"; |
| 1 | +import { query as claudeQuery, type SDKMessage, type AgentDefinition as SDKAgentDefinition, type ModelInfo as SDKModelInfo, type SdkBeta, type McpServerConfig } from "@anthropic-ai/claude-agent-sdk"; |
2 | 2 | import { setActiveQuery, trackMessageId, clearTrackedMessages } from "./query-manager.ts"; |
| 3 | +import * as path from "https://deno.land/std@0.208.0/path/mod.ts"; |
| 4 | + |
| 5 | +// Load MCP server configs from .claude/mcp.json |
| 6 | +async function loadMcpServers(workDir: string): Promise<Record<string, McpServerConfig> | undefined> { |
| 7 | + try { |
| 8 | + const mcpPath = path.join(workDir, ".claude", "mcp.json"); |
| 9 | + const raw = await Deno.readTextFile(mcpPath); |
| 10 | + const parsed = JSON.parse(raw); |
| 11 | + const servers = parsed?.mcpServers; |
| 12 | + if (!servers || typeof servers !== "object") return undefined; |
| 13 | + |
| 14 | + // Clean configs to match SDK's McpStdioServerConfig shape and resolve placeholders |
| 15 | + const result: Record<string, McpServerConfig> = {}; |
| 16 | + for (const [name, cfg] of Object.entries(servers)) { |
| 17 | + // deno-lint-ignore no-explicit-any |
| 18 | + const raw = cfg as any; |
| 19 | + // Resolve ${workspaceFolder:-.} placeholder in args |
| 20 | + const args = Array.isArray(raw.args) |
| 21 | + ? raw.args.map((a: string) => a.replace(/\$\{workspaceFolder:-\.?\}/g, workDir)) |
| 22 | + : undefined; |
| 23 | + result[name] = { |
| 24 | + type: "stdio" as const, |
| 25 | + command: raw.command, |
| 26 | + ...(args && { args }), |
| 27 | + ...(raw.env && { env: raw.env }), |
| 28 | + }; |
| 29 | + } |
| 30 | + console.log(`[MCP] Loaded ${Object.keys(result).length} MCP server(s): ${Object.keys(result).join(", ")}`); |
| 31 | + return result; |
| 32 | + } catch { |
| 33 | + // File doesn't exist or is invalid — no MCP servers |
| 34 | + return undefined; |
| 35 | + } |
| 36 | +} |
3 | 37 |
|
4 | 38 | export type { SDKAgentDefinition, SDKModelInfo }; |
5 | 39 |
|
@@ -105,6 +139,9 @@ export async function sendToClaudeCode( |
105 | 139 | // Clean up session ID |
106 | 140 | const cleanedSessionId = sessionId ? cleanSessionId(sessionId) : undefined; |
107 | 141 |
|
| 142 | + // Load MCP servers from .claude/mcp.json |
| 143 | + const mcpServers = await loadMcpServers(workDir); |
| 144 | + |
108 | 145 | // Wrap with comprehensive error handling |
109 | 146 | const executeWithErrorHandling = async (overrideModel?: string) => { |
110 | 147 | try { |
@@ -160,6 +197,8 @@ export async function sendToClaudeCode( |
160 | 197 | ...(modelOptions?.enableFileCheckpointing && { enableFileCheckpointing: true }), |
161 | 198 | ...(modelOptions?.sandbox && { sandbox: modelOptions.sandbox }), |
162 | 199 | ...(modelOptions?.outputFormat && { outputFormat: modelOptions.outputFormat }), |
| 200 | + // MCP servers from .claude/mcp.json |
| 201 | + ...(mcpServers && { mcpServers }), |
163 | 202 | env: envVars, |
164 | 203 | }, |
165 | 204 | }; |
|
0 commit comments