@agenticprimitives/mcp-runtime 0.1.0-alpha.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agentic Trust Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # @agenticprimitives/mcp-runtime
2
+
3
+ Delegation-aware authorization middleware around the official MCP TypeScript SDK. Eliminates the ~65% code duplication observed across smart-agent's three mature MCP servers (`person-mcp`, `org-mcp`, `people-group-mcp`).
4
+
5
+ This package is the **decision layer**, not the SDK. The official `@modelcontextprotocol/sdk` already provides tool/resource/prompt registration, transports, and OAuth 2.1+PKCE+RFC-9728+RFC-8707 plumbing (mandated by the 2026-03-15 MCP spec). We add the bridge to `@agenticprimitives/delegation` + `@agenticprimitives/tool-policy`.
6
+
7
+ See [`spec.md`](./spec.md) → [`specs/205-mcp-runtime.md`](../../specs/205-mcp-runtime.md).
8
+
9
+ ## Quick start
10
+
11
+ ```ts
12
+ import { McpServer } from '@modelcontextprotocol/sdk/server';
13
+ import { withDelegation, createSqliteJtiStore } from '@agenticprimitives/mcp-runtime';
14
+
15
+ const config = {
16
+ audience: 'urn:mcp:server:person',
17
+ chainId: 31337,
18
+ rpcUrl: process.env.RPC_URL!,
19
+ delegationManager: process.env.DELEGATION_MANAGER_ADDRESS as `0x${string}`,
20
+ enforcerMap,
21
+ jtiStore: createSqliteJtiStore(db, 'token_usage'),
22
+ };
23
+
24
+ const server = new McpServer({ name: 'person-mcp', version: '0.1.0' });
25
+
26
+ server.registerTool({
27
+ name: 'get_profile',
28
+ inputSchema: { type: 'object', properties: { token: { type: 'string' } } },
29
+ handler: withDelegation(config, async ({ principal }) => {
30
+ return db.profiles.findUnique({ where: { ownerAddress: principal } });
31
+ }),
32
+ });
33
+ ```
34
+
35
+ The handler no longer touches auth. The wrapper performs: HMAC envelope check → session-key signature → EIP-712 hash → on-chain `isRevoked` → ERC-1271 verify → caveat eval (fail-closed) → JTI usage tracking → `tool-policy.evaluatePolicy` → hand `{ principal, grants? }` to the inner handler.
36
+
37
+ ## Cross-delegation
38
+
39
+ **Removed from the public surface in H7-B.8** (XPKG-002 / EXT-024 closure). The previous `withCrossDelegation` was a stub that unconditionally rejected. Per spec 100 §6, experimental capability lives behind a `./experimental` subpath; when cross-delegation work resumes it lands there. See [`docs/audits/2026-05-packages-contracts-production-readiness.md`](../../docs/audits/2026-05-packages-contracts-production-readiness.md) (PKG-mcp-runtime-001).
40
+
41
+ ## Status
42
+
43
+ Pre-alpha. Spec stable.
@@ -0,0 +1,6 @@
1
+ import type { ResourceDefinition } from './types';
2
+ import type { ToolClassification } from '@agenticprimitives/tool-policy';
3
+ export declare function declareResource(def: ResourceDefinition, classification: ToolClassification): ResourceDefinition & {
4
+ _classification: ToolClassification;
5
+ };
6
+ //# sourceMappingURL=declare-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declare-resource.d.ts","sourceRoot":"","sources":["../src/declare-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,kBAAkB,EACvB,cAAc,EAAE,kBAAkB,GACjC,kBAAkB,GAAG;IAAE,eAAe,EAAE,kBAAkB,CAAA;CAAE,CAE9D"}
@@ -0,0 +1,4 @@
1
+ export function declareResource(def, classification) {
2
+ return Object.assign({}, def, { _classification: classification });
3
+ }
4
+ //# sourceMappingURL=declare-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declare-resource.js","sourceRoot":"","sources":["../src/declare-resource.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAC7B,GAAuB,EACvB,cAAkC;IAElC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { withDelegation, verifyDelegationForResource, McpAuthError, type McpAuthErrorCode, type PrivateAuthFailureContext, } from './with-delegation';
2
+ export { declareResource } from './declare-resource';
3
+ export { createMemoryJtiStore, createSqliteJtiStore, createPostgresJtiStore, type MigratableJtiStore, } from './jti-stores';
4
+ export { generateServiceMac, verifyServiceMac, bodyDigestHex, } from './service-mac';
5
+ export type { MacProviderLike, ServiceMacContext, ServiceMacHeaders, } from './service-mac';
6
+ export type { Address, Hex, Caveat, DataScopeGrant, Delegation, EnforcerAddressMap, JtiStore, ToolClassification, McpResourceVerifyConfig, ResourceDefinition, BetterSqlite3DatabaseLike, PgPoolLike, } from './types';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,OAAO,EACP,GAAG,EACH,MAAM,EACN,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,yBAAyB,EACzB,UAAU,GACX,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ // @agenticprimitives/mcp-runtime — public API
2
+ //
3
+ // See ../../specs/205-mcp-runtime.md for the full contract.
4
+ // H7-B.8: `withCrossDelegation` + `verifyCrossDelegationForResource` removed
5
+ // from the public surface (XPKG-002 / EXT-024 closure). Both were stubs that
6
+ // unconditionally rejected. They will resurface behind `./experimental` per
7
+ // spec 100 §6 when the cross-delegation work resumes.
8
+ export { withDelegation, verifyDelegationForResource, McpAuthError, } from './with-delegation';
9
+ export { declareResource } from './declare-resource';
10
+ export { createMemoryJtiStore, createSqliteJtiStore, createPostgresJtiStore, } from './jti-stores';
11
+ export { generateServiceMac, verifyServiceMac, bodyDigestHex, } from './service-mac';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,4DAA4D;AAE5D,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,sDAAsD;AACtD,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GAEvB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { JtiStore } from '@agenticprimitives/delegation';
2
+ import type { BetterSqlite3DatabaseLike, PgPoolLike } from './types';
3
+ /**
4
+ * Sentinel env var. When set to "true", `createMemoryJtiStore` will
5
+ * construct in production without throwing. Required for one-off
6
+ * scenarios (CI smoke tests against a prod-built bundle, isolated dev
7
+ * worker instances). All callers MUST treat this as a loud opt-in — a
8
+ * one-time `console.warn` is emitted on construction.
9
+ */
10
+ export declare const ALLOW_MEMORY_JTI_ENV = "AGENTIC_ALLOW_MEMORY_JTI_STORE";
11
+ /**
12
+ * H7-B.9 / XPKG-005 — explicit environment opt-in. The memory store is
13
+ * the only JTI store that ships with this package and has cross-isolate
14
+ * replay-vulnerability; production deploys MUST pass `environment:
15
+ * 'production'` to gate it on (and supply the `AP_ALLOW_MEMORY_JTI_STORE`
16
+ * opt-out). The previous `process.env.NODE_ENV` check silently opened on
17
+ * Cloudflare Workers / SES where `process.env` is undefined.
18
+ */
19
+ export interface CreateMemoryJtiStoreOpts {
20
+ environment?: 'production' | 'development';
21
+ }
22
+ export declare function createMemoryJtiStore(opts?: CreateMemoryJtiStoreOpts): JtiStore;
23
+ /**
24
+ * JtiStore extended with an explicit `migrate()` step. H7-B.6: the SQL /
25
+ * pg adapters MUST be migrated once at bootstrap before any `trackUsage`
26
+ * is called. The migrate step is idempotent (`CREATE TABLE IF NOT EXISTS`)
27
+ * but requires DDL permission — keep it out of the security hot path.
28
+ */
29
+ export interface MigratableJtiStore extends JtiStore {
30
+ migrate(): Promise<void>;
31
+ }
32
+ /**
33
+ * H7-B.6 — SQLite JTI store. Construction no longer issues DDL; call
34
+ * `await store.migrate()` from your bootstrap before serving traffic.
35
+ * Calling `trackUsage` without a prior `migrate()` throws a setup error
36
+ * (NOT a silent noop) so least-privilege deploys fail loud, not silent.
37
+ */
38
+ export declare function createSqliteJtiStore(db: BetterSqlite3DatabaseLike, table?: string): MigratableJtiStore;
39
+ /**
40
+ * H7-B.6 — Postgres JTI store. Construction no longer issues DDL; call
41
+ * `await store.migrate()` from your bootstrap. Calling `trackUsage` without
42
+ * a prior `migrate()` throws a setup error so a misconfigured least-privilege
43
+ * deploy fails loud rather than silently disabling replay protection.
44
+ */
45
+ export declare function createPostgresJtiStore(pool: PgPoolLike, table?: string): MigratableJtiStore;
46
+ //# sourceMappingURL=jti-stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jti-stores.d.ts","sourceRoot":"","sources":["../src/jti-stores.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,mCAAmC,CAAC;AAIrE;;;;;;;GAOG;AACH,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;CAC5C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,wBAA6B,GAAG,QAAQ,CAgClF;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,yBAAyB,EAC7B,KAAK,GAAE,MAAsB,GAC5B,kBAAkB,CAqCpB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,UAAU,EAChB,KAAK,GAAE,MAAsB,GAC5B,kBAAkB,CAgCpB"}
@@ -0,0 +1,125 @@
1
+ // JtiStore adapters: memory (test), sqlite (demo + many prod), postgres (prod).
2
+ // Each implementation MUST be atomic under concurrent writers per the
3
+ // security invariant in spec 205 §5.
4
+ //
5
+ // H7-B.6 / PKG-MCP-RUNTIME-001 closure (also covers EXT-027). Prior versions
6
+ // ran `CREATE TABLE IF NOT EXISTS …` inside the adapter constructor (sqlite)
7
+ // or lazily on first `trackUsage` (postgres). That coupled the security hot
8
+ // path to runtime DDL permissions:
9
+ // - Postgres deploys following least-privilege (app role lacks DDL): first
10
+ // `trackUsage` throws → JTI store down → replay protection silently
11
+ // disabled (caller swallows → fail-open).
12
+ // - SQLite: CREATE runs at construction → mig-vs-app race.
13
+ //
14
+ // Fix: explicit `migrate()` step the consumer wires once at bootstrap; the
15
+ // runtime path no longer issues DDL. If `migrate()` was not called and the
16
+ // table is missing, `trackUsage` fails LOUD with a setup error (not a silent
17
+ // noop).
18
+ /**
19
+ * Sentinel env var. When set to "true", `createMemoryJtiStore` will
20
+ * construct in production without throwing. Required for one-off
21
+ * scenarios (CI smoke tests against a prod-built bundle, isolated dev
22
+ * worker instances). All callers MUST treat this as a loud opt-in — a
23
+ * one-time `console.warn` is emitted on construction.
24
+ */
25
+ export const ALLOW_MEMORY_JTI_ENV = 'AGENTIC_ALLOW_MEMORY_JTI_STORE';
26
+ let memoryStoreWarnedOnce = false;
27
+ export function createMemoryJtiStore(opts = {}) {
28
+ // Production guard — H7-B.9: the caller MUST pass `environment: 'production'`
29
+ // to opt into the gate. We no longer infer from NODE_ENV (Workers / SES
30
+ // runtimes don't reliably expose it, leading to silent fall-open).
31
+ const env = typeof process !== 'undefined' ? (process.env ?? {}) : {};
32
+ const environment = opts.environment ?? (env.NODE_ENV === 'production' ? 'production' : 'development');
33
+ if (environment === 'production' && env[ALLOW_MEMORY_JTI_ENV] !== 'true') {
34
+ throw new Error('[mcp-runtime] createMemoryJtiStore refused: environment="production". ' +
35
+ 'The memory store offers no cross-process replay protection. Use ' +
36
+ 'createSqliteJtiStore / createPostgresJtiStore / a D1-backed store in ' +
37
+ `production. If you genuinely need to override (e.g., isolated test ` +
38
+ `worker), set ${ALLOW_MEMORY_JTI_ENV}=true and accept that delegation ` +
39
+ 'tokens are replay-vulnerable across restarts.');
40
+ }
41
+ if (environment === 'production' && !memoryStoreWarnedOnce) {
42
+ console.warn(`[mcp-runtime] ⚠ MEMORY JTI STORE in production — ${ALLOW_MEMORY_JTI_ENV} ` +
43
+ 'is set; delegation-token replay protection is non-durable. Remove this ' +
44
+ 'flag before handling real-value workloads.');
45
+ memoryStoreWarnedOnce = true;
46
+ }
47
+ const usage = new Map();
48
+ return {
49
+ async trackUsage(jti, limit) {
50
+ const current = (usage.get(jti) ?? 0) + 1;
51
+ usage.set(jti, current);
52
+ return { usage: current, allowed: current <= limit };
53
+ },
54
+ };
55
+ }
56
+ /**
57
+ * H7-B.6 — SQLite JTI store. Construction no longer issues DDL; call
58
+ * `await store.migrate()` from your bootstrap before serving traffic.
59
+ * Calling `trackUsage` without a prior `migrate()` throws a setup error
60
+ * (NOT a silent noop) so least-privilege deploys fail loud, not silent.
61
+ */
62
+ export function createSqliteJtiStore(db, table = 'token_usage') {
63
+ let migrated = false;
64
+ let upsert = null;
65
+ const prepareUpsert = () => db.prepare(`INSERT INTO ${table} (jti, usage) VALUES (?, 1)
66
+ ON CONFLICT(jti) DO UPDATE SET usage = usage + 1
67
+ RETURNING usage`);
68
+ return {
69
+ async migrate() {
70
+ if (migrated)
71
+ return;
72
+ db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
73
+ jti TEXT PRIMARY KEY,
74
+ usage INTEGER NOT NULL DEFAULT 0,
75
+ first_seen TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
76
+ )`).run();
77
+ upsert = prepareUpsert();
78
+ migrated = true;
79
+ },
80
+ async trackUsage(jti, limit) {
81
+ if (!migrated || !upsert) {
82
+ throw new Error(`[mcp-runtime] sqlite JTI store: migrate() was not called before trackUsage. ` +
83
+ `Call \`await store.migrate()\` once at bootstrap (it is idempotent). ` +
84
+ `H7-B.6 (PKG-MCP-RUNTIME-001 / EXT-027 closure) moved DDL off the hot path.`);
85
+ }
86
+ const row = upsert.get(jti);
87
+ const current = row?.usage ?? 1;
88
+ return { usage: current, allowed: current <= limit };
89
+ },
90
+ };
91
+ }
92
+ /**
93
+ * H7-B.6 — Postgres JTI store. Construction no longer issues DDL; call
94
+ * `await store.migrate()` from your bootstrap. Calling `trackUsage` without
95
+ * a prior `migrate()` throws a setup error so a misconfigured least-privilege
96
+ * deploy fails loud rather than silently disabling replay protection.
97
+ */
98
+ export function createPostgresJtiStore(pool, table = 'token_usage') {
99
+ let migrated = false;
100
+ return {
101
+ async migrate() {
102
+ if (migrated)
103
+ return;
104
+ await pool.query(`CREATE TABLE IF NOT EXISTS ${table} (
105
+ jti TEXT PRIMARY KEY,
106
+ usage INTEGER NOT NULL DEFAULT 0,
107
+ first_seen TIMESTAMPTZ NOT NULL DEFAULT NOW()
108
+ )`);
109
+ migrated = true;
110
+ },
111
+ async trackUsage(jti, limit) {
112
+ if (!migrated) {
113
+ throw new Error(`[mcp-runtime] postgres JTI store: migrate() was not called before trackUsage. ` +
114
+ `Call \`await store.migrate()\` once at bootstrap (it is idempotent). ` +
115
+ `H7-B.6 (PKG-MCP-RUNTIME-001 / EXT-027 closure) moved DDL off the hot path.`);
116
+ }
117
+ const res = await pool.query(`INSERT INTO ${table} (jti, usage) VALUES ($1, 1)
118
+ ON CONFLICT (jti) DO UPDATE SET usage = ${table}.usage + 1
119
+ RETURNING usage`, [jti]);
120
+ const current = res.rows[0]?.usage ?? 1;
121
+ return { usage: current, allowed: current <= limit };
122
+ },
123
+ };
124
+ }
125
+ //# sourceMappingURL=jti-stores.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jti-stores.js","sourceRoot":"","sources":["../src/jti-stores.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,sEAAsE;AACtE,qCAAqC;AACrC,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,mCAAmC;AACnC,6EAA6E;AAC7E,wEAAwE;AACxE,8CAA8C;AAC9C,6DAA6D;AAC7D,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,SAAS;AAKT;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,gCAAgC,CAAC;AAErE,IAAI,qBAAqB,GAAG,KAAK,CAAC;AAclC,MAAM,UAAU,oBAAoB,CAAC,OAAiC,EAAE;IACtE,8EAA8E;IAC9E,wEAAwE;IACxE,mEAAmE;IACnE,MAAM,GAAG,GAAG,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACvG,IAAI,WAAW,KAAK,YAAY,IAAI,GAAG,CAAC,oBAAoB,CAAC,KAAK,MAAM,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CACb,wEAAwE;YACtE,kEAAkE;YAClE,uEAAuE;YACvE,qEAAqE;YACrE,gBAAgB,oBAAoB,mCAAmC;YACvE,+CAA+C,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,KAAK,YAAY,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3D,OAAO,CAAC,IAAI,CACV,oDAAoD,oBAAoB,GAAG;YACzE,yEAAyE;YACzE,4CAA4C,CAC/C,CAAC;QACF,qBAAqB,GAAG,IAAI,CAAC;IAC/B,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,OAAO;QACL,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,KAAa;YACzC,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC1C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC;QACvD,CAAC;KACF,CAAC;AACJ,CAAC;AAYD;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,EAA6B,EAC7B,QAAgB,aAAa;IAE7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,MAAM,GAA4D,IAAI,CAAC;IAE3E,MAAM,aAAa,GAAG,GAAG,EAAE,CACzB,EAAE,CAAC,OAAO,CACR,eAAe,KAAK;;uBAEH,CAClB,CAAC;IAEJ,OAAO;QACL,KAAK,CAAC,OAAO;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,EAAE,CAAC,OAAO,CACR,8BAA8B,KAAK;;;;UAIjC,CACH,CAAC,GAAG,EAAE,CAAC;YACR,MAAM,GAAG,aAAa,EAAE,CAAC;YACzB,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,KAAa;YACzC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,8EAA8E;oBAC5E,uEAAuE;oBACvE,4EAA4E,CAC/E,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAkC,CAAC;YAC7D,MAAM,OAAO,GAAG,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;YAChC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC;QACvD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAgB,EAChB,QAAgB,aAAa;IAE7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO;QACL,KAAK,CAAC,OAAO;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,MAAM,IAAI,CAAC,KAAK,CACd,8BAA8B,KAAK;;;;UAIjC,CACH,CAAC;YACF,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,KAAa;YACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACb,gFAAgF;oBAC9E,uEAAuE;oBACvE,4EAA4E,CAC/E,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAC1B,eAAe,KAAK;mDACuB,KAAK;yBAC/B,EACjB,CAAC,GAAG,CAAC,CACN,CAAC;YACF,MAAM,OAAO,GAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAmC,EAAE,KAAK,IAAI,CAAC,CAAC;YAC3E,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC;QACvD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Service-to-service MAC envelope. Audit C1.
3
+ *
4
+ * Closes the gap where MCP requests rely solely on bearer delegation
5
+ * tokens with no route-level service authenticity or replay control.
6
+ * The MAC binds:
7
+ * - `audience` (the MCP server identity, e.g. `urn:mcp:server:person`)
8
+ * - `service` (the caller identity, e.g. `a2a-to-mcp`)
9
+ * - `route` (the tool name being invoked)
10
+ * - `nonce` (one-shot, replay-tracked via JtiStore)
11
+ * - `timestamp` (millisecond epoch, clock-skew bounded)
12
+ * - `bodyDigest` (sha256 of the raw request body)
13
+ *
14
+ * Both sides (a2a caller + mcp verifier) share an HMAC key via
15
+ * `key-custody.buildMacProvider(...)`. For dev, a local-aes provider
16
+ * with a shared 32-byte secret. For production, a GCP KMS HMAC key
17
+ * with IAM scoped to the two service accounts. The wire format is
18
+ * provider-agnostic.
19
+ *
20
+ * Doctrine: MCP runtime stays transport-agnostic. This module ships
21
+ * pure helpers; the demo's Hono middleware wires them to HTTP headers.
22
+ */
23
+ import type { Hex } from '@agenticprimitives/types';
24
+ import type { JtiStore } from '@agenticprimitives/delegation';
25
+ import { type AuditSink } from '@agenticprimitives/audit';
26
+ export interface MacProviderLike {
27
+ readonly keyVersion: string;
28
+ generateMac?(input: {
29
+ canonicalMessage: Uint8Array;
30
+ service: string;
31
+ audience: string;
32
+ }): Promise<{
33
+ mac: Uint8Array;
34
+ keyId: string;
35
+ }>;
36
+ }
37
+ export interface ServiceMacContext {
38
+ /** MCP server identity. Same value MUST be used on both sides. */
39
+ audience: string;
40
+ /** Caller identity (e.g. 'a2a-to-mcp'). */
41
+ service: string;
42
+ /** Route family — typically the tool name. */
43
+ route: string;
44
+ /** sha256 of the raw request body. */
45
+ bodyDigest: Hex;
46
+ }
47
+ export interface ServiceMacHeaders {
48
+ /** base64url(HMAC) over the canonical message. */
49
+ mac: string;
50
+ /** base64url(16 random bytes). One-shot; tracked via JtiStore. */
51
+ nonce: string;
52
+ /** Epoch milliseconds at generate time, as decimal string. */
53
+ timestamp: string;
54
+ /** Provider-supplied key ID (for log/forensics + key rotation). */
55
+ keyId: string;
56
+ }
57
+ /** Hex-encoded sha256 of a body string. Helper for callers. */
58
+ export declare function bodyDigestHex(body: string): Hex;
59
+ /**
60
+ * Caller side: generate the MAC + headers for an outgoing request.
61
+ * The provider MUST support `generateMac`.
62
+ *
63
+ * H7-F.3 / PKG-MCP-RUNTIME-006 / CT-9 closure — accepts an optional
64
+ * `auditSink` that receives `mcp-runtime.service-mac.issue` on
65
+ * successful generation (mirroring the verify side's
66
+ * `service-mac.{accept,reject}`). The audit row carries `keyId`,
67
+ * `service`, `audience`, and the `correlationId` the caller threads in,
68
+ * so a forensics query can join the issue with the corresponding
69
+ * downstream accept/reject.
70
+ *
71
+ * Fail-soft: audit emission failures NEVER break the MAC issuance.
72
+ */
73
+ export declare function generateServiceMac(args: {
74
+ ctx: ServiceMacContext;
75
+ provider: MacProviderLike;
76
+ /** Override for tests. Production: leave undefined for crypto.randomBytes-derived nonce. */
77
+ nonce?: Uint8Array;
78
+ /** Override for tests. Production: leave undefined. */
79
+ now?: () => number;
80
+ /** H7-F.3 — emit `mcp-runtime.service-mac.issue` on success. */
81
+ auditSink?: AuditSink;
82
+ /** Correlation id stitched into the emitted event. */
83
+ correlationId?: string;
84
+ }): Promise<ServiceMacHeaders>;
85
+ /**
86
+ * Verifier side: recompute the MAC + check it matches in constant time,
87
+ * + check clock skew, + consume the nonce (replay tracking via JtiStore).
88
+ *
89
+ * Fail-closed: any failure returns `{ ok: false, reason }`. Callers MUST
90
+ * NOT echo `reason` to external clients — log it, return generic 401.
91
+ */
92
+ export declare function verifyServiceMac(args: {
93
+ ctx: ServiceMacContext;
94
+ headers: ServiceMacHeaders;
95
+ provider: MacProviderLike;
96
+ jtiStore: JtiStore;
97
+ /** Default 60_000ms. */
98
+ maxClockSkewMs?: number;
99
+ now?: () => number;
100
+ /**
101
+ * Audit sink (audit C3). When provided, both outcomes emit:
102
+ *
103
+ * - On reject: `mcp-runtime.service-mac.reject` with a `reason` string
104
+ * classifying the failure (clock skew, mac mismatch, nonce replay,
105
+ * malformed input, ...).
106
+ * - On accept: `mcp-runtime.service-mac.accept` with the keyId + a
107
+ * short hash of the consumed nonce.
108
+ *
109
+ * Both events fire even when the downstream `withDelegation` wrapper
110
+ * also emits — service-mac and delegation are separate primitives
111
+ * with separate threat models, so anomaly detection (accept rate
112
+ * per primitive, missing-pair detection) needs them as distinct
113
+ * rows. Per-emit overhead is one D1 INSERT; not worth coalescing.
114
+ */
115
+ auditSink?: AuditSink;
116
+ /** Correlation ID threaded into emitted events. */
117
+ correlationId?: string;
118
+ }): Promise<{
119
+ ok: true;
120
+ } | {
121
+ ok: false;
122
+ reason: string;
123
+ }>;
124
+ //# sourceMappingURL=service-mac.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-mac.d.ts","sourceRoot":"","sources":["../src/service-mac.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAItE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,CAAC,KAAK,EAAE;QAClB,gBAAgB,EAAE,UAAU,CAAC;QAC7B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,UAAU,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;CACf;AAoDD,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,EAAE,iBAAiB,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,4FAA4F;IAC5F,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,gEAAgE;IAChE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwC7B;AASD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,wBAAwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAkGxD"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Service-to-service MAC envelope. Audit C1.
3
+ *
4
+ * Closes the gap where MCP requests rely solely on bearer delegation
5
+ * tokens with no route-level service authenticity or replay control.
6
+ * The MAC binds:
7
+ * - `audience` (the MCP server identity, e.g. `urn:mcp:server:person`)
8
+ * - `service` (the caller identity, e.g. `a2a-to-mcp`)
9
+ * - `route` (the tool name being invoked)
10
+ * - `nonce` (one-shot, replay-tracked via JtiStore)
11
+ * - `timestamp` (millisecond epoch, clock-skew bounded)
12
+ * - `bodyDigest` (sha256 of the raw request body)
13
+ *
14
+ * Both sides (a2a caller + mcp verifier) share an HMAC key via
15
+ * `key-custody.buildMacProvider(...)`. For dev, a local-aes provider
16
+ * with a shared 32-byte secret. For production, a GCP KMS HMAC key
17
+ * with IAM scoped to the two service accounts. The wire format is
18
+ * provider-agnostic.
19
+ *
20
+ * Doctrine: MCP runtime stays transport-agnostic. This module ships
21
+ * pure helpers; the demo's Hono middleware wires them to HTTP headers.
22
+ */
23
+ import { sha256, toHex } from 'viem';
24
+ import { buildEvent } from '@agenticprimitives/audit';
25
+ const VERSION = 'agentic-a2a-mcp-v1';
26
+ const DEFAULT_CLOCK_SKEW_MS = 60_000;
27
+ function canonicalMessage(ctx, nonce, timestamp) {
28
+ const text = VERSION +
29
+ '\n' +
30
+ ctx.audience +
31
+ '\n' +
32
+ ctx.service +
33
+ '\n' +
34
+ ctx.route +
35
+ '\n' +
36
+ nonce +
37
+ '\n' +
38
+ timestamp +
39
+ '\n' +
40
+ ctx.bodyDigest.toLowerCase();
41
+ return new TextEncoder().encode(text);
42
+ }
43
+ function base64urlEncode(bytes) {
44
+ const bin = Array.from(bytes, (b) => String.fromCharCode(b)).join('');
45
+ const b64 = typeof btoa === 'function'
46
+ ? btoa(bin)
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ : globalThis.Buffer.from(bytes).toString('base64');
49
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
50
+ }
51
+ function base64urlDecode(s) {
52
+ const padded = s.replace(/-/g, '+').replace(/_/g, '/') +
53
+ '=='.slice((2 - (s.length & 3)) & 3);
54
+ const bin = typeof atob === 'function'
55
+ ? atob(padded)
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ : globalThis.Buffer.from(padded, 'base64').toString('binary');
58
+ const out = new Uint8Array(bin.length);
59
+ for (let i = 0; i < bin.length; i++)
60
+ out[i] = bin.charCodeAt(i);
61
+ return out;
62
+ }
63
+ function constantTimeEqual(a, b) {
64
+ if (a.length !== b.length)
65
+ return false;
66
+ let diff = 0;
67
+ for (let i = 0; i < a.length; i++)
68
+ diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
69
+ return diff === 0;
70
+ }
71
+ /** Hex-encoded sha256 of a body string. Helper for callers. */
72
+ export function bodyDigestHex(body) {
73
+ return sha256(toHex(body));
74
+ }
75
+ /**
76
+ * Caller side: generate the MAC + headers for an outgoing request.
77
+ * The provider MUST support `generateMac`.
78
+ *
79
+ * H7-F.3 / PKG-MCP-RUNTIME-006 / CT-9 closure — accepts an optional
80
+ * `auditSink` that receives `mcp-runtime.service-mac.issue` on
81
+ * successful generation (mirroring the verify side's
82
+ * `service-mac.{accept,reject}`). The audit row carries `keyId`,
83
+ * `service`, `audience`, and the `correlationId` the caller threads in,
84
+ * so a forensics query can join the issue with the corresponding
85
+ * downstream accept/reject.
86
+ *
87
+ * Fail-soft: audit emission failures NEVER break the MAC issuance.
88
+ */
89
+ export async function generateServiceMac(args) {
90
+ if (!args.provider.generateMac) {
91
+ throw new Error('serviceMac: provider lacks generateMac (use a MAC-capable backend)');
92
+ }
93
+ const nonceBytes = args.nonce ?? cryptoRandomBytes(16);
94
+ const nonce = base64urlEncode(nonceBytes);
95
+ const timestamp = String((args.now ?? Date.now)());
96
+ const canonical = canonicalMessage(args.ctx, nonce, timestamp);
97
+ const { mac, keyId } = await args.provider.generateMac({
98
+ canonicalMessage: canonical,
99
+ service: args.ctx.service,
100
+ audience: args.ctx.audience,
101
+ });
102
+ const headers = {
103
+ mac: base64urlEncode(mac),
104
+ nonce,
105
+ timestamp,
106
+ keyId,
107
+ };
108
+ if (args.auditSink) {
109
+ try {
110
+ await args.auditSink.write({
111
+ id: cryptoRandomBytesHex(8),
112
+ timestamp: new Date().toISOString(),
113
+ action: 'mcp-runtime.service-mac.issue',
114
+ outcome: 'success',
115
+ correlationId: args.correlationId,
116
+ actor: { type: 'service', id: args.ctx.service },
117
+ audience: args.ctx.audience,
118
+ subject: { type: 'service-mac', id: keyId ?? 'unknown' },
119
+ context: {
120
+ route: args.ctx.route,
121
+ },
122
+ });
123
+ }
124
+ catch {
125
+ /* H7-F.3: fail-soft. Issuance must not break on audit failure. */
126
+ }
127
+ }
128
+ return headers;
129
+ }
130
+ function cryptoRandomBytesHex(n) {
131
+ const buf = cryptoRandomBytes(n);
132
+ let hex = '';
133
+ for (const b of buf)
134
+ hex += b.toString(16).padStart(2, '0');
135
+ return hex;
136
+ }
137
+ /**
138
+ * Verifier side: recompute the MAC + check it matches in constant time,
139
+ * + check clock skew, + consume the nonce (replay tracking via JtiStore).
140
+ *
141
+ * Fail-closed: any failure returns `{ ok: false, reason }`. Callers MUST
142
+ * NOT echo `reason` to external clients — log it, return generic 401.
143
+ */
144
+ export async function verifyServiceMac(args) {
145
+ const emitReject = async (reason) => {
146
+ if (!args.auditSink)
147
+ return;
148
+ try {
149
+ await args.auditSink.write(buildEvent({
150
+ action: 'mcp-runtime.service-mac.reject',
151
+ outcome: 'denied',
152
+ correlationId: args.correlationId,
153
+ actor: { type: 'service', id: args.ctx.service },
154
+ subject: { type: 'tool', id: args.ctx.route },
155
+ audience: args.ctx.audience,
156
+ reason,
157
+ context: {
158
+ keyId: args.headers.keyId,
159
+ // Hash of the nonce so the raw value (which is one-shot
160
+ // and tied to a specific request) isn't surfaced in logs
161
+ // beyond what's already required for the rejection trail.
162
+ nonceHash: nonceHashShort(args.headers.nonce),
163
+ },
164
+ }));
165
+ }
166
+ catch {
167
+ /* fail-soft */
168
+ }
169
+ };
170
+ const reject = async (reason) => {
171
+ await emitReject(reason);
172
+ return { ok: false, reason };
173
+ };
174
+ if (!args.provider.generateMac) {
175
+ return reject('verifier provider lacks generateMac');
176
+ }
177
+ // Clock-skew gate.
178
+ const ts = Number(args.headers.timestamp);
179
+ if (!Number.isFinite(ts) || ts <= 0) {
180
+ return reject('malformed timestamp');
181
+ }
182
+ const now = (args.now ?? Date.now)();
183
+ const skew = args.maxClockSkewMs ?? DEFAULT_CLOCK_SKEW_MS;
184
+ if (Math.abs(now - ts) > skew) {
185
+ return reject(`clock skew ${Math.abs(now - ts)}ms exceeds ${skew}ms`);
186
+ }
187
+ // MAC recompute + constant-time compare.
188
+ const canonical = canonicalMessage(args.ctx, args.headers.nonce, args.headers.timestamp);
189
+ let expected;
190
+ try {
191
+ const got = await args.provider.generateMac({
192
+ canonicalMessage: canonical,
193
+ service: args.ctx.service,
194
+ audience: args.ctx.audience,
195
+ });
196
+ expected = got.mac;
197
+ }
198
+ catch (e) {
199
+ return reject(`mac recompute failed: ${e instanceof Error ? e.message : e}`);
200
+ }
201
+ let received;
202
+ try {
203
+ received = base64urlDecode(args.headers.mac);
204
+ }
205
+ catch (e) {
206
+ return reject(`malformed mac base64url: ${e instanceof Error ? e.message : e}`);
207
+ }
208
+ if (!constantTimeEqual(expected, received)) {
209
+ return reject('mac mismatch');
210
+ }
211
+ // Replay: track the nonce via JTI store. limit=1 means single-use:
212
+ // first call succeeds (usage=1, allowed=true); second sees usage=2,
213
+ // allowed=false. JTI key is namespaced to distinguish from
214
+ // delegation-token JTIs.
215
+ const jti = `mac:${args.ctx.audience}:${args.ctx.service}:${args.headers.nonce}`;
216
+ const tracked = await args.jtiStore.trackUsage(jti, 1);
217
+ if (!tracked.allowed) {
218
+ return reject('mac nonce already consumed (replay)');
219
+ }
220
+ void ts; // ts is bounded by clock-skew gate above; no further use here.
221
+ if (args.auditSink) {
222
+ try {
223
+ await args.auditSink.write(buildEvent({
224
+ action: 'mcp-runtime.service-mac.accept',
225
+ outcome: 'success',
226
+ correlationId: args.correlationId,
227
+ actor: { type: 'service', id: args.ctx.service },
228
+ subject: { type: 'tool', id: args.ctx.route },
229
+ audience: args.ctx.audience,
230
+ context: {
231
+ keyId: args.headers.keyId,
232
+ nonceHash: nonceHashShort(args.headers.nonce),
233
+ },
234
+ }));
235
+ }
236
+ catch {
237
+ /* fail-soft */
238
+ }
239
+ }
240
+ return { ok: true };
241
+ }
242
+ // ─── Internals ────────────────────────────────────────────────────────
243
+ function nonceHashShort(nonce) {
244
+ // 8-byte prefix of sha256(nonce) — enough to correlate events
245
+ // without surfacing the raw one-shot nonce in logs.
246
+ const digest = sha256(toHex(nonce));
247
+ return digest.slice(0, 18); // '0x' + 16 hex chars
248
+ }
249
+ function cryptoRandomBytes(n) {
250
+ const out = new Uint8Array(n);
251
+ // Both Web Crypto (browsers, Workers) and Node 18+ have globalThis.crypto.
252
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
+ const g = globalThis;
254
+ if (g.crypto?.getRandomValues) {
255
+ g.crypto.getRandomValues(out);
256
+ return out;
257
+ }
258
+ throw new Error('serviceMac: crypto.getRandomValues unavailable');
259
+ }
260
+ //# sourceMappingURL=service-mac.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-mac.js","sourceRoot":"","sources":["../src/service-mac.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { Address, Hex } from '@agenticprimitives/types';
2
+ import type { Caveat, DataScopeGrant, Delegation, EnforcerAddressMap, JtiStore, VerifyError } from '@agenticprimitives/delegation';
3
+ import type { ToolClassification } from '@agenticprimitives/tool-policy';
4
+ export type { Address, Hex, Caveat, DataScopeGrant, Delegation, EnforcerAddressMap, JtiStore, ToolClassification, VerifyError };
5
+ export interface McpResourceVerifyConfig {
6
+ audience: string;
7
+ chainId: number;
8
+ rpcUrl: string;
9
+ delegationManager: Address;
10
+ enforcerMap: EnforcerAddressMap;
11
+ jtiStore: JtiStore;
12
+ acceptLegacyCrossDelegations?: boolean;
13
+ /**
14
+ * Whether to require the delegator's smart account to be on-chain.
15
+ * Default: `true` (fail-closed). When the account isn't deployed, ERC-1271
16
+ * can't be verified. Demos using counterfactual addresses without
17
+ * deploying may set `false` explicitly.
18
+ */
19
+ requireDeployed?: boolean;
20
+ /**
21
+ * Spec 207: `QuorumEnforcer` contract address for this chain. When a
22
+ * tool's classification produces a `requiresQuorum: true` decision
23
+ * from `tool-policy.evaluateThresholdPolicy(...)`, `withDelegation`
24
+ * threads this address into `delegation.verifyDelegationToken`'s
25
+ * `requireQuorumCaveat` opt so the delegation MUST carry a quorum
26
+ * caveat with this enforcer or verify fails closed.
27
+ *
28
+ * Consumer apps SHOULD configure this from their deployments JSON
29
+ * (packages/contracts/deployments-<network>.json's `quorumEnforcer`
30
+ * field). When unset, T3+ tools that require quorum will fail
31
+ * closed at the boundary — apps that don't ship multi-sig can
32
+ * either omit T3+ tools or leave this unset and stick to T1/T2.
33
+ */
34
+ quorumEnforcer?: Address;
35
+ }
36
+ export interface ResourceDefinition {
37
+ name: string;
38
+ audience: string;
39
+ fields?: string[];
40
+ }
41
+ export interface BetterSqlite3DatabaseLike {
42
+ prepare(sql: string): {
43
+ run(...args: unknown[]): unknown;
44
+ get(...args: unknown[]): unknown;
45
+ };
46
+ }
47
+ export interface PgPoolLike {
48
+ query(text: string, params?: unknown[]): Promise<{
49
+ rows: unknown[];
50
+ }>;
51
+ }
52
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EACV,MAAM,EACN,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,WAAW,EACZ,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC;AAEhI,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,EAAE,QAAQ,CAAC;IACnB,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QACpB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACjC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CACvE"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,135 @@
1
+ import type { Address } from '@agenticprimitives/types';
2
+ import type { ToolClassification } from '@agenticprimitives/tool-policy';
3
+ import { type AuditSink, type MetricsSink } from '@agenticprimitives/audit';
4
+ import type { DataScopeGrant, McpResourceVerifyConfig } from './types';
5
+ /**
6
+ * H7-F.1 / PKG-MCP-RUNTIME-003 / EXT-026 / EXT-032 closure — split
7
+ * public error surface from private failure context.
8
+ *
9
+ * Previously `McpAuthError.reason` carried the full denial cause
10
+ * ("policy deny: high-risk tool requires quorum", "delegation
11
+ * revoked at block N", "ERC-1271 returned 0x00…", etc.). A relying
12
+ * app that forwarded `error.reason` to the client leaked denial
13
+ * cause + occasionally PII (signer addresses, delegation hashes).
14
+ *
15
+ * The new surface:
16
+ * - {@link McpAuthError} is OPAQUE: carries only `code` (a small,
17
+ * bounded set) + an opaque `correlationId` the operator can use
18
+ * to look up the audit row.
19
+ * - {@link PrivateAuthFailureContext} is the rich shape emitted to
20
+ * the audit sink at the moment of failure. NEVER returned to the
21
+ * caller; consumed only by ops + forensics tooling.
22
+ *
23
+ * Migration note: tests that previously asserted on `error.reason`
24
+ * should assert on `error.code` instead and (for the rich shape)
25
+ * intercept the audit sink.
26
+ */
27
+ export type McpAuthErrorCode = 'auth-failed' | 'auth-misconfigured' | 'auth-paused';
28
+ export declare class McpAuthError extends Error {
29
+ readonly code: McpAuthErrorCode;
30
+ readonly correlationId: string;
31
+ constructor(code: McpAuthErrorCode, correlationId: string);
32
+ }
33
+ /**
34
+ * Rich failure context emitted to the audit sink. NEVER returned to
35
+ * the caller.
36
+ */
37
+ export interface PrivateAuthFailureContext {
38
+ /** Same correlationId as the thrown {@link McpAuthError}. */
39
+ correlationId: string;
40
+ /** The opaque public code. */
41
+ code: McpAuthErrorCode;
42
+ /**
43
+ * The ORIGINAL detailed denial reason (private). May contain
44
+ * delegation hashes, on-chain addresses, classification tier labels,
45
+ * etc. Routed to the audit sink (durable, op-only).
46
+ */
47
+ reason: string;
48
+ /** Tool name if known. */
49
+ toolName?: string;
50
+ /** Step the failure happened at (`verify`, `policy`, `classification`, etc.). */
51
+ stage?: string;
52
+ }
53
+ export declare function withDelegation<A extends Record<string, unknown>>(config: McpResourceVerifyConfig, handler: (args: A & {
54
+ principal: Address;
55
+ grants?: DataScopeGrant[];
56
+ }) => Promise<unknown>, opts?: {
57
+ toolName?: string;
58
+ /**
59
+ * Tool classification metadata (audit H2). When provided, the
60
+ * `evaluatePolicy()` decision engine runs after delegation verify;
61
+ * `deny` and `requires-consent` both reject with McpAuthError. When
62
+ * omitted, an internal warning is logged but the call proceeds
63
+ * (back-compat for unclassified demo tools). Production code MUST
64
+ * pass classification — the production preflight will eventually
65
+ * enforce this.
66
+ */
67
+ classification?: ToolClassification;
68
+ /**
69
+ * Audit sink (audit C3). When provided, the wrapper emits
70
+ * `mcp-runtime.with-delegation.{accept,reject}` events on every
71
+ * call. Omit only for tests / paths that explicitly opt out of
72
+ * forensics; production code MUST pass a sink and the preflight
73
+ * will eventually enforce.
74
+ */
75
+ auditSink?: AuditSink;
76
+ /** Correlation ID threaded into emitted events. */
77
+ correlationId?: string;
78
+ /**
79
+ * Metrics sink (production-readiness wave 1). When provided, the
80
+ * wrapper emits:
81
+ * - counter `mcp_runtime.with_delegation.calls` per call
82
+ * (tags: tool, audience, outcome ∈ accept|reject)
83
+ * - histogram `mcp_runtime.with_delegation.duration_ms` per call
84
+ * (tags: tool, audience, outcome)
85
+ * Cardinality is bounded by the tool registry; safe for production
86
+ * Prometheus / Datadog / OpenTelemetry pipelines.
87
+ */
88
+ metricsSink?: MetricsSink;
89
+ /**
90
+ * W3C traceparent header value (`00-{trace-id}-{parent-id}-{flags}`)
91
+ * captured from the inbound request. Forwarded on outbound calls
92
+ * the handler makes and stamped into emitted audit events so the
93
+ * full session→token→tool chain stitches together end-to-end.
94
+ */
95
+ traceparent?: string;
96
+ /**
97
+ * Production-readiness gate (audit H1). Inverted default behaviour:
98
+ * `withDelegation` runs in PRODUCTION mode unless the consumer
99
+ * explicitly opts out via `developmentMode: true` (test/dev shim)
100
+ * OR the runtime reports `NODE_ENV !== 'production'`. In
101
+ * production, the wrapper throws at construction time if
102
+ * `classification` or `auditSink` is missing. This makes the
103
+ * package API impossible to misuse: you can't register a tool
104
+ * wrapper without the metadata the policy engine + audit pipeline
105
+ * need.
106
+ *
107
+ * Pass `environment: 'production'` to force production (the
108
+ * canonical override; useful for tests that need to exercise prod
109
+ * gates without setting NODE_ENV). Pass `environment: 'development'`
110
+ * or `developmentMode: true` to opt out — required only for tests.
111
+ */
112
+ environment?: 'production' | 'development';
113
+ /**
114
+ * Explicit opt-out shorthand for non-production callers. Equivalent
115
+ * to `environment: 'development'`. Useful so test code reads as
116
+ * "this is intentionally a dev wrapper" rather than referencing
117
+ * the environment axis directly.
118
+ */
119
+ developmentMode?: boolean;
120
+ }): (args: A & {
121
+ token: string;
122
+ }) => Promise<unknown>;
123
+ export interface VerifyDelegationForResourceOpts {
124
+ toolName?: string;
125
+ }
126
+ export declare function verifyDelegationForResource(token: string, config: McpResourceVerifyConfig, ctx?: {
127
+ toolName?: string;
128
+ timestamp?: number;
129
+ }): Promise<{
130
+ principal: Address;
131
+ grants?: DataScopeGrant[];
132
+ } | {
133
+ error: string;
134
+ }>;
135
+ //# sourceMappingURL=with-delegation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-delegation.d.ts","sourceRoot":"","sources":["../src/with-delegation.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAO,MAAM,0BAA0B,CAAC;AAG7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AA4BvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,oBAAoB,GACpB,aAAa,CAAC;AAElB,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;gBACnB,IAAI,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM;CAM1D;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,MAAM,EAAE,uBAAuB,EAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;CAAE,KAAK,OAAO,CAAC,OAAO,CAAC,EAC1F,IAAI,CAAC,EAAE;IACL,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;IAC3C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GACA,CAAC,IAAI,EAAE,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAgNnD;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,uBAAuB,EAC/B,GAAG,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAYhF"}
@@ -0,0 +1,266 @@
1
+ // withDelegation — the headline wrapper.
2
+ //
3
+ // Pipeline (per spec 205 §2):
4
+ // 1. extract token from args
5
+ // 2. delegation.verifyDelegationToken(token, opts) — full chain check
6
+ // 3. tool-policy.evaluatePolicy(ctx) for classification gating
7
+ // (audit H2; fail-closed on deny / requires-consent / unknown
8
+ // classification)
9
+ // 4. invoke inner handler with verified { principal, grants? }
10
+ //
11
+ // Error responses must NOT leak the specific failure mode (malformed vs
12
+ // expired vs revoked vs caveat-failed vs policy-denied). Single
13
+ // "auth failed" error class.
14
+ import { verifyDelegationToken } from '@agenticprimitives/delegation';
15
+ import { evaluatePolicy, evaluateThresholdPolicy } from '@agenticprimitives/tool-policy';
16
+ import { buildEvent } from '@agenticprimitives/audit';
17
+ /**
18
+ * Resolve the effective environment for production-mode gates. Order
19
+ * of precedence:
20
+ * 1. Explicit `opts.environment` value.
21
+ * 2. `developmentMode: true` → 'development'.
22
+ * 3. `process.env.NODE_ENV` if readable.
23
+ * 4. Default to 'production' — safe-by-default when the runtime is
24
+ * ambiguous (Cloudflare Workers, Deno, browser). Consumers who
25
+ * want a permissive wrapper MUST opt out explicitly.
26
+ */
27
+ function inferEnvironment(opts) {
28
+ if (opts?.environment)
29
+ return opts.environment;
30
+ if (opts?.developmentMode === true)
31
+ return 'development';
32
+ try {
33
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV) {
34
+ return process.env.NODE_ENV === 'production' ? 'production' : 'development';
35
+ }
36
+ }
37
+ catch {
38
+ /* SES / Workers may throw on process access */
39
+ }
40
+ return 'production';
41
+ }
42
+ export class McpAuthError extends Error {
43
+ code;
44
+ correlationId;
45
+ constructor(code, correlationId) {
46
+ super('mcp: auth failed');
47
+ this.name = 'McpAuthError';
48
+ this.code = code;
49
+ this.correlationId = correlationId;
50
+ }
51
+ }
52
+ export function withDelegation(config, handler, opts) {
53
+ // Inferred environment — production-by-default per audit H1. The
54
+ // construction-time gate now fires unless the consumer explicitly
55
+ // opts into development.
56
+ const env = inferEnvironment(opts);
57
+ if (env === 'production') {
58
+ if (!opts?.classification) {
59
+ throw new Error('[mcp-runtime] withDelegation requires `classification` in production. ' +
60
+ 'The policy engine (tool-policy.evaluatePolicy) MUST run; an unclassified tool ' +
61
+ 'is a security regression. Pass `opts.classification = declareTool(...)`. ' +
62
+ 'For tests, pass `developmentMode: true` to opt out of the strict gate.');
63
+ }
64
+ if (!opts?.auditSink) {
65
+ throw new Error('[mcp-runtime] withDelegation requires `auditSink` in production. ' +
66
+ 'Audit emission is the only forensic trail for delegation accept/reject; ' +
67
+ 'production deployments MUST persist these. Pass a durable sink (D1, ' +
68
+ 'Cloud Logging, etc.) — wrap with composeSinks(durable, console) if you ' +
69
+ 'still want a tail-friendly mirror.');
70
+ }
71
+ }
72
+ return async (args) => {
73
+ // Pull `quorumProof` off args (audit H3). It's a delegation-layer
74
+ // concern, not handler input. Either the caller serializes proof
75
+ // alongside the token, or there's no proof — and the verifier
76
+ // rejects accordingly when `requireQuorumCaveat` is set.
77
+ const { token, quorumProof, ...rest } = args;
78
+ const toolName = opts?.toolName ?? 'unknown';
79
+ // H7-F.1: every request gets a stable correlationId. Caller-supplied
80
+ // wins; otherwise mint a random one so the thrown McpAuthError carries
81
+ // a non-empty handle the operator can correlate with audit rows.
82
+ const correlationId = opts?.correlationId ??
83
+ `wd-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
84
+ const startedAt = Date.now();
85
+ const metric = opts?.metricsSink;
86
+ const emit = async (outcome, reason, principal) => {
87
+ // Metrics fire in lockstep with audit emissions so a single
88
+ // observability pipeline sees both the structured event AND the
89
+ // counter/histogram. Cardinality is bounded by tool name +
90
+ // audience + outcome — safe for production Prometheus.
91
+ if (metric) {
92
+ const tags = {
93
+ tool: toolName,
94
+ audience: config.audience ?? 'unknown',
95
+ outcome: outcome === 'success' ? 'accept' : 'reject',
96
+ };
97
+ try {
98
+ metric.increment('mcp_runtime.with_delegation.calls', 1, tags);
99
+ }
100
+ catch { /* fail-soft */ }
101
+ try {
102
+ metric.observe('mcp_runtime.with_delegation.duration_ms', Date.now() - startedAt, tags);
103
+ }
104
+ catch { /* fail-soft */ }
105
+ }
106
+ if (!opts?.auditSink)
107
+ return;
108
+ try {
109
+ await opts.auditSink.write(buildEvent({
110
+ action: outcome === 'success'
111
+ ? 'mcp-runtime.with-delegation.accept'
112
+ : 'mcp-runtime.with-delegation.reject',
113
+ outcome,
114
+ correlationId,
115
+ actor: principal ? { type: 'user', id: principal } : { type: 'unknown' },
116
+ subject: { type: 'tool', id: toolName },
117
+ audience: config.audience,
118
+ chainId: config.chainId,
119
+ reason,
120
+ // Traceparent (W3C) stamped into context for downstream
121
+ // trace correlation. Reject events still carry the trace.
122
+ context: opts?.traceparent ? { traceparent: opts.traceparent } : undefined,
123
+ }));
124
+ }
125
+ catch {
126
+ // Fail-soft: audit emission must never break the auth flow.
127
+ // composeSinks should be doing this for us, but belt-and-braces.
128
+ }
129
+ };
130
+ if (typeof token !== 'string' || token.length === 0) {
131
+ // H7-F.1: private reason goes to audit; caller sees opaque code.
132
+ await emit('denied', 'missing token', undefined);
133
+ throw new McpAuthError('auth-failed', correlationId);
134
+ }
135
+ // Spec 207 threshold-policy: when a classification is provided,
136
+ // derive the threshold-policy decision via tool-policy +
137
+ // translate into delegation's verify opts. Pre-verify check so a
138
+ // missing quorum caveat or absent on-chain blessing fails closed
139
+ // before any chain reads.
140
+ let requireQuorumCaveat;
141
+ let requireAcceptedOnChain;
142
+ if (opts?.classification) {
143
+ const thrDecision = evaluateThresholdPolicy(opts.classification);
144
+ if (thrDecision.requiresQuorum) {
145
+ if (!config.quorumEnforcer) {
146
+ // Fail closed at the boundary — a T3+ tool that needs
147
+ // quorum can't be verified if the runtime doesn't know
148
+ // where to find the QuorumEnforcer. Consumer apps must
149
+ // wire `config.quorumEnforcer` from their deployments JSON.
150
+ const detail = 'tool requires quorum caveat but mcp-runtime has no quorumEnforcer configured';
151
+ console.error('[mcp-runtime] auth misconfigured:', detail);
152
+ await emit('denied', detail, undefined);
153
+ // H7-F.1: server-side config gap surfaces as the distinct
154
+ // 'auth-misconfigured' code so the caller can distinguish from
155
+ // a legitimate credential reject.
156
+ throw new McpAuthError('auth-misconfigured', correlationId);
157
+ }
158
+ requireQuorumCaveat = { enforcer: config.quorumEnforcer };
159
+ }
160
+ if (thrDecision.requiresAcceptedOnChain) {
161
+ requireAcceptedOnChain = true;
162
+ }
163
+ // `requiresUv` from the threshold-policy decision is verified
164
+ // at the SIGNER layer (the wallet sets the WebAuthn UV flag when
165
+ // producing the delegation signature). delegation's verify path
166
+ // doesn't re-check UV because it would need to parse the
167
+ // passkey signature blob; that's the consumer app's
168
+ // responsibility at signing time.
169
+ }
170
+ const result = await verifyDelegationToken(token, {
171
+ audience: config.audience,
172
+ chainId: config.chainId,
173
+ rpcUrl: config.rpcUrl,
174
+ delegationManager: config.delegationManager,
175
+ enforcerMap: config.enforcerMap,
176
+ jtiStore: config.jtiStore,
177
+ toolName: opts?.toolName,
178
+ requireDeployed: config.requireDeployed,
179
+ // Thread the audit sink + correlation id down so delegation
180
+ // emits `delegation.verify.{accept,reject}` events through the
181
+ // same sink as `mcp-runtime.with-delegation.*`. Pass 3b.
182
+ auditSink: opts?.auditSink,
183
+ correlationId,
184
+ // Spec 207 threshold-policy gates (6c.4). Both undefined for T1
185
+ // tools; either or both set for T2+ depending on the tool's
186
+ // `@sa-risk-tier` classification.
187
+ requireQuorumCaveat,
188
+ requireAcceptedOnChain,
189
+ // Audit H3 — when requireQuorumCaveat is set, delegation refuses
190
+ // without an explicit proof. Forward the caller-supplied proof
191
+ // through; if missing, the verifier rejects (a Wave H1 production
192
+ // wrapper would have already thrown at construction if the tool
193
+ // is unclassified).
194
+ quorumProof,
195
+ });
196
+ if ('error' in result) {
197
+ // H7-F.1: the private reason (which may carry delegation hashes
198
+ // or signer addresses) is emitted to the audit sink and stays
199
+ // server-side. The caller sees only the opaque code + correlationId
200
+ // they can quote to the operator for forensics.
201
+ console.error('[mcp-runtime] auth failed:', result.error);
202
+ await emit('denied', result.error, undefined);
203
+ throw new McpAuthError('auth-failed', correlationId);
204
+ }
205
+ // Policy enforcement (audit H2). Fail-closed on deny + requires-consent.
206
+ if (opts?.classification) {
207
+ const decision = evaluatePolicy({
208
+ toolName,
209
+ classification: opts.classification,
210
+ callerKind: 'user-session',
211
+ delegation: {
212
+ delegator: result.principal,
213
+ delegate: result.principal,
214
+ caveats: [],
215
+ },
216
+ });
217
+ if (decision.decision !== 'allow') {
218
+ // Spec 207 reconciliation: critical-risk tools have historically
219
+ // returned `requires-consent` from evaluatePolicy + the wrapper
220
+ // failed closed because the runtime doesn't host a consent loop
221
+ // (audit H2). The threshold-policy `requiresAcceptedOnChain`
222
+ // gate IS the consent loop for that path — the user committed
223
+ // an `acceptSessionDelegation(hash)` transaction in advance.
224
+ // When that gate is in force AND it passed (verify didn't
225
+ // reject), the requires-consent outcome is satisfied.
226
+ const thrDec = evaluateThresholdPolicy(opts.classification);
227
+ const satisfiedByOnChainBlessing = decision.decision === 'requires-consent' && thrDec.requiresAcceptedOnChain;
228
+ if (!satisfiedByOnChainBlessing) {
229
+ const detail = decision.decision === 'deny'
230
+ ? `policy deny: ${decision.reason}`
231
+ : `policy requires-consent (${decision.promptId}); runtime does not host consent loop`;
232
+ console.error('[mcp-runtime] auth failed:', detail);
233
+ await emit('denied', detail, result.principal);
234
+ // H7-F.1: same opaque shape as other reject paths.
235
+ throw new McpAuthError('auth-failed', correlationId);
236
+ }
237
+ }
238
+ }
239
+ else {
240
+ console.warn('[mcp-runtime] withDelegation called without classification — ' +
241
+ 'consider passing opts.classification for policy enforcement (audit H2)');
242
+ }
243
+ await emit('success', undefined, result.principal);
244
+ return handler({ ...rest, principal: result.principal, grants: result.grants });
245
+ };
246
+ }
247
+ export async function verifyDelegationForResource(token, config, ctx) {
248
+ return verifyDelegationToken(token, {
249
+ audience: config.audience,
250
+ chainId: config.chainId,
251
+ rpcUrl: config.rpcUrl,
252
+ delegationManager: config.delegationManager,
253
+ enforcerMap: config.enforcerMap,
254
+ jtiStore: config.jtiStore,
255
+ toolName: ctx?.toolName,
256
+ requireDeployed: config.requireDeployed,
257
+ now: ctx?.timestamp ? () => ctx.timestamp * 1000 : undefined,
258
+ });
259
+ }
260
+ // H7-B.8 (XPKG-002 / EXT-024 closure) — `withCrossDelegation` +
261
+ // `verifyCrossDelegationForResource` were public symbols that
262
+ // unconditionally rejected. Removed from the public surface; will land
263
+ // behind `./experimental` per spec 100 §6 when the cross-delegation work
264
+ // resumes. See PKG-mcp-runtime-001 in
265
+ // docs/audits/2026-05-packages-contracts-production-readiness.md.
266
+ //# sourceMappingURL=with-delegation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-delegation.js","sourceRoot":"","sources":["../src/with-delegation.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@agenticprimitives/mcp-runtime",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Delegation-aware authorization middleware around the official MCP TypeScript SDK. The decision layer, not the SDK.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
9
+ "directory": "packages/mcp-runtime"
10
+ },
11
+ "homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/mcp-runtime",
12
+ "bugs": {
13
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./testing": {
24
+ "types": "./dist/testing.d.ts",
25
+ "import": "./dist/testing.js"
26
+ },
27
+ "./lint": {
28
+ "types": "./dist/lint.d.ts",
29
+ "import": "./dist/lint.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "LICENSE",
34
+ "dist",
35
+ "spec.md",
36
+ "README.md"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc -p tsconfig.build.json",
40
+ "typecheck": "tsc -p tsconfig.json --noEmit",
41
+ "test": "vitest run",
42
+ "test:unit": "vitest run test/unit",
43
+ "test:integration": "vitest run test/integration --passWithNoTests",
44
+ "test:watch": "vitest",
45
+ "clean": "rm -rf dist"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "peerDependencies": {
51
+ "@agenticprimitives/audit": "workspace:*",
52
+ "@agenticprimitives/delegation": "workspace:*",
53
+ "@agenticprimitives/key-custody": "workspace:*",
54
+ "@agenticprimitives/tool-policy": "workspace:*",
55
+ "@agenticprimitives/types": "workspace:*",
56
+ "@modelcontextprotocol/sdk": ">=1.29.0 <2",
57
+ "viem": "^2.50.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^22.7.0",
61
+ "vitest": "^2.1.0"
62
+ },
63
+ "keywords": [
64
+ "mcp",
65
+ "model-context-protocol",
66
+ "delegation",
67
+ "authorization",
68
+ "agentic"
69
+ ]
70
+ }
package/spec.md ADDED
@@ -0,0 +1,6 @@
1
+ # @agenticprimitives/mcp-runtime — spec
2
+
3
+ The authoritative specification lives at:
4
+ **[`../../specs/205-mcp-runtime.md`](../../specs/205-mcp-runtime.md)**
5
+
6
+ Do not edit a divergent copy here.