@aisy/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/dist/agent-loop/index.d.ts +4 -0
- package/dist/agent-loop/index.d.ts.map +1 -0
- package/dist/agent-loop/index.js +352 -0
- package/dist/agent-loop/index.js.map +1 -0
- package/dist/agent-loop/types.d.ts +183 -0
- package/dist/agent-loop/types.d.ts.map +1 -0
- package/dist/agent-loop/types.js +3 -0
- package/dist/agent-loop/types.js.map +1 -0
- package/dist/bin/aisy.d.ts +3 -0
- package/dist/bin/aisy.d.ts.map +1 -0
- package/dist/bin/aisy.js +14 -0
- package/dist/bin/aisy.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +114 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/context-engine/index.d.ts +4 -0
- package/dist/context-engine/index.d.ts.map +1 -0
- package/dist/context-engine/index.js +126 -0
- package/dist/context-engine/index.js.map +1 -0
- package/dist/context-engine/types.d.ts +54 -0
- package/dist/context-engine/types.d.ts.map +1 -0
- package/dist/context-engine/types.js +4 -0
- package/dist/context-engine/types.js.map +1 -0
- package/dist/eval/index.d.ts +20 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +128 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/types.d.ts +62 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +17 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/gateway/index.d.ts +5 -0
- package/dist/gateway/index.d.ts.map +1 -0
- package/dist/gateway/index.js +288 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/types.d.ts +194 -0
- package/dist/gateway/types.d.ts.map +1 -0
- package/dist/gateway/types.js +94 -0
- package/dist/gateway/types.js.map +1 -0
- package/dist/goals/index.d.ts +11 -0
- package/dist/goals/index.d.ts.map +1 -0
- package/dist/goals/index.js +21 -0
- package/dist/goals/index.js.map +1 -0
- package/dist/goals/types.d.ts +47 -0
- package/dist/goals/types.d.ts.map +1 -0
- package/dist/goals/types.js +5 -0
- package/dist/goals/types.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +215 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/types.d.ts +148 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +4 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/memory/index.d.ts +6 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +419 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/types.d.ts +131 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +33 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/nightly/index.d.ts +4 -0
- package/dist/nightly/index.d.ts.map +1 -0
- package/dist/nightly/index.js +470 -0
- package/dist/nightly/index.js.map +1 -0
- package/dist/nightly/types.d.ts +326 -0
- package/dist/nightly/types.d.ts.map +1 -0
- package/dist/nightly/types.js +3 -0
- package/dist/nightly/types.js.map +1 -0
- package/dist/observability/index.d.ts +11 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +396 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/types.d.ts +139 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +4 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/onboarding/index.d.ts +16 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +787 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/interactive.d.ts +23 -0
- package/dist/onboarding/interactive.d.ts.map +1 -0
- package/dist/onboarding/interactive.js +45 -0
- package/dist/onboarding/interactive.js.map +1 -0
- package/dist/onboarding/types.d.ts +388 -0
- package/dist/onboarding/types.d.ts.map +1 -0
- package/dist/onboarding/types.js +35 -0
- package/dist/onboarding/types.js.map +1 -0
- package/dist/orchestration/index.d.ts +8 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +706 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/types.d.ts +391 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +30 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/personality/index.d.ts +65 -0
- package/dist/personality/index.d.ts.map +1 -0
- package/dist/personality/index.js +339 -0
- package/dist/personality/index.js.map +1 -0
- package/dist/personality/types.d.ts +103 -0
- package/dist/personality/types.d.ts.map +1 -0
- package/dist/personality/types.js +15 -0
- package/dist/personality/types.js.map +1 -0
- package/dist/provider/index.d.ts +4 -0
- package/dist/provider/index.d.ts.map +1 -0
- package/dist/provider/index.js +236 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/provider/types.d.ts +180 -0
- package/dist/provider/types.d.ts.map +1 -0
- package/dist/provider/types.js +4 -0
- package/dist/provider/types.js.map +1 -0
- package/dist/runtime/agent-cards.d.ts +14 -0
- package/dist/runtime/agent-cards.d.ts.map +1 -0
- package/dist/runtime/agent-cards.js +90 -0
- package/dist/runtime/agent-cards.js.map +1 -0
- package/dist/runtime/agent-runner.d.ts +30 -0
- package/dist/runtime/agent-runner.d.ts.map +1 -0
- package/dist/runtime/agent-runner.js +37 -0
- package/dist/runtime/agent-runner.js.map +1 -0
- package/dist/runtime/budget.d.ts +15 -0
- package/dist/runtime/budget.d.ts.map +1 -0
- package/dist/runtime/budget.js +24 -0
- package/dist/runtime/budget.js.map +1 -0
- package/dist/runtime/delegation-driver.d.ts +11 -0
- package/dist/runtime/delegation-driver.d.ts.map +1 -0
- package/dist/runtime/delegation-driver.js +132 -0
- package/dist/runtime/delegation-driver.js.map +1 -0
- package/dist/runtime/exact-cache.d.ts +10 -0
- package/dist/runtime/exact-cache.d.ts.map +1 -0
- package/dist/runtime/exact-cache.js +30 -0
- package/dist/runtime/exact-cache.js.map +1 -0
- package/dist/runtime/execute-tool.d.ts +29 -0
- package/dist/runtime/execute-tool.d.ts.map +1 -0
- package/dist/runtime/execute-tool.js +80 -0
- package/dist/runtime/execute-tool.js.map +1 -0
- package/dist/runtime/guardian.d.ts +9 -0
- package/dist/runtime/guardian.d.ts.map +1 -0
- package/dist/runtime/guardian.js +41 -0
- package/dist/runtime/guardian.js.map +1 -0
- package/dist/runtime/hook-gate.d.ts +17 -0
- package/dist/runtime/hook-gate.d.ts.map +1 -0
- package/dist/runtime/hook-gate.js +56 -0
- package/dist/runtime/hook-gate.js.map +1 -0
- package/dist/runtime/memory-adapter.d.ts +6 -0
- package/dist/runtime/memory-adapter.d.ts.map +1 -0
- package/dist/runtime/memory-adapter.js +38 -0
- package/dist/runtime/memory-adapter.js.map +1 -0
- package/dist/runtime/nightly-adapters.d.ts +48 -0
- package/dist/runtime/nightly-adapters.d.ts.map +1 -0
- package/dist/runtime/nightly-adapters.js +139 -0
- package/dist/runtime/nightly-adapters.js.map +1 -0
- package/dist/runtime/nightly-generator.d.ts +10 -0
- package/dist/runtime/nightly-generator.d.ts.map +1 -0
- package/dist/runtime/nightly-generator.js +335 -0
- package/dist/runtime/nightly-generator.js.map +1 -0
- package/dist/runtime/onboarding-node.d.ts +6 -0
- package/dist/runtime/onboarding-node.d.ts.map +1 -0
- package/dist/runtime/onboarding-node.js +356 -0
- package/dist/runtime/onboarding-node.js.map +1 -0
- package/dist/runtime/provider-anthropic.d.ts +43 -0
- package/dist/runtime/provider-anthropic.d.ts.map +1 -0
- package/dist/runtime/provider-anthropic.js +148 -0
- package/dist/runtime/provider-anthropic.js.map +1 -0
- package/dist/runtime/provider-cli.d.ts +18 -0
- package/dist/runtime/provider-cli.d.ts.map +1 -0
- package/dist/runtime/provider-cli.js +73 -0
- package/dist/runtime/provider-cli.js.map +1 -0
- package/dist/runtime/provider-openai.d.ts +30 -0
- package/dist/runtime/provider-openai.d.ts.map +1 -0
- package/dist/runtime/provider-openai.js +114 -0
- package/dist/runtime/provider-openai.js.map +1 -0
- package/dist/runtime/providers.d.ts +43 -0
- package/dist/runtime/providers.d.ts.map +1 -0
- package/dist/runtime/providers.js +72 -0
- package/dist/runtime/providers.js.map +1 -0
- package/dist/runtime/sandbox-bash.d.ts +21 -0
- package/dist/runtime/sandbox-bash.d.ts.map +1 -0
- package/dist/runtime/sandbox-bash.js +51 -0
- package/dist/runtime/sandbox-bash.js.map +1 -0
- package/dist/runtime/scoped-tool-executor.d.ts +10 -0
- package/dist/runtime/scoped-tool-executor.d.ts.map +1 -0
- package/dist/runtime/scoped-tool-executor.js +30 -0
- package/dist/runtime/scoped-tool-executor.js.map +1 -0
- package/dist/runtime/session-log.d.ts +6 -0
- package/dist/runtime/session-log.d.ts.map +1 -0
- package/dist/runtime/session-log.js +54 -0
- package/dist/runtime/session-log.js.map +1 -0
- package/dist/runtime/settings.d.ts +24 -0
- package/dist/runtime/settings.d.ts.map +1 -0
- package/dist/runtime/settings.js +29 -0
- package/dist/runtime/settings.js.map +1 -0
- package/dist/runtime/spawn-plan.d.ts +13 -0
- package/dist/runtime/spawn-plan.d.ts.map +1 -0
- package/dist/runtime/spawn-plan.js +107 -0
- package/dist/runtime/spawn-plan.js.map +1 -0
- package/dist/runtime/spend.d.ts +41 -0
- package/dist/runtime/spend.d.ts.map +1 -0
- package/dist/runtime/spend.js +0 -0
- package/dist/runtime/spend.js.map +1 -0
- package/dist/runtime/sub-agent-runner.d.ts +19 -0
- package/dist/runtime/sub-agent-runner.d.ts.map +1 -0
- package/dist/runtime/sub-agent-runner.js +47 -0
- package/dist/runtime/sub-agent-runner.js.map +1 -0
- package/dist/safety/grants.d.ts +7 -0
- package/dist/safety/grants.d.ts.map +1 -0
- package/dist/safety/grants.js +53 -0
- package/dist/safety/grants.js.map +1 -0
- package/dist/safety/index.d.ts +72 -0
- package/dist/safety/index.d.ts.map +1 -0
- package/dist/safety/index.js +464 -0
- package/dist/safety/index.js.map +1 -0
- package/dist/safety/types.d.ts +254 -0
- package/dist/safety/types.d.ts.map +1 -0
- package/dist/safety/types.js +3 -0
- package/dist/safety/types.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +463 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/types.d.ts +177 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +3 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/testing/clock.d.ts +8 -0
- package/dist/testing/clock.d.ts.map +1 -0
- package/dist/testing/clock.js +13 -0
- package/dist/testing/clock.js.map +1 -0
- package/dist/testing/effect-verifier.d.ts +15 -0
- package/dist/testing/effect-verifier.d.ts.map +1 -0
- package/dist/testing/effect-verifier.js +27 -0
- package/dist/testing/effect-verifier.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/provider-fake.d.ts +14 -0
- package/dist/testing/provider-fake.d.ts.map +1 -0
- package/dist/testing/provider-fake.js +18 -0
- package/dist/testing/provider-fake.js.map +1 -0
- package/dist/testing/sandbox-stub.d.ts +15 -0
- package/dist/testing/sandbox-stub.d.ts.map +1 -0
- package/dist/testing/sandbox-stub.js +15 -0
- package/dist/testing/sandbox-stub.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +0 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/types.d.ts +138 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/triggers/index.d.ts +4 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +187 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/types.d.ts +74 -0
- package/dist/triggers/types.d.ts.map +1 -0
- package/dist/triggers/types.js +5 -0
- package/dist/triggers/types.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Canonical descriptor hashing (ADR-0013, CSO-M2)
|
|
4
|
+
// sha256 over name + description + inputSchema + rwClassInputs, tools sorted
|
|
5
|
+
// by name, object keys deep-sorted — byte-stable for identical descriptors.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
function sortDeep(value) {
|
|
8
|
+
if (Array.isArray(value))
|
|
9
|
+
return value.map(sortDeep);
|
|
10
|
+
if (value !== null && typeof value === 'object') {
|
|
11
|
+
const out = {};
|
|
12
|
+
for (const key of Object.keys(value).sort()) {
|
|
13
|
+
out[key] = sortDeep(value[key]);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
export function canonicalDescriptorHash(tools) {
|
|
20
|
+
const canonical = [...tools]
|
|
21
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
22
|
+
.map(t => sortDeep({
|
|
23
|
+
name: t.name,
|
|
24
|
+
description: t.description,
|
|
25
|
+
inputSchema: t.inputSchema,
|
|
26
|
+
rwClassInputs: t.rwClassInputs ?? {},
|
|
27
|
+
}));
|
|
28
|
+
return createHash('sha256').update(JSON.stringify(canonical), 'utf8').digest('hex');
|
|
29
|
+
}
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// makeMCPManager — the deterministic connect gauntlet + call path (ADR-0013).
|
|
32
|
+
// Pure code; no model decision anywhere on this surface.
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
export function makeMCPManager(deps) {
|
|
35
|
+
const entryFor = (name) => deps.allowlist?.servers.find(s => s.name === name);
|
|
36
|
+
/** Per-process minimal-scope env: ONLY the server's own token (CSO-M4). */
|
|
37
|
+
const envFor = (entry) => {
|
|
38
|
+
if (entry.tokenEnv === null)
|
|
39
|
+
return {};
|
|
40
|
+
const token = deps.resolveToken(entry.tokenEnv);
|
|
41
|
+
if (token === null)
|
|
42
|
+
return 'unresolved';
|
|
43
|
+
return { [entry.tokenEnv]: token };
|
|
44
|
+
};
|
|
45
|
+
const hostOf = (endpoint) => {
|
|
46
|
+
try {
|
|
47
|
+
return new URL(endpoint).host;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return endpoint;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
verifyHash(entry, live) {
|
|
55
|
+
return canonicalDescriptorHash(live) === entry.descriptorHash;
|
|
56
|
+
},
|
|
57
|
+
// Connect gauntlet: allowlist -> pin present -> hash present -> egress ->
|
|
58
|
+
// token -> spawn -> live pin -> tools/list -> hash verify -> menu.
|
|
59
|
+
// Every refusal happens BEFORE the next side effect (fail-closed).
|
|
60
|
+
async connect(name) {
|
|
61
|
+
const entry = entryFor(name);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
deps.emit('mcp.refused', { server: name, reason: 'not-allowlisted' });
|
|
64
|
+
return { kind: 'refused', reason: 'not-allowlisted' };
|
|
65
|
+
}
|
|
66
|
+
if (!entry.pin) {
|
|
67
|
+
deps.emit('mcp.refused', { server: name, reason: 'no-pin' });
|
|
68
|
+
return { kind: 'refused', reason: 'no-pin' };
|
|
69
|
+
}
|
|
70
|
+
if (!entry.descriptorHash) {
|
|
71
|
+
deps.emit('mcp.refused', { server: name, reason: 'no-hash' });
|
|
72
|
+
return { kind: 'refused', reason: 'no-hash' };
|
|
73
|
+
}
|
|
74
|
+
// HTTP endpoints must be on the Safety egress allowlist BEFORE any contact.
|
|
75
|
+
if (entry.transport === 'streamable-http' && entry.endpoint) {
|
|
76
|
+
if (!deps.isEgressAllowed(hostOf(entry.endpoint))) {
|
|
77
|
+
deps.emit('mcp.refused', { server: name, reason: 'egress-blocked' });
|
|
78
|
+
return { kind: 'refused', reason: 'egress-blocked' };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Fail-closed on unresolved tokens — never a shared/fallback credential.
|
|
82
|
+
const env = envFor(entry);
|
|
83
|
+
if (env === 'unresolved') {
|
|
84
|
+
deps.emit('mcp.refused', { server: name, reason: 'token-unresolved' });
|
|
85
|
+
return { kind: 'refused', reason: 'token-unresolved' };
|
|
86
|
+
}
|
|
87
|
+
const handle = deps.spawnProcess(entry.command ?? [entry.endpoint ?? ''], env);
|
|
88
|
+
try {
|
|
89
|
+
// Live version must equal the pin BEFORE tools/list is trusted.
|
|
90
|
+
const livePin = await deps.resolvePin(handle);
|
|
91
|
+
if (livePin !== entry.pin) {
|
|
92
|
+
deps.emit('mcp.refused', { server: name, reason: 'pin-mismatch' });
|
|
93
|
+
return { kind: 'refused', reason: 'pin-mismatch' };
|
|
94
|
+
}
|
|
95
|
+
const live = await deps.fetchDescriptors(handle);
|
|
96
|
+
const liveHash = canonicalDescriptorHash(live);
|
|
97
|
+
if (liveHash !== entry.descriptorHash) {
|
|
98
|
+
// Rug-pull defense: server disabled until an operator approves the diff.
|
|
99
|
+
// The card carries BOTH the previously-approved (pinned) descriptors and
|
|
100
|
+
// the new (live) set, so the operator can see exactly what changed.
|
|
101
|
+
const diffCard = {
|
|
102
|
+
server: name,
|
|
103
|
+
oldHash: entry.descriptorHash,
|
|
104
|
+
newHash: liveHash,
|
|
105
|
+
descriptorDiff: { previous: entry.descriptors ?? [], live },
|
|
106
|
+
};
|
|
107
|
+
deps.emit('mcp.disabled_hash_mismatch', { server: name });
|
|
108
|
+
deps.emit('mcp.diff_card_emitted', diffCard);
|
|
109
|
+
return { kind: 'disabled', reason: 'hash-mismatch', diffCard };
|
|
110
|
+
}
|
|
111
|
+
// Menu derivation: human-authored summary verbatim; null -> quarantined
|
|
112
|
+
// generation; generation failure -> tool OMITTED (never raw description).
|
|
113
|
+
const menu = [];
|
|
114
|
+
for (const policy of entry.tools) {
|
|
115
|
+
let summary = policy.summary;
|
|
116
|
+
if (summary === null) {
|
|
117
|
+
const descriptor = live.find(t => t.name === policy.tool);
|
|
118
|
+
// Entering the quarantined-generation path is observable regardless of
|
|
119
|
+
// outcome — a silent generator failure must still reach Observability.
|
|
120
|
+
deps.emit('mcp.summary_quarantined', { server: name, tool: policy.tool });
|
|
121
|
+
summary = descriptor ? await deps.generateSummary(descriptor) : null;
|
|
122
|
+
}
|
|
123
|
+
if (summary === null)
|
|
124
|
+
continue;
|
|
125
|
+
menu.push({
|
|
126
|
+
name: `${name}.${policy.tool}`,
|
|
127
|
+
summary,
|
|
128
|
+
rw: policy.outboundSink ? 'write' : 'read',
|
|
129
|
+
tier: policy.tier,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
deps.emit('mcp.connected', { server: name });
|
|
133
|
+
return { kind: 'connected', menu };
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
// One-shot gauntlet process; the call path spawns its own.
|
|
137
|
+
handle.terminate();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
// Resolve + invoke. `outboundSink`/`tier` always come from the human
|
|
141
|
+
// policy; capability narrowing and the motivated-call block run in code.
|
|
142
|
+
async call(namespaced, args, argProvenance = 'operator') {
|
|
143
|
+
if (!deps.allowlist)
|
|
144
|
+
throw new Error('cold start: MCP allowlist not loaded — call_mcp refused');
|
|
145
|
+
// The name is the menu's `${server}.${tool}` join. Both server names and
|
|
146
|
+
// tool names may legitimately contain '.', so a naive indexOf('.') split
|
|
147
|
+
// is ambiguous and can mis-route to the wrong policy (or fail closed on a
|
|
148
|
+
// valid call). Resolve authoritatively against the allowlist: find the
|
|
149
|
+
// (entry, policy) pair whose `${entry.name}.${policy.tool}` equals the
|
|
150
|
+
// namespaced name. Reject when the parse is ambiguous or yields an empty
|
|
151
|
+
// server/tool segment (fail-closed) — never silently bypass the policy.
|
|
152
|
+
const dot = namespaced.indexOf('.');
|
|
153
|
+
if (dot <= 0 || dot >= namespaced.length - 1) {
|
|
154
|
+
throw new Error(`malformed mcp call '${namespaced}' — expected non-empty server.tool`);
|
|
155
|
+
}
|
|
156
|
+
let entry;
|
|
157
|
+
let policy;
|
|
158
|
+
for (const candidate of deps.allowlist.servers) {
|
|
159
|
+
const prefix = `${candidate.name}.`;
|
|
160
|
+
if (!namespaced.startsWith(prefix))
|
|
161
|
+
continue;
|
|
162
|
+
const toolName = namespaced.slice(prefix.length);
|
|
163
|
+
const match = candidate.tools.find(t => t.tool === toolName);
|
|
164
|
+
if (match) {
|
|
165
|
+
if (policy)
|
|
166
|
+
throw new Error(`ambiguous mcp call '${namespaced}' — matches multiple allowlist policies`);
|
|
167
|
+
entry = candidate;
|
|
168
|
+
policy = match;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!entry || !policy)
|
|
172
|
+
throw new Error(`mcp tool '${namespaced}' has no allowlist policy`);
|
|
173
|
+
const server = entry.name;
|
|
174
|
+
const tool = policy.tool;
|
|
175
|
+
// ADR-0027: while an untrusted span is in context, outbound sinks are locked.
|
|
176
|
+
if (policy.outboundSink && deps.hasUntrustedSpan?.()) {
|
|
177
|
+
throw new Error(`mcp call '${namespaced}' denied: outbound locked (untrusted span in context)`);
|
|
178
|
+
}
|
|
179
|
+
// Motivated-call block: untrusted-derived args never reach a sink.
|
|
180
|
+
if (policy.outboundSink && argProvenance === 'untrusted') {
|
|
181
|
+
throw new Error(`mcp call '${namespaced}' denied: motivated call blocked (untrusted args on outbound sink)`);
|
|
182
|
+
}
|
|
183
|
+
// Egress is enforced per request, not only at connect (spec §8 "Egress
|
|
184
|
+
// redirection"). The call path spawns its own process and may run with no
|
|
185
|
+
// prior connect(), so re-check the endpoint host before any contact.
|
|
186
|
+
if (entry.transport === 'streamable-http' && entry.endpoint && !deps.isEgressAllowed(hostOf(entry.endpoint))) {
|
|
187
|
+
throw new Error(`mcp call '${namespaced}' denied: egress blocked for '${entry.endpoint}'`);
|
|
188
|
+
}
|
|
189
|
+
const env = envFor(entry);
|
|
190
|
+
if (env === 'unresolved')
|
|
191
|
+
throw new Error(`mcp server '${server}' token unresolved — fail-closed`);
|
|
192
|
+
const resolved = {
|
|
193
|
+
server,
|
|
194
|
+
tool,
|
|
195
|
+
args,
|
|
196
|
+
outboundSink: policy.outboundSink,
|
|
197
|
+
tier: policy.tier,
|
|
198
|
+
};
|
|
199
|
+
deps.onResolved?.(resolved);
|
|
200
|
+
const handle = deps.spawnProcess(entry.command ?? [entry.endpoint ?? ''], env);
|
|
201
|
+
try {
|
|
202
|
+
const text = deps.invokeTool ? await deps.invokeTool(handle, resolved) : '';
|
|
203
|
+
// Every result enters context as untrusted (ADR-0028); the classifier is
|
|
204
|
+
// advisory and lives in Safety (05) — absent here, the result is
|
|
205
|
+
// quarantined, never admitted as trusted.
|
|
206
|
+
deps.emit('mcp.result_quarantined', { server, tool });
|
|
207
|
+
return { provenance: 'untrusted', text, server };
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
handle.terminate();
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
export type McpTransport = "stdio" | "streamable-http";
|
|
2
|
+
/** Human-owned, version-controlled entry in the MCP allowlist config.
|
|
3
|
+
* `tier` and `outboundSink` live here; they are NEVER derived from descriptor text (CSO-M2). */
|
|
4
|
+
export interface McpServerEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
transport: McpTransport;
|
|
7
|
+
endpoint?: string;
|
|
8
|
+
command?: string[];
|
|
9
|
+
pin: string;
|
|
10
|
+
descriptorHash: string;
|
|
11
|
+
descriptors?: RawDescriptor[];
|
|
12
|
+
tokenEnv: string | null;
|
|
13
|
+
tools: McpToolPolicy[];
|
|
14
|
+
}
|
|
15
|
+
/** Per-tool policy — human-authored at allowlist time.
|
|
16
|
+
* The sole authority for `tier` and `outboundSink`; descriptor text is not an input. */
|
|
17
|
+
export interface McpToolPolicy {
|
|
18
|
+
tool: string;
|
|
19
|
+
tier: 0 | 1 | 2 | 3;
|
|
20
|
+
outboundSink: boolean;
|
|
21
|
+
summary: string | null;
|
|
22
|
+
}
|
|
23
|
+
export type ConnectResult = {
|
|
24
|
+
kind: "connected";
|
|
25
|
+
menu: McpMenuLine[];
|
|
26
|
+
} | {
|
|
27
|
+
kind: "refused";
|
|
28
|
+
reason: "not-allowlisted" | "no-pin" | "no-hash" | "pin-mismatch" | "egress-blocked" | "token-unresolved";
|
|
29
|
+
} | {
|
|
30
|
+
kind: "disabled";
|
|
31
|
+
reason: "hash-mismatch";
|
|
32
|
+
diffCard: DiffCard;
|
|
33
|
+
};
|
|
34
|
+
/** One namespaced line injected into the model's tool menu.
|
|
35
|
+
* Raw `description`, full `inputSchema`, endpoint URLs, tokens, and hashes are kept out of the prompt. */
|
|
36
|
+
export interface McpMenuLine {
|
|
37
|
+
name: string;
|
|
38
|
+
summary: string;
|
|
39
|
+
rw: "read" | "write";
|
|
40
|
+
tier: 0 | 1 | 2 | 3;
|
|
41
|
+
}
|
|
42
|
+
/** The untrusted descriptor shape returned by a server's `tools/list` call.
|
|
43
|
+
* This is input to descriptor hashing only — it never reaches the prompt verbatim. */
|
|
44
|
+
export interface RawDescriptor {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
inputSchema: Record<string, unknown>;
|
|
48
|
+
rwClassInputs?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
/** A model-selected tool resolved to a concrete call, ready for PreToolUse hook gating.
|
|
51
|
+
* `outboundSink` and `tier` are always taken from `McpToolPolicy`, never from descriptor. */
|
|
52
|
+
export interface ResolvedMcpCall {
|
|
53
|
+
server: string;
|
|
54
|
+
tool: string;
|
|
55
|
+
args: Record<string, unknown>;
|
|
56
|
+
outboundSink: boolean;
|
|
57
|
+
tier: 0 | 1 | 2 | 3;
|
|
58
|
+
}
|
|
59
|
+
/** Every MCP tools/call result is wrapped in this type at ingestion.
|
|
60
|
+
* `provenance` is set by code, never by the model (ADR-0028). */
|
|
61
|
+
export interface UntrustedResultSpan {
|
|
62
|
+
provenance: "untrusted";
|
|
63
|
+
text: string;
|
|
64
|
+
server: string;
|
|
65
|
+
}
|
|
66
|
+
/** Emitted when the live descriptor hash mismatches the stored value.
|
|
67
|
+
* Server stays disabled until an operator reviews and approves the diff. */
|
|
68
|
+
export interface DiffCard {
|
|
69
|
+
server: string;
|
|
70
|
+
oldHash: string;
|
|
71
|
+
newHash: string;
|
|
72
|
+
descriptorDiff: DescriptorDiff;
|
|
73
|
+
}
|
|
74
|
+
/** Old-vs-new descriptor pair shown to the operator on a rug-pull (hash mismatch).
|
|
75
|
+
* `previous` is the human-approved set stored in the allowlist entry (empty if none was recorded);
|
|
76
|
+
* `live` is the set just fetched from the server. */
|
|
77
|
+
export interface DescriptorDiff {
|
|
78
|
+
previous: RawDescriptor[];
|
|
79
|
+
live: RawDescriptor[];
|
|
80
|
+
}
|
|
81
|
+
export interface McpClient {
|
|
82
|
+
/** Deterministic connect gauntlet (ADR-0013). Pure code; no model call. */
|
|
83
|
+
connect(name: string): Promise<ConnectResult>;
|
|
84
|
+
/** Canonical sha256 over name + description + inputSchema + rwClassInputs, sorted by name (CSO-M2).
|
|
85
|
+
* Byte-stable: identical descriptors always produce the same hash. */
|
|
86
|
+
descriptorHash(tools: RawDescriptor[]): string;
|
|
87
|
+
/** Resolve a model-selected `server.tool` to a concrete call.
|
|
88
|
+
* The returned call re-enters Tools & Hooks (04) PreToolUse; this method NEVER executes a write. */
|
|
89
|
+
resolve(namespaced: string, args: unknown): ResolvedMcpCall;
|
|
90
|
+
/** Execute an already hook-approved call against the per-process, minimal-scope server.
|
|
91
|
+
* Returns the result span tagged `untrusted` for Safety's classifier (ADR-0028). */
|
|
92
|
+
invokeApproved(call: ResolvedMcpCall): Promise<UntrustedResultSpan>;
|
|
93
|
+
}
|
|
94
|
+
/** Allowlist config — the human-owned, version-controlled source of truth. */
|
|
95
|
+
export interface McpAllowlistConfig {
|
|
96
|
+
servers: McpServerEntry[];
|
|
97
|
+
}
|
|
98
|
+
/** Hash record stored per server after first-approval (mirrors the allowlist fields). */
|
|
99
|
+
export interface McpDescriptorHash {
|
|
100
|
+
server: string;
|
|
101
|
+
hash: string;
|
|
102
|
+
}
|
|
103
|
+
/** Observability events this component emits (Observability 12). */
|
|
104
|
+
export type McpEvent = "mcp.connected" | "mcp.refused" | "mcp.disabled_hash_mismatch" | "mcp.diff_card_emitted" | "mcp.summary_quarantined" | "mcp.result_classified" | "mcp.result_quarantined";
|
|
105
|
+
export interface McpManagerDeps {
|
|
106
|
+
/** Loaded allowlist config; absent = cold-start, fail-closed. */
|
|
107
|
+
allowlist: McpAllowlistConfig | null;
|
|
108
|
+
/** Check whether an HTTP endpoint host is on the Safety egress allowlist. */
|
|
109
|
+
isEgressAllowed(host: string): boolean;
|
|
110
|
+
/** Resolve a token by env name; returns null if unresolved. */
|
|
111
|
+
resolveToken(envName: string): string | null;
|
|
112
|
+
/** Emit an observability event. */
|
|
113
|
+
emit(event: McpEvent, payload?: unknown): void;
|
|
114
|
+
/** Stub for the quarantined summary-generation pass (Eng-9).
|
|
115
|
+
* Returns null on failure (tool omitted from menu rather than falling back to raw description). */
|
|
116
|
+
generateSummary(descriptor: RawDescriptor): Promise<string | null>;
|
|
117
|
+
/** Spy-able spawn shim — returns an opaque process handle. */
|
|
118
|
+
spawnProcess(command: string[], env: Record<string, string>): McpProcessHandle;
|
|
119
|
+
/** Fetch the live tools/list from a server process. */
|
|
120
|
+
fetchDescriptors(handle: McpProcessHandle): Promise<RawDescriptor[]>;
|
|
121
|
+
/** Resolve live version/digest from a server process (before tools/list). */
|
|
122
|
+
resolvePin(handle: McpProcessHandle): Promise<string>;
|
|
123
|
+
/** Capability-narrowing input (ADR-0027): true while an untrusted span is in context. */
|
|
124
|
+
hasUntrustedSpan?: () => boolean;
|
|
125
|
+
/** Execute an approved tools/call against a running server (injectable seam, Eng-11). */
|
|
126
|
+
invokeTool?: (handle: McpProcessHandle, call: ResolvedMcpCall) => Promise<string>;
|
|
127
|
+
/** Test seam: observe the policy-resolved call before invocation. */
|
|
128
|
+
onResolved?: (call: ResolvedMcpCall) => void;
|
|
129
|
+
}
|
|
130
|
+
/** Opaque handle to a running MCP server process (stdio) or HTTP session. */
|
|
131
|
+
export interface McpProcessHandle {
|
|
132
|
+
readonly id: string;
|
|
133
|
+
readonly env: Record<string, string>;
|
|
134
|
+
terminate(): void;
|
|
135
|
+
}
|
|
136
|
+
/** The public manager surface (narrow waist — the model only reaches this via `call_mcp`). */
|
|
137
|
+
export interface McpManager {
|
|
138
|
+
/** Run the full connect gauntlet for a named server (ADR-0013). */
|
|
139
|
+
connect(name: string): Promise<ConnectResult>;
|
|
140
|
+
/** Resolve + invoke an already-approved `server.tool` call.
|
|
141
|
+
* `argProvenance` is code-assigned by the caller (ADR-0028); untrusted-derived
|
|
142
|
+
* args on an outbound sink are blocked (motivated-call, ADR-0027). */
|
|
143
|
+
call(namespaced: string, args: Record<string, unknown>, argProvenance?: "operator" | "untrusted"): Promise<UntrustedResultSpan>;
|
|
144
|
+
/** Return true if the stored hash for the entry matches the recomputed hash.
|
|
145
|
+
* Used by the connect gauntlet; exposed for testing. */
|
|
146
|
+
verifyHash(entry: McpServerEntry, live: RawDescriptor[]): boolean;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mcp/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mcp/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,+BAA+B"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Memory, MemoryStoreDeps } from './types.js';
|
|
2
|
+
export type { Memory, Memory as MemoryStore, MemoryStoreDeps, MemoryFact } from './types.js';
|
|
3
|
+
export type { FactKey, MemoryOp, GuardVerdict, CommitResult, RankedHit, LazyLoadStep, ForgetListEntry, FrozenSnapshot, IntegrityResult, } from './types.js';
|
|
4
|
+
export { CorruptIndexError, ForgetListTamperError, BypassError, GuardBlocked, } from './types.js';
|
|
5
|
+
export declare function makeMemoryStore(deps: MemoryStoreDeps): Memory;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EAEN,eAAe,EAOhB,MAAM,YAAY,CAAA;AAGnB,YAAY,EAAE,MAAM,EAAE,MAAM,IAAI,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5F,YAAY,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAA;AAmInB,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAoW7D"}
|