@mcp-index/sdk 0.18.1 → 0.19.1
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/CHANGELOG.md +20 -1
- package/README.md +178 -0
- package/dist/src/ai.d.ts +96 -0
- package/dist/src/ai.d.ts.map +1 -0
- package/dist/src/ai.js +151 -0
- package/dist/src/ai.js.map +1 -0
- package/dist/src/gate.d.ts +7 -0
- package/dist/src/gate.d.ts.map +1 -1
- package/dist/src/gate.js +36 -2
- package/dist/src/gate.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lock/check.d.ts +143 -0
- package/dist/src/lock/check.d.ts.map +1 -0
- package/dist/src/lock/check.js +274 -0
- package/dist/src/lock/check.js.map +1 -0
- package/dist/src/lock/digest.d.ts +48 -0
- package/dist/src/lock/digest.d.ts.map +1 -0
- package/dist/src/lock/digest.js +234 -0
- package/dist/src/lock/digest.js.map +1 -0
- package/dist/src/lock/events.d.ts +82 -0
- package/dist/src/lock/events.d.ts.map +1 -0
- package/dist/src/lock/events.js +80 -0
- package/dist/src/lock/events.js.map +1 -0
- package/dist/src/lock/index.d.ts +20 -0
- package/dist/src/lock/index.d.ts.map +1 -0
- package/dist/src/lock/index.js +14 -0
- package/dist/src/lock/index.js.map +1 -0
- package/dist/src/lock/lock.d.ts +195 -0
- package/dist/src/lock/lock.d.ts.map +1 -0
- package/dist/src/lock/lock.js +1075 -0
- package/dist/src/lock/lock.js.map +1 -0
- package/dist/src/lock/pg.d.ts +150 -0
- package/dist/src/lock/pg.d.ts.map +1 -0
- package/dist/src/lock/pg.js +539 -0
- package/dist/src/lock/pg.js.map +1 -0
- package/dist/src/lock/rawList.d.ts +127 -0
- package/dist/src/lock/rawList.d.ts.map +1 -0
- package/dist/src/lock/rawList.js +561 -0
- package/dist/src/lock/rawList.js.map +1 -0
- package/dist/src/lock/signing.d.ts +35 -0
- package/dist/src/lock/signing.d.ts.map +1 -0
- package/dist/src/lock/signing.js +85 -0
- package/dist/src/lock/signing.js.map +1 -0
- package/dist/src/lock/store.d.ts +149 -0
- package/dist/src/lock/store.d.ts.map +1 -0
- package/dist/src/lock/store.js +459 -0
- package/dist/src/lock/store.js.map +1 -0
- package/dist/src/schemaDiff.d.ts +21 -2
- package/dist/src/schemaDiff.d.ts.map +1 -1
- package/dist/src/schemaDiff.js +79 -1
- package/dist/src/schemaDiff.js.map +1 -1
- package/package.json +31 -2
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lock check (section 9): a pure decision over one complete listing, and a
|
|
3
|
+
* per-connection CallGate that allows `tools/call` only for names shown on the
|
|
4
|
+
* latest checked listing.
|
|
5
|
+
*
|
|
6
|
+
* Lock mode has no first-use pin, no auto-accept and no re-pin. Nothing here
|
|
7
|
+
* writes to a lock; the lock changes only through LockStore.approve/revoke.
|
|
8
|
+
*/
|
|
9
|
+
import { compareCodePoints, hasTopMeta, instructionsDigest, metaDigest, toolDigest } from "./digest.js";
|
|
10
|
+
import { LockError, POSTURES, identityKey } from "./lock.js";
|
|
11
|
+
export const LOCK_REFUSAL_CODE = -32011;
|
|
12
|
+
export const LOCK_REFUSAL_MESSAGE = "Tool withheld by lock";
|
|
13
|
+
export function isPosture(value) {
|
|
14
|
+
return typeof value === "string" && POSTURES.includes(value);
|
|
15
|
+
}
|
|
16
|
+
function nameOf(tool) {
|
|
17
|
+
if (tool === null || typeof tool !== "object" || Array.isArray(tool))
|
|
18
|
+
return null;
|
|
19
|
+
const name = Object.getOwnPropertyDescriptor(tool, "name")?.value;
|
|
20
|
+
return typeof name === "string" ? name : null;
|
|
21
|
+
}
|
|
22
|
+
function freezeAll(value) {
|
|
23
|
+
return Object.freeze(value);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check one complete listing against a lock, or against a whole-lock failure.
|
|
27
|
+
* `listing.tools` is the raw array as received; nothing is fetched again.
|
|
28
|
+
*/
|
|
29
|
+
export function checkListing(lock, identity, listing, posture) {
|
|
30
|
+
if (!isPosture(posture))
|
|
31
|
+
throw new Error(`unknown posture ${String(posture)}`);
|
|
32
|
+
const guard = posture !== "monitor";
|
|
33
|
+
const raw = listing.tools;
|
|
34
|
+
if (!Array.isArray(raw))
|
|
35
|
+
throw new TypeError("listing has no tools array");
|
|
36
|
+
const served = listing.instructions;
|
|
37
|
+
const hasInstructions = served !== undefined && served !== null;
|
|
38
|
+
const shown = [];
|
|
39
|
+
const shownIndexes = [];
|
|
40
|
+
const withheld = new Map();
|
|
41
|
+
const flagged = new Map();
|
|
42
|
+
const callable = new Set();
|
|
43
|
+
const meta = new Map();
|
|
44
|
+
const stripMeta = new Set();
|
|
45
|
+
const tools = [];
|
|
46
|
+
if (lock instanceof LockError) {
|
|
47
|
+
for (const tool of raw) {
|
|
48
|
+
const name = nameOf(tool);
|
|
49
|
+
if (name === null)
|
|
50
|
+
continue;
|
|
51
|
+
withheld.set(name, lock.reason);
|
|
52
|
+
tools.push(freezeAll({ name, served: toolDigest(tool), approved: null, decision: "withheld", reason: lock.reason, meta: null }));
|
|
53
|
+
}
|
|
54
|
+
return freezeAll({
|
|
55
|
+
posture,
|
|
56
|
+
shown,
|
|
57
|
+
withheld,
|
|
58
|
+
flagged,
|
|
59
|
+
removed: [],
|
|
60
|
+
instructions: null,
|
|
61
|
+
stripInstructions: hasInstructions,
|
|
62
|
+
lockError: lock.reason,
|
|
63
|
+
callable,
|
|
64
|
+
shownIndexes,
|
|
65
|
+
meta: new Map(),
|
|
66
|
+
stripMeta: new Set(),
|
|
67
|
+
tools,
|
|
68
|
+
served: raw.length,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const shard = lock.shards.get(identityKey(identity)) ?? null;
|
|
72
|
+
const counts = new Map();
|
|
73
|
+
for (const tool of raw) {
|
|
74
|
+
const name = nameOf(tool);
|
|
75
|
+
if (name !== null)
|
|
76
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
77
|
+
}
|
|
78
|
+
raw.forEach((tool, index) => {
|
|
79
|
+
const name = nameOf(tool);
|
|
80
|
+
if (name === null)
|
|
81
|
+
return; // never shown, never callable
|
|
82
|
+
const digest = toolDigest(tool);
|
|
83
|
+
const entry = shard?.tools.get(name) ?? null;
|
|
84
|
+
let reason;
|
|
85
|
+
if (shard === null)
|
|
86
|
+
reason = "unlocked-server";
|
|
87
|
+
else if ((counts.get(name) ?? 0) > 1)
|
|
88
|
+
reason = "duplicate-name";
|
|
89
|
+
else if (digest === null)
|
|
90
|
+
reason = "no-digest";
|
|
91
|
+
else if (entry === null)
|
|
92
|
+
reason = "new-tool";
|
|
93
|
+
else if (entry.digest !== digest)
|
|
94
|
+
reason = "upstream-changed";
|
|
95
|
+
else
|
|
96
|
+
reason = null;
|
|
97
|
+
const approved = entry?.digest ?? null;
|
|
98
|
+
if (reason !== null && guard) {
|
|
99
|
+
withheld.set(name, reason);
|
|
100
|
+
tools.push(freezeAll({ name, served: digest, approved, decision: "withheld", reason, meta: null }));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (reason !== null)
|
|
104
|
+
flagged.set(name, reason);
|
|
105
|
+
let flag = null;
|
|
106
|
+
if (hasTopMeta(tool)) {
|
|
107
|
+
const approvedMeta = entry?.metaDigest;
|
|
108
|
+
if (approvedMeta === undefined)
|
|
109
|
+
flag = "meta-unapproved";
|
|
110
|
+
else if (metaDigest(tool) !== approvedMeta)
|
|
111
|
+
flag = "meta-changed";
|
|
112
|
+
meta.set(name, freezeAll({ relay: flag === null || !guard, flag }));
|
|
113
|
+
if (flag !== null && guard)
|
|
114
|
+
stripMeta.add(index);
|
|
115
|
+
}
|
|
116
|
+
shown.push(name);
|
|
117
|
+
shownIndexes.push(index);
|
|
118
|
+
callable.add(name);
|
|
119
|
+
tools.push(freezeAll({ name, served: digest, approved, decision: "shown", reason, meta: flag }));
|
|
120
|
+
});
|
|
121
|
+
const removed = shard === null ? [] : [...shard.tools.keys()].filter((n) => !counts.has(n)).sort(compareCodePoints);
|
|
122
|
+
let instructions = null;
|
|
123
|
+
let stripInstructions = false;
|
|
124
|
+
if (hasInstructions) {
|
|
125
|
+
const locked = shard?.instructions ?? null;
|
|
126
|
+
const digest = typeof served === "string" ? instructionsDigest(served) : null;
|
|
127
|
+
if (locked === null || digest !== locked) {
|
|
128
|
+
instructions = "instructions-changed";
|
|
129
|
+
stripInstructions = guard;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return freezeAll({
|
|
133
|
+
posture,
|
|
134
|
+
shown,
|
|
135
|
+
withheld,
|
|
136
|
+
flagged,
|
|
137
|
+
removed,
|
|
138
|
+
instructions,
|
|
139
|
+
stripInstructions,
|
|
140
|
+
lockError: null,
|
|
141
|
+
callable,
|
|
142
|
+
shownIndexes,
|
|
143
|
+
meta,
|
|
144
|
+
stripMeta,
|
|
145
|
+
tools,
|
|
146
|
+
served: raw.length,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/** Decide instructions alone, for a host that sees them before any listing (initialize). */
|
|
150
|
+
export function checkInstructions(lock, identity, instructions, posture) {
|
|
151
|
+
if (instructions === undefined || instructions === null)
|
|
152
|
+
return { reason: null, strip: false };
|
|
153
|
+
const d = checkListing(lock, identity, { tools: [], instructions }, posture);
|
|
154
|
+
if (d.lockError !== null)
|
|
155
|
+
return { reason: d.lockError, strip: true };
|
|
156
|
+
return { reason: d.instructions, strip: d.stripInstructions };
|
|
157
|
+
}
|
|
158
|
+
/** 'allow', or the reason sent in data.reason of a -32011 error. */
|
|
159
|
+
export function checkCall(decision, name) {
|
|
160
|
+
if (decision === null)
|
|
161
|
+
return "no-listing";
|
|
162
|
+
if (decision.lockError !== null)
|
|
163
|
+
return decision.lockError;
|
|
164
|
+
if (decision.callable.has(name))
|
|
165
|
+
return "allow";
|
|
166
|
+
return decision.withheld.get(name) ?? "not-listed";
|
|
167
|
+
}
|
|
168
|
+
export function refusalError(name, reason) {
|
|
169
|
+
const data = name === null ? { reason } : { reason, tool: name };
|
|
170
|
+
return { code: LOCK_REFUSAL_CODE, message: LOCK_REFUSAL_MESSAGE, data };
|
|
171
|
+
}
|
|
172
|
+
/** Error thrown to callers who check through CallGate.enforce. */
|
|
173
|
+
export class LockRefusal extends Error {
|
|
174
|
+
code = LOCK_REFUSAL_CODE;
|
|
175
|
+
reason;
|
|
176
|
+
tool;
|
|
177
|
+
constructor(tool, reason) {
|
|
178
|
+
super(LOCK_REFUSAL_MESSAGE);
|
|
179
|
+
this.name = "LockRefusal";
|
|
180
|
+
this.tool = tool;
|
|
181
|
+
this.reason = reason;
|
|
182
|
+
}
|
|
183
|
+
toJsonRpcError() {
|
|
184
|
+
return refusalError(this.tool, this.reason);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/** Default age after which a call first reloads the snapshot (section 9.8), as in the Python host. */
|
|
188
|
+
export const DEFAULT_MAX_STALENESS_MS = 60_000;
|
|
189
|
+
/**
|
|
190
|
+
* Per-connection allow-list. `record` replaces the decision only when a
|
|
191
|
+
* complete listing has been checked. A list_changed notification does not
|
|
192
|
+
* touch it. While a listing is in progress (section 9.2.1: `beginListing`
|
|
193
|
+
* until `record` or `markUnreachable`) every call is refused with
|
|
194
|
+
* `no-listing`, so nothing is called on the strength of a listing that is
|
|
195
|
+
* being replaced.
|
|
196
|
+
*
|
|
197
|
+
* Order of reasons (section 9.5): `no-listing` while a listing is in
|
|
198
|
+
* progress or before any listing has ended; then the whole-lock error of the
|
|
199
|
+
* latest completed listing, which a later failed listing does not clear;
|
|
200
|
+
* then `unreachable` after a failed listing; then `lock-stale`; then the
|
|
201
|
+
* per-name answer.
|
|
202
|
+
*/
|
|
203
|
+
export class CallGate {
|
|
204
|
+
#decision = null;
|
|
205
|
+
#snapshotAt = 0;
|
|
206
|
+
#snapshotId = null;
|
|
207
|
+
#unreachable = false;
|
|
208
|
+
#collecting = false;
|
|
209
|
+
#maxStalenessMs;
|
|
210
|
+
#now;
|
|
211
|
+
constructor(options = {}) {
|
|
212
|
+
const max = options.maxStalenessMs ?? DEFAULT_MAX_STALENESS_MS;
|
|
213
|
+
if (!(max >= 0))
|
|
214
|
+
throw new Error("maxStalenessMs must be >= 0");
|
|
215
|
+
this.#maxStalenessMs = max;
|
|
216
|
+
this.#now = options.now ?? Date.now;
|
|
217
|
+
}
|
|
218
|
+
get decision() {
|
|
219
|
+
return this.#decision;
|
|
220
|
+
}
|
|
221
|
+
get snapshotId() {
|
|
222
|
+
return this.#snapshotId;
|
|
223
|
+
}
|
|
224
|
+
/** A listing started: the host asked for its first page. */
|
|
225
|
+
beginListing() {
|
|
226
|
+
this.#collecting = true;
|
|
227
|
+
}
|
|
228
|
+
/** The listing in progress ended without a decision and without failing. */
|
|
229
|
+
endListing() {
|
|
230
|
+
this.#collecting = false;
|
|
231
|
+
}
|
|
232
|
+
get listingInProgress() {
|
|
233
|
+
return this.#collecting;
|
|
234
|
+
}
|
|
235
|
+
/** Install the decision for the latest complete listing. */
|
|
236
|
+
record(decision, snapshot) {
|
|
237
|
+
this.#decision = decision;
|
|
238
|
+
this.#snapshotId = snapshot.snapshotId;
|
|
239
|
+
this.#snapshotAt = snapshot.loadedAt;
|
|
240
|
+
this.#unreachable = false;
|
|
241
|
+
this.#collecting = false;
|
|
242
|
+
}
|
|
243
|
+
/** The latest listing failed; refuse every call with `unreachable` until one completes. */
|
|
244
|
+
markUnreachable() {
|
|
245
|
+
this.#unreachable = true;
|
|
246
|
+
this.#collecting = false;
|
|
247
|
+
}
|
|
248
|
+
get unreachable() {
|
|
249
|
+
return this.#unreachable;
|
|
250
|
+
}
|
|
251
|
+
isStale() {
|
|
252
|
+
if (this.#decision === null)
|
|
253
|
+
return false;
|
|
254
|
+
return this.#now() - this.#snapshotAt > this.#maxStalenessMs;
|
|
255
|
+
}
|
|
256
|
+
check(name) {
|
|
257
|
+
const decision = this.#decision;
|
|
258
|
+
if (this.#collecting || (decision === null && !this.#unreachable))
|
|
259
|
+
return "no-listing";
|
|
260
|
+
if (decision !== null && decision.lockError !== null)
|
|
261
|
+
return decision.lockError;
|
|
262
|
+
if (this.#unreachable || decision === null)
|
|
263
|
+
return "unreachable";
|
|
264
|
+
if (this.isStale())
|
|
265
|
+
return "lock-stale";
|
|
266
|
+
return checkCall(decision, name);
|
|
267
|
+
}
|
|
268
|
+
enforce(name) {
|
|
269
|
+
const verdict = this.check(name);
|
|
270
|
+
if (verdict !== "allow")
|
|
271
|
+
throw new LockRefusal(name, verdict);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/lock/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Definition Digest, Tool Set Digest and instructions digest (lock draft 1,
|
|
3
|
+
* section 2), over RFC 8785 (JCS) canonical JSON.
|
|
4
|
+
*
|
|
5
|
+
* The input is what JSON.parse returned for the raw message, never an SDK model.
|
|
6
|
+
* The serializer walks own keys with Object.keys and writes the output string
|
|
7
|
+
* directly, so a member named `__proto__` (which JSON.parse creates as an own
|
|
8
|
+
* property) is covered like any other. Nothing here copies through object
|
|
9
|
+
* spread or plain-object assignment, either of which would turn `__proto__`
|
|
10
|
+
* into a prototype change and drop it from the digest.
|
|
11
|
+
*
|
|
12
|
+
* Separate from ../canonical.ts on purpose: that file is the legacy pin hash
|
|
13
|
+
* (NFC, ensure_ascii, Python float repr). This one is plain RFC 8785 and does
|
|
14
|
+
* not normalize Unicode.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DIGEST_PREFIX = "sha256:";
|
|
17
|
+
/** Numbers at or above this magnitude get no digest (checked on the parsed value). */
|
|
18
|
+
export declare const NUMBER_LIMIT: number;
|
|
19
|
+
export declare class CanonicalizationError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare function hasLoneSurrogate(text: string): boolean;
|
|
23
|
+
/** RFC 8785 text of a JSON value. Throws CanonicalizationError. */
|
|
24
|
+
export declare function canonicalize(value: unknown): string;
|
|
25
|
+
export declare function sha256Hex(data: string | Uint8Array): string;
|
|
26
|
+
/** Digest of one raw Tool object, or null when it has no digest (section 2.1). */
|
|
27
|
+
export declare function toolDigest(tool: unknown): string | null;
|
|
28
|
+
/** Contract file bytes for a tool: sha256 of these is the tool digest. */
|
|
29
|
+
export declare function canonicalBody(tool: unknown): Buffer | null;
|
|
30
|
+
/**
|
|
31
|
+
* Meta digest (section 2.3, draft 1c): sha256 of the RFC 8785 text of a
|
|
32
|
+
* tool's top-level `_meta`, under the rules of the tool digest with `_meta`
|
|
33
|
+
* at depth 1, as it sits in the tool. Null when the tool has no `_meta`, when
|
|
34
|
+
* `_meta` is not an object, or when the rules exclude it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function metaDigest(tool: unknown): string | null;
|
|
37
|
+
/** True when the tool object has a top-level `_meta` member of its own. */
|
|
38
|
+
export declare function hasTopMeta(tool: unknown): boolean;
|
|
39
|
+
/** Digest of the server's instructions string (section 2.2), or null. */
|
|
40
|
+
export declare function instructionsDigest(instructions: unknown): string | null;
|
|
41
|
+
/** Compare by Unicode code point, as Python compares str. */
|
|
42
|
+
export declare function compareCodePoints(a: string, b: string): number;
|
|
43
|
+
/**
|
|
44
|
+
* Digest over every tool's digest, sorted by (name, digest) as Python sorts
|
|
45
|
+
* tuples. Null if any tool has no digest.
|
|
46
|
+
*/
|
|
47
|
+
export declare function toolSetDigest(tools: readonly unknown[]): string | null;
|
|
48
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../../src/lock/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,sFAAsF;AACtF,eAAO,MAAM,YAAY,QAAU,CAAC;AAOpC,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAsFD,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAK3D;AAsBD,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGvD;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CASvD;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEjD;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGvE;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAW9D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,GAAG,IAAI,CAatE"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Definition Digest, Tool Set Digest and instructions digest (lock draft 1,
|
|
3
|
+
* section 2), over RFC 8785 (JCS) canonical JSON.
|
|
4
|
+
*
|
|
5
|
+
* The input is what JSON.parse returned for the raw message, never an SDK model.
|
|
6
|
+
* The serializer walks own keys with Object.keys and writes the output string
|
|
7
|
+
* directly, so a member named `__proto__` (which JSON.parse creates as an own
|
|
8
|
+
* property) is covered like any other. Nothing here copies through object
|
|
9
|
+
* spread or plain-object assignment, either of which would turn `__proto__`
|
|
10
|
+
* into a prototype change and drop it from the digest.
|
|
11
|
+
*
|
|
12
|
+
* Separate from ../canonical.ts on purpose: that file is the legacy pin hash
|
|
13
|
+
* (NFC, ensure_ascii, Python float repr). This one is plain RFC 8785 and does
|
|
14
|
+
* not normalize Unicode.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
export const DIGEST_PREFIX = "sha256:";
|
|
18
|
+
/** Numbers at or above this magnitude get no digest (checked on the parsed value). */
|
|
19
|
+
export const NUMBER_LIMIT = 2 ** 53;
|
|
20
|
+
/** Nesting deeper than this gets no digest rather than a stack overflow. */
|
|
21
|
+
const MAX_DEPTH = 512;
|
|
22
|
+
const LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
23
|
+
export class CanonicalizationError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "CanonicalizationError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function hasLoneSurrogate(text) {
|
|
30
|
+
return LONE_SURROGATE.test(text);
|
|
31
|
+
}
|
|
32
|
+
function isObject(value) {
|
|
33
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function own(obj, key) {
|
|
36
|
+
return Object.getOwnPropertyDescriptor(obj, key)?.value;
|
|
37
|
+
}
|
|
38
|
+
/** True when every number is finite with magnitude below 2^53. */
|
|
39
|
+
function numbersInRange(value, depth) {
|
|
40
|
+
if (depth > MAX_DEPTH)
|
|
41
|
+
return false;
|
|
42
|
+
if (typeof value === "number")
|
|
43
|
+
return Number.isFinite(value) && Math.abs(value) < NUMBER_LIMIT;
|
|
44
|
+
if (Array.isArray(value))
|
|
45
|
+
return value.every((v) => numbersInRange(v, depth + 1));
|
|
46
|
+
if (isObject(value)) {
|
|
47
|
+
for (const key of Object.keys(value)) {
|
|
48
|
+
if (!numbersInRange(own(value, key), depth + 1))
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** False when any member name or string holds an unpaired UTF-16 surrogate. */
|
|
55
|
+
function wellFormed(value, depth) {
|
|
56
|
+
if (depth > MAX_DEPTH)
|
|
57
|
+
return false;
|
|
58
|
+
if (typeof value === "string")
|
|
59
|
+
return !hasLoneSurrogate(value);
|
|
60
|
+
if (Array.isArray(value))
|
|
61
|
+
return value.every((v) => wellFormed(v, depth + 1));
|
|
62
|
+
if (isObject(value)) {
|
|
63
|
+
for (const key of Object.keys(value)) {
|
|
64
|
+
if (hasLoneSurrogate(key) || !wellFormed(own(value, key), depth + 1))
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function serializeString(text) {
|
|
71
|
+
if (hasLoneSurrogate(text))
|
|
72
|
+
throw new CanonicalizationError("unpaired surrogate");
|
|
73
|
+
// For well-formed strings JSON.stringify escapes exactly what RFC 8785 asks:
|
|
74
|
+
// quote, backslash, and controls below U+0020 (short forms for \b \f \n \r \t,
|
|
75
|
+
// lower-case \u00xx otherwise). Everything else is written as is.
|
|
76
|
+
return JSON.stringify(text);
|
|
77
|
+
}
|
|
78
|
+
function serializeNumber(n) {
|
|
79
|
+
if (!Number.isFinite(n))
|
|
80
|
+
throw new CanonicalizationError("non-finite number");
|
|
81
|
+
// ECMAScript Number::toString is the RFC 8785 number form; -0 prints as 0.
|
|
82
|
+
return String(n);
|
|
83
|
+
}
|
|
84
|
+
/** Key order is UTF-16 code unit order, which is what `<` on JS strings compares. */
|
|
85
|
+
function compareCodeUnits(a, b) {
|
|
86
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
87
|
+
}
|
|
88
|
+
function serialize(value, depth, skipTopMeta) {
|
|
89
|
+
if (depth > MAX_DEPTH)
|
|
90
|
+
throw new CanonicalizationError("nesting too deep");
|
|
91
|
+
if (value === null)
|
|
92
|
+
return "null";
|
|
93
|
+
if (value === true)
|
|
94
|
+
return "true";
|
|
95
|
+
if (value === false)
|
|
96
|
+
return "false";
|
|
97
|
+
if (typeof value === "number")
|
|
98
|
+
return serializeNumber(value);
|
|
99
|
+
if (typeof value === "string")
|
|
100
|
+
return serializeString(value);
|
|
101
|
+
if (Array.isArray(value)) {
|
|
102
|
+
let out = "[";
|
|
103
|
+
for (let i = 0; i < value.length; i++) {
|
|
104
|
+
if (i > 0)
|
|
105
|
+
out += ",";
|
|
106
|
+
out += serialize(value[i], depth + 1, false);
|
|
107
|
+
}
|
|
108
|
+
return out + "]";
|
|
109
|
+
}
|
|
110
|
+
if (isObject(value)) {
|
|
111
|
+
const keys = Object.keys(value)
|
|
112
|
+
.filter((k) => !(skipTopMeta && k === "_meta"))
|
|
113
|
+
.sort(compareCodeUnits);
|
|
114
|
+
let out = "{";
|
|
115
|
+
let first = true;
|
|
116
|
+
for (const key of keys) {
|
|
117
|
+
if (!first)
|
|
118
|
+
out += ",";
|
|
119
|
+
first = false;
|
|
120
|
+
out += serializeString(key) + ":" + serialize(own(value, key), depth + 1, false);
|
|
121
|
+
}
|
|
122
|
+
return out + "}";
|
|
123
|
+
}
|
|
124
|
+
throw new CanonicalizationError(`not a JSON value: ${typeof value}`);
|
|
125
|
+
}
|
|
126
|
+
/** RFC 8785 text of a JSON value. Throws CanonicalizationError. */
|
|
127
|
+
export function canonicalize(value) {
|
|
128
|
+
return serialize(value, 0, false);
|
|
129
|
+
}
|
|
130
|
+
export function sha256Hex(data) {
|
|
131
|
+
const hash = createHash("sha256");
|
|
132
|
+
if (typeof data === "string")
|
|
133
|
+
hash.update(data, "utf8");
|
|
134
|
+
else
|
|
135
|
+
hash.update(data);
|
|
136
|
+
return hash.digest("hex");
|
|
137
|
+
}
|
|
138
|
+
function digestOf(text) {
|
|
139
|
+
return DIGEST_PREFIX + sha256Hex(text);
|
|
140
|
+
}
|
|
141
|
+
/** RFC 8785 text of the tool minus its top-level `_meta`, or null when it has no digest. */
|
|
142
|
+
function canonicalToolText(tool) {
|
|
143
|
+
if (!isObject(tool))
|
|
144
|
+
return null;
|
|
145
|
+
for (const key of Object.keys(tool)) {
|
|
146
|
+
if (key === "_meta")
|
|
147
|
+
continue;
|
|
148
|
+
if (hasLoneSurrogate(key))
|
|
149
|
+
return null;
|
|
150
|
+
const v = own(tool, key);
|
|
151
|
+
if (!wellFormed(v, 1) || !numbersInRange(v, 1))
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
return serialize(tool, 0, true);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Digest of one raw Tool object, or null when it has no digest (section 2.1). */
|
|
162
|
+
export function toolDigest(tool) {
|
|
163
|
+
const text = canonicalToolText(tool);
|
|
164
|
+
return text === null ? null : digestOf(text);
|
|
165
|
+
}
|
|
166
|
+
/** Contract file bytes for a tool: sha256 of these is the tool digest. */
|
|
167
|
+
export function canonicalBody(tool) {
|
|
168
|
+
const text = canonicalToolText(tool);
|
|
169
|
+
return text === null ? null : Buffer.from(text, "utf8");
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Meta digest (section 2.3, draft 1c): sha256 of the RFC 8785 text of a
|
|
173
|
+
* tool's top-level `_meta`, under the rules of the tool digest with `_meta`
|
|
174
|
+
* at depth 1, as it sits in the tool. Null when the tool has no `_meta`, when
|
|
175
|
+
* `_meta` is not an object, or when the rules exclude it.
|
|
176
|
+
*/
|
|
177
|
+
export function metaDigest(tool) {
|
|
178
|
+
if (!isObject(tool) || !Object.prototype.hasOwnProperty.call(tool, "_meta"))
|
|
179
|
+
return null;
|
|
180
|
+
const meta = own(tool, "_meta");
|
|
181
|
+
if (!isObject(meta) || !wellFormed(meta, 1) || !numbersInRange(meta, 1))
|
|
182
|
+
return null;
|
|
183
|
+
try {
|
|
184
|
+
return digestOf(serialize(meta, 1, false));
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** True when the tool object has a top-level `_meta` member of its own. */
|
|
191
|
+
export function hasTopMeta(tool) {
|
|
192
|
+
return isObject(tool) && Object.prototype.hasOwnProperty.call(tool, "_meta");
|
|
193
|
+
}
|
|
194
|
+
/** Digest of the server's instructions string (section 2.2), or null. */
|
|
195
|
+
export function instructionsDigest(instructions) {
|
|
196
|
+
if (typeof instructions !== "string" || hasLoneSurrogate(instructions))
|
|
197
|
+
return null;
|
|
198
|
+
return digestOf(serializeString(instructions));
|
|
199
|
+
}
|
|
200
|
+
/** Compare by Unicode code point, as Python compares str. */
|
|
201
|
+
export function compareCodePoints(a, b) {
|
|
202
|
+
const ia = a[Symbol.iterator]();
|
|
203
|
+
const ib = b[Symbol.iterator]();
|
|
204
|
+
for (;;) {
|
|
205
|
+
const x = ia.next();
|
|
206
|
+
const y = ib.next();
|
|
207
|
+
if (x.done || y.done)
|
|
208
|
+
return x.done && y.done ? 0 : x.done ? -1 : 1;
|
|
209
|
+
const cx = x.value.codePointAt(0);
|
|
210
|
+
const cy = y.value.codePointAt(0);
|
|
211
|
+
if (cx !== cy)
|
|
212
|
+
return cx < cy ? -1 : 1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Digest over every tool's digest, sorted by (name, digest) as Python sorts
|
|
217
|
+
* tuples. Null if any tool has no digest.
|
|
218
|
+
*/
|
|
219
|
+
export function toolSetDigest(tools) {
|
|
220
|
+
const pairs = [];
|
|
221
|
+
for (const tool of tools) {
|
|
222
|
+
const digest = toolDigest(tool);
|
|
223
|
+
if (digest === null)
|
|
224
|
+
return null;
|
|
225
|
+
const name = isObject(tool) ? own(tool, "name") : undefined;
|
|
226
|
+
// The name only sets the order. One that is not a string sorts as "", as
|
|
227
|
+
// in the Python reference (sep_digest.tool_set_digest).
|
|
228
|
+
const key = typeof name === "string" ? name : "";
|
|
229
|
+
pairs.push([key, digest]);
|
|
230
|
+
}
|
|
231
|
+
pairs.sort((a, b) => compareCodePoints(a[0], b[0]) || compareCodePoints(a[1], b[1]));
|
|
232
|
+
return digestOf(canonicalize(pairs.map((p) => p[1])));
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../../../src/lock/digest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpindex.lock.event/1 records (section 10), handed to a sink the caller
|
|
3
|
+
* passes in. Nothing here opens a network connection; the only file sink is
|
|
4
|
+
* one the caller constructs with a path.
|
|
5
|
+
*
|
|
6
|
+
* Events carry tool names, digests and reason codes. They never carry call
|
|
7
|
+
* arguments, call results, descriptions, instructions text or credentials:
|
|
8
|
+
* builders take only those fields, so there is no object to leak from.
|
|
9
|
+
*/
|
|
10
|
+
import type { Identity, LockErrorReason, Posture, Via } from "./lock.js";
|
|
11
|
+
import type { CallReason, Decision, MetaReason, ToolReason } from "./check.js";
|
|
12
|
+
export declare const EVENT_SCHEMA = "mcpindex.lock.event/1";
|
|
13
|
+
export interface EventServer {
|
|
14
|
+
readonly h16: string;
|
|
15
|
+
readonly slug: string;
|
|
16
|
+
}
|
|
17
|
+
interface EventBase {
|
|
18
|
+
readonly schema: typeof EVENT_SCHEMA;
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly time: string;
|
|
21
|
+
readonly host: string;
|
|
22
|
+
readonly server: EventServer;
|
|
23
|
+
}
|
|
24
|
+
export interface ListingEvent extends EventBase {
|
|
25
|
+
readonly type: "listing";
|
|
26
|
+
readonly posture: Posture;
|
|
27
|
+
readonly lockError: LockErrorReason | null;
|
|
28
|
+
readonly counts: {
|
|
29
|
+
readonly served: number;
|
|
30
|
+
readonly shown: number;
|
|
31
|
+
readonly withheld: number;
|
|
32
|
+
readonly removed: number;
|
|
33
|
+
};
|
|
34
|
+
readonly tools: ReadonlyArray<{
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly served: string | null;
|
|
37
|
+
readonly approved: string | null;
|
|
38
|
+
readonly decision: "shown" | "withheld";
|
|
39
|
+
readonly reason: ToolReason | LockErrorReason | null;
|
|
40
|
+
readonly meta: MetaReason | null;
|
|
41
|
+
}>;
|
|
42
|
+
readonly removed: readonly string[];
|
|
43
|
+
readonly instructions: string | null;
|
|
44
|
+
/** The snapshot the decision used (optional in the spec, always set here). */
|
|
45
|
+
readonly snapshotId: string;
|
|
46
|
+
}
|
|
47
|
+
export interface RefusalEvent extends EventBase {
|
|
48
|
+
readonly type: "refusal";
|
|
49
|
+
readonly tool: string;
|
|
50
|
+
readonly reason: CallReason;
|
|
51
|
+
}
|
|
52
|
+
export interface ApprovalEvent extends EventBase {
|
|
53
|
+
readonly type: "approval";
|
|
54
|
+
readonly tool: string;
|
|
55
|
+
readonly digest: string;
|
|
56
|
+
readonly via: Via;
|
|
57
|
+
readonly subject: string;
|
|
58
|
+
readonly ref: string | null;
|
|
59
|
+
}
|
|
60
|
+
export type LockEvent = ListingEvent | RefusalEvent | ApprovalEvent;
|
|
61
|
+
export type LockEventSink = (event: LockEvent) => void;
|
|
62
|
+
export interface EventContext {
|
|
63
|
+
readonly host: string;
|
|
64
|
+
readonly identity: Identity;
|
|
65
|
+
readonly now?: () => Date;
|
|
66
|
+
readonly newId?: () => string;
|
|
67
|
+
}
|
|
68
|
+
export declare function listingEvent(ctx: EventContext, decision: Decision, snapshotId: string): ListingEvent;
|
|
69
|
+
export declare function refusalEvent(ctx: EventContext, tool: string, reason: CallReason): RefusalEvent;
|
|
70
|
+
export declare function approvalEvent(ctx: EventContext, approval: {
|
|
71
|
+
tool: string;
|
|
72
|
+
digest: string;
|
|
73
|
+
via: Via;
|
|
74
|
+
subject: string;
|
|
75
|
+
ref?: string;
|
|
76
|
+
}): ApprovalEvent;
|
|
77
|
+
/** Call the sink and swallow its errors: an event failure never changes a decision. */
|
|
78
|
+
export declare function emit(sink: LockEventSink | undefined, event: LockEvent): void;
|
|
79
|
+
/** Append one JSON line per event to `path`. Only used when a caller builds it. */
|
|
80
|
+
export declare function jsonlFileSink(path: string): LockEventSink;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=events.d.ts.map
|