Skip to content

Commit 2534429

Browse files
committed
fix: load and pass MCP servers from .claude/mcp.json to SDK query
The SDK's query() function accepts options.mcpServers but we were never reading .claude/mcp.json and passing those servers to the SDK. This meant MCP tools were unavailable to Claude during Discord queries. Added loadMcpServers() which: - Reads .claude/mcp.json from the workDir - Cleans configs to match McpStdioServerConfig shape - Resolves workspaceFolder placeholders in args - Passes servers via options.mcpServers to the SDK query
1 parent 2514b96 commit 2534429

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

claude/client.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
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";
22
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+
}
337

438
export type { SDKAgentDefinition, SDKModelInfo };
539

@@ -105,6 +139,9 @@ export async function sendToClaudeCode(
105139
// Clean up session ID
106140
const cleanedSessionId = sessionId ? cleanSessionId(sessionId) : undefined;
107141

142+
// Load MCP servers from .claude/mcp.json
143+
const mcpServers = await loadMcpServers(workDir);
144+
108145
// Wrap with comprehensive error handling
109146
const executeWithErrorHandling = async (overrideModel?: string) => {
110147
try {
@@ -160,6 +197,8 @@ export async function sendToClaudeCode(
160197
...(modelOptions?.enableFileCheckpointing && { enableFileCheckpointing: true }),
161198
...(modelOptions?.sandbox && { sandbox: modelOptions.sandbox }),
162199
...(modelOptions?.outputFormat && { outputFormat: modelOptions.outputFormat }),
200+
// MCP servers from .claude/mcp.json
201+
...(mcpServers && { mcpServers }),
163202
env: envVars,
164203
},
165204
};

0 commit comments

Comments
 (0)