fix(mcp): keep codegraph_explore loaded in Claude Code and Copilot CLI (#1696)
Claude Code defers every MCP tool behind ToolSearch by default, so a fresh session sees only the tool name until the model searches for it. The explore tool now carries `_meta: { "anthropic/alwaysLoad": true }`, which exempts it on existing installs, and the Claude Code installer target writes `alwaysLoad: true` on the server entry (re-running install adds the key to an older entry). Copilot CLI tool search holds MCP tools back the same way once ~30 tools are connected, so its entry carries `deferTools: "never"`.
This commit is contained in:
@@ -41,6 +41,18 @@ import {
|
||||
CODEGRAPH_SECTION_START,
|
||||
} from '../instructions-template';
|
||||
|
||||
/**
|
||||
* The shared stdio entry plus `alwaysLoad: true`, Claude Code's exemption from
|
||||
* tool-search deferral (https://code.claude.com/docs/en/mcp#exempt-a-server-from-deferral).
|
||||
* `codegraph_explore` carries the same flag in its `_meta`, which covers an
|
||||
* entry written before this key; the entry-level key additionally makes
|
||||
* Claude Code wait for this server's tools at startup, so they are in the
|
||||
* first prompt rather than listed after the server connects in the background.
|
||||
*/
|
||||
function getClaudeMcpServerConfig() {
|
||||
return { ...getMcpServerConfig(), alwaysLoad: true };
|
||||
}
|
||||
|
||||
function configDir(loc: Location): string {
|
||||
return loc === 'global'
|
||||
? path.join(os.homedir(), '.claude')
|
||||
@@ -211,7 +223,7 @@ class ClaudeCodeTarget implements AgentTarget {
|
||||
|
||||
printConfig(loc: Location): string {
|
||||
const target = mcpJsonPath(loc);
|
||||
const snippet = JSON.stringify({ mcpServers: { codegraph: getMcpServerConfig() } }, null, 2);
|
||||
const snippet = JSON.stringify({ mcpServers: { codegraph: getClaudeMcpServerConfig() } }, null, 2);
|
||||
return `# Add to ${target}\n\n${snippet}\n`;
|
||||
}
|
||||
|
||||
@@ -231,7 +243,7 @@ export function writeMcpEntry(loc: Location): WriteResult['files'][number] {
|
||||
const file = mcpJsonPath(loc);
|
||||
const existing = readJsonFile(file);
|
||||
const before = existing.mcpServers?.codegraph;
|
||||
const after = getMcpServerConfig();
|
||||
const after = getClaudeMcpServerConfig();
|
||||
|
||||
if (jsonDeepEqual(before, after)) {
|
||||
// Already exactly what we'd write — preserve byte-identical file.
|
||||
|
||||
@@ -95,9 +95,15 @@ function copilotOnPath(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function buildCopilotMcpConfig(): { type: string; command: string; args: string[]; tools: string[] } {
|
||||
/**
|
||||
* The shared stdio entry, every tool allowed, and `deferTools: 'never'`: Copilot CLI's tool
|
||||
* search (on by default from ~30 connected tools on Claude and GPT-5.4+ models) otherwise holds
|
||||
* MCP tools back until the model searches for them, so `codegraph_explore` would be a name the
|
||||
* model has to go looking for before it can follow the "call it instead of Read" instruction.
|
||||
*/
|
||||
function buildCopilotMcpConfig(): { type: string; command: string; args: string[]; tools: string[]; deferTools: 'never' } {
|
||||
const base = getMcpServerConfig();
|
||||
return { ...base, tools: ['*'] };
|
||||
return { ...base, tools: ['*'], deferTools: 'never' };
|
||||
}
|
||||
|
||||
class CopilotCliTarget implements AgentTarget {
|
||||
|
||||
@@ -942,6 +942,12 @@ export interface ToolDefinition {
|
||||
};
|
||||
/** Behavioral hints for clients (see {@link ToolAnnotations}). */
|
||||
annotations?: ToolAnnotations;
|
||||
/**
|
||||
* MCP `_meta` on the tool definition. `anthropic/alwaysLoad: true` makes
|
||||
* Claude Code load the tool at session start instead of deferring it behind
|
||||
* its tool search (https://code.claude.com/docs/en/mcp#exempt-a-server-from-deferral).
|
||||
*/
|
||||
_meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1196,6 +1202,9 @@ export const tools: ToolDefinition[] = [
|
||||
required: ['query'],
|
||||
},
|
||||
annotations: READ_ONLY_ANNOTATIONS,
|
||||
// Loaded from the first prompt in Claude Code, which otherwise defers every
|
||||
// MCP tool behind a ToolSearch step (#1696).
|
||||
_meta: { 'anthropic/alwaysLoad': true },
|
||||
},
|
||||
{
|
||||
name: 'codegraph_status',
|
||||
|
||||
Reference in New Issue
Block a user