mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-13 16:38:56 +02:00
fix(gbrain-status): MCP scoping is per-project, and project-local beats user scope
hasRemoteOnlyGbrainMcp scanned EVERY project's mcpServers in ~/.claude.json, so one project's remote gbrain registration reclassified broken local engines as thin-client machine-wide. It now reads user scope plus only the cwd's nearest-ancestor project key. The precedence itself was verified empirically and hermetically (fake HOME + CLAUDE_CONFIG_DIR fixtures, claude 2.1.233): with both scopes defining gbrain, 'claude mcp get gbrain' reports Scope: Local config — PROJECT-LOCAL WINS. Both in-repo consumers assumed the opposite; brain-cache's endpoint resolution flips to nearest-ancestor-project-first, and the stale user-first pin in brain-cache-roundtrip now pins the verified precedence. (The user-first jq in the brain-sync preamble resolver gets the same swap in the template block.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6955dfa348
commit
d8a207fdd7
@@ -166,7 +166,12 @@ describe('brain-cache endpoint detection', () => {
|
||||
expect(outer).not.toBe('local');
|
||||
});
|
||||
|
||||
test('detectEndpointHash still prefers user scope over project scope (#2499)', async () => {
|
||||
test('detectEndpointHash prefers project-local scope over user scope (#2392 wave)', async () => {
|
||||
// Empirically verified against claude 2.1.233 with hermetic fixtures:
|
||||
// `claude mcp get gbrain` reports "Scope: Local config" when both scopes
|
||||
// define the server — project-local WINS. The old pin here encoded the
|
||||
// opposite (user-first) assumption, which mis-hashed endpoints whenever
|
||||
// the two scopes disagreed.
|
||||
const mod = await importCache();
|
||||
const cj = join(TMP_HOME, 'claude.json');
|
||||
writeFileSync(cj, JSON.stringify({
|
||||
@@ -175,14 +180,14 @@ describe('brain-cache endpoint detection', () => {
|
||||
'/w/repo': { mcpServers: { gbrain: { url: 'https://proj.example/mcp' } } },
|
||||
},
|
||||
}));
|
||||
const userScoped = mod.detectEndpointHash(cj, '/w/repo');
|
||||
// Same file minus the user-scope entry → different hash proves user scope won.
|
||||
const conflictHash = mod.detectEndpointHash(cj, '/w/repo');
|
||||
// Same file minus the USER entry → identical hash proves project scope won.
|
||||
writeFileSync(cj, JSON.stringify({
|
||||
projects: {
|
||||
'/w/repo': { mcpServers: { gbrain: { url: 'https://proj.example/mcp' } } },
|
||||
},
|
||||
}));
|
||||
expect(mod.detectEndpointHash(cj, '/w/repo')).not.toBe(userScoped);
|
||||
expect(mod.detectEndpointHash(cj, '/w/repo')).toBe(conflictHash);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user