feat(tokens): MCP tool-schema deferral check + CLI-over-MCP lever (v5.10 B4)
By default Claude Code defers MCP tool schemas (names-only, ~120 tok; full
schemas on demand via tool search). CA-TOK-006 detects config-file signals that
force the FULL schemas into the always-loaded prefix every turn:
- settings.json env.ENABLE_TOOL_SEARCH="false" (high)
- "ToolSearch" in permissions.deny (high)
- configured model is a Haiku model (medium)
- per-server .mcp.json alwaysLoad:true (CC v2.1.121+) (high)
auto[:N] is threshold mode (info, not a trigger).
New engine lib/mcp-deferral.mjs: pure assessMcpDeferral({settings,mcpServers})
(unit-tested, no IO) + thin IO wrapper assessMcpDeferralForRepo shared by TOK and
GAP. Severity scales with aggregate forced-upfront tokens (medium-confidence
reasons cap at medium). feature-gap cliOverMcpLeverFinding fires only as a
companion to CA-TOK-006 (prefer gh/aws/gcloud over MCP for common ops).
Honest scoping (Verifiseringsplikt): triggers on config files ONLY — never
process.env shell vars. Vertex / custom ANTHROPIC_BASE_URL / runtime /model
switch are launch state (would flap snapshots machine-dependently), so they are
DISCLOSED in every finding, not triggered. Tool-level anthropic/alwaysLoad and
claude.ai connectors likewise disclosed. Mechanism verified 2026-06-23 against
code.claude.com/docs (context-window.md, mcp.md#configure-tool-search +
#exempt-a-server-from-deferral, costs.md); the prefix-cache invalidation claim
was NOT-CONFIRMED in docs and is not asserted.
alwaysLoad added to CA-MCP VALID_SERVER_FIELDS (no longer flagged as unknown).
active-config-reader surfaces per-server alwaysLoad. Byte-stable: CA-TOK-006
fires only on new conditions; frozen v5.0.0 + SC-5 snapshots untouched.
Tests 1215 -> 1239 (engine 16, integration 5, lever 2, mcp-field guard 1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
42e48514e4
commit
8f7e196046
13 changed files with 692 additions and 2 deletions
|
|
@ -136,6 +136,36 @@ describe('MCP scanner — stray `trust` field is an unknown field (verify-first,
|
|||
});
|
||||
});
|
||||
|
||||
describe('MCP scanner — `alwaysLoad` is a valid field (v5.10 B4, verify-first 2026-06-23)', () => {
|
||||
let result;
|
||||
let tmpRoot;
|
||||
|
||||
beforeEach(async () => {
|
||||
resetCounter();
|
||||
tmpRoot = await mkdtemp(join(tmpdir(), 'ca-mcp-alwaysload-'));
|
||||
// alwaysLoad exempts a server from MCP tool-schema deferral (CC v2.1.121+).
|
||||
// Verified against code.claude.com/docs/en/mcp.md#exempt-a-server-from-deferral.
|
||||
const mcp = {
|
||||
mcpServers: {
|
||||
core: { type: 'http', url: 'https://mcp.example.com/mcp', alwaysLoad: true },
|
||||
},
|
||||
};
|
||||
await writeFile(join(tmpRoot, '.mcp.json'), JSON.stringify(mcp, null, 2) + '\n', 'utf8');
|
||||
const discovery = await discoverConfigFiles(tmpRoot);
|
||||
result = await scan(tmpRoot, discovery);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (tmpRoot) await rm(tmpRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('does NOT flag `alwaysLoad` as an unknown MCP server field', () => {
|
||||
const f = result.findings.find(x => x.title.includes('Unknown MCP server field')
|
||||
&& /alwaysLoad/.test(x.description || ''));
|
||||
assert.equal(f, undefined, 'alwaysLoad is a valid field and must not be flagged');
|
||||
});
|
||||
});
|
||||
|
||||
describe('MCP scanner — env-var false positives (CC 2.1.139/2.1.142, Batch 1)', () => {
|
||||
let tmpRoot;
|
||||
let envFindings;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue