@mcp-i/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +390 -0
  3. package/dist/auth/handshake.d.ts +104 -0
  4. package/dist/auth/handshake.d.ts.map +1 -0
  5. package/dist/auth/handshake.js +230 -0
  6. package/dist/auth/handshake.js.map +1 -0
  7. package/dist/auth/index.d.ts +3 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +2 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/types.d.ts +31 -0
  12. package/dist/auth/types.d.ts.map +1 -0
  13. package/dist/auth/types.js +7 -0
  14. package/dist/auth/types.js.map +1 -0
  15. package/dist/delegation/audience-validator.d.ts +9 -0
  16. package/dist/delegation/audience-validator.d.ts.map +1 -0
  17. package/dist/delegation/audience-validator.js +17 -0
  18. package/dist/delegation/audience-validator.js.map +1 -0
  19. package/dist/delegation/bitstring.d.ts +37 -0
  20. package/dist/delegation/bitstring.d.ts.map +1 -0
  21. package/dist/delegation/bitstring.js +117 -0
  22. package/dist/delegation/bitstring.js.map +1 -0
  23. package/dist/delegation/cascading-revocation.d.ts +45 -0
  24. package/dist/delegation/cascading-revocation.d.ts.map +1 -0
  25. package/dist/delegation/cascading-revocation.js +148 -0
  26. package/dist/delegation/cascading-revocation.js.map +1 -0
  27. package/dist/delegation/delegation-graph.d.ts +49 -0
  28. package/dist/delegation/delegation-graph.d.ts.map +1 -0
  29. package/dist/delegation/delegation-graph.js +99 -0
  30. package/dist/delegation/delegation-graph.js.map +1 -0
  31. package/dist/delegation/did-key-resolver.d.ts +64 -0
  32. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  33. package/dist/delegation/did-key-resolver.js +154 -0
  34. package/dist/delegation/did-key-resolver.js.map +1 -0
  35. package/dist/delegation/did-web-resolver.d.ts +83 -0
  36. package/dist/delegation/did-web-resolver.d.ts.map +1 -0
  37. package/dist/delegation/did-web-resolver.js +218 -0
  38. package/dist/delegation/did-web-resolver.js.map +1 -0
  39. package/dist/delegation/index.d.ts +21 -0
  40. package/dist/delegation/index.d.ts.map +1 -0
  41. package/dist/delegation/index.js +21 -0
  42. package/dist/delegation/index.js.map +1 -0
  43. package/dist/delegation/outbound-headers.d.ts +81 -0
  44. package/dist/delegation/outbound-headers.d.ts.map +1 -0
  45. package/dist/delegation/outbound-headers.js +139 -0
  46. package/dist/delegation/outbound-headers.js.map +1 -0
  47. package/dist/delegation/outbound-proof.d.ts +43 -0
  48. package/dist/delegation/outbound-proof.d.ts.map +1 -0
  49. package/dist/delegation/outbound-proof.js +52 -0
  50. package/dist/delegation/outbound-proof.js.map +1 -0
  51. package/dist/delegation/statuslist-manager.d.ts +44 -0
  52. package/dist/delegation/statuslist-manager.d.ts.map +1 -0
  53. package/dist/delegation/statuslist-manager.js +126 -0
  54. package/dist/delegation/statuslist-manager.js.map +1 -0
  55. package/dist/delegation/storage/memory-graph-storage.d.ts +70 -0
  56. package/dist/delegation/storage/memory-graph-storage.d.ts.map +1 -0
  57. package/dist/delegation/storage/memory-graph-storage.js +145 -0
  58. package/dist/delegation/storage/memory-graph-storage.js.map +1 -0
  59. package/dist/delegation/storage/memory-statuslist-storage.d.ts +19 -0
  60. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +1 -0
  61. package/dist/delegation/storage/memory-statuslist-storage.js +33 -0
  62. package/dist/delegation/storage/memory-statuslist-storage.js.map +1 -0
  63. package/dist/delegation/utils.d.ts +49 -0
  64. package/dist/delegation/utils.d.ts.map +1 -0
  65. package/dist/delegation/utils.js +131 -0
  66. package/dist/delegation/utils.js.map +1 -0
  67. package/dist/delegation/vc-issuer.d.ts +56 -0
  68. package/dist/delegation/vc-issuer.d.ts.map +1 -0
  69. package/dist/delegation/vc-issuer.js +80 -0
  70. package/dist/delegation/vc-issuer.js.map +1 -0
  71. package/dist/delegation/vc-verifier.d.ts +112 -0
  72. package/dist/delegation/vc-verifier.d.ts.map +1 -0
  73. package/dist/delegation/vc-verifier.js +280 -0
  74. package/dist/delegation/vc-verifier.js.map +1 -0
  75. package/dist/index.d.ts +45 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +53 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/logging/index.d.ts +2 -0
  80. package/dist/logging/index.d.ts.map +1 -0
  81. package/dist/logging/index.js +2 -0
  82. package/dist/logging/index.js.map +1 -0
  83. package/dist/logging/logger.d.ts +23 -0
  84. package/dist/logging/logger.d.ts.map +1 -0
  85. package/dist/logging/logger.js +82 -0
  86. package/dist/logging/logger.js.map +1 -0
  87. package/dist/middleware/index.d.ts +7 -0
  88. package/dist/middleware/index.d.ts.map +1 -0
  89. package/dist/middleware/index.js +7 -0
  90. package/dist/middleware/index.js.map +1 -0
  91. package/dist/middleware/with-mcpi.d.ts +152 -0
  92. package/dist/middleware/with-mcpi.d.ts.map +1 -0
  93. package/dist/middleware/with-mcpi.js +472 -0
  94. package/dist/middleware/with-mcpi.js.map +1 -0
  95. package/dist/proof/errors.d.ts +49 -0
  96. package/dist/proof/errors.d.ts.map +1 -0
  97. package/dist/proof/errors.js +61 -0
  98. package/dist/proof/errors.js.map +1 -0
  99. package/dist/proof/generator.d.ts +65 -0
  100. package/dist/proof/generator.d.ts.map +1 -0
  101. package/dist/proof/generator.js +163 -0
  102. package/dist/proof/generator.js.map +1 -0
  103. package/dist/proof/index.d.ts +4 -0
  104. package/dist/proof/index.d.ts.map +1 -0
  105. package/dist/proof/index.js +4 -0
  106. package/dist/proof/index.js.map +1 -0
  107. package/dist/proof/verifier.d.ts +108 -0
  108. package/dist/proof/verifier.d.ts.map +1 -0
  109. package/dist/proof/verifier.js +299 -0
  110. package/dist/proof/verifier.js.map +1 -0
  111. package/dist/providers/base.d.ts +64 -0
  112. package/dist/providers/base.d.ts.map +1 -0
  113. package/dist/providers/base.js +19 -0
  114. package/dist/providers/base.js.map +1 -0
  115. package/dist/providers/index.d.ts +3 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +3 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/memory.d.ts +33 -0
  120. package/dist/providers/memory.d.ts.map +1 -0
  121. package/dist/providers/memory.js +102 -0
  122. package/dist/providers/memory.js.map +1 -0
  123. package/dist/session/index.d.ts +2 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +2 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/session/manager.d.ts +77 -0
  128. package/dist/session/manager.d.ts.map +1 -0
  129. package/dist/session/manager.js +251 -0
  130. package/dist/session/manager.js.map +1 -0
  131. package/dist/types/protocol.d.ts +320 -0
  132. package/dist/types/protocol.d.ts.map +1 -0
  133. package/dist/types/protocol.js +229 -0
  134. package/dist/types/protocol.js.map +1 -0
  135. package/dist/utils/base58.d.ts +31 -0
  136. package/dist/utils/base58.d.ts.map +1 -0
  137. package/dist/utils/base58.js +104 -0
  138. package/dist/utils/base58.js.map +1 -0
  139. package/dist/utils/base64.d.ts +13 -0
  140. package/dist/utils/base64.d.ts.map +1 -0
  141. package/dist/utils/base64.js +99 -0
  142. package/dist/utils/base64.js.map +1 -0
  143. package/dist/utils/crypto-service.d.ts +37 -0
  144. package/dist/utils/crypto-service.d.ts.map +1 -0
  145. package/dist/utils/crypto-service.js +153 -0
  146. package/dist/utils/crypto-service.js.map +1 -0
  147. package/dist/utils/did-helpers.d.ts +156 -0
  148. package/dist/utils/did-helpers.d.ts.map +1 -0
  149. package/dist/utils/did-helpers.js +193 -0
  150. package/dist/utils/did-helpers.js.map +1 -0
  151. package/dist/utils/ed25519-constants.d.ts +18 -0
  152. package/dist/utils/ed25519-constants.d.ts.map +1 -0
  153. package/dist/utils/ed25519-constants.js +21 -0
  154. package/dist/utils/ed25519-constants.js.map +1 -0
  155. package/dist/utils/index.d.ts +5 -0
  156. package/dist/utils/index.d.ts.map +1 -0
  157. package/dist/utils/index.js +5 -0
  158. package/dist/utils/index.js.map +1 -0
  159. package/package.json +105 -0
  160. package/src/__tests__/integration/full-flow.test.ts +362 -0
  161. package/src/__tests__/providers/base.test.ts +173 -0
  162. package/src/__tests__/providers/memory.test.ts +332 -0
  163. package/src/__tests__/utils/mock-providers.ts +319 -0
  164. package/src/__tests__/utils/node-crypto-provider.ts +93 -0
  165. package/src/auth/handshake.ts +411 -0
  166. package/src/auth/index.ts +11 -0
  167. package/src/auth/types.ts +40 -0
  168. package/src/delegation/__tests__/audience-validator.test.ts +110 -0
  169. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  170. package/src/delegation/__tests__/cascading-revocation.test.ts +624 -0
  171. package/src/delegation/__tests__/delegation-graph.test.ts +623 -0
  172. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  173. package/src/delegation/__tests__/did-web-resolver.test.ts +467 -0
  174. package/src/delegation/__tests__/outbound-headers.test.ts +230 -0
  175. package/src/delegation/__tests__/outbound-proof.test.ts +179 -0
  176. package/src/delegation/__tests__/statuslist-manager.test.ts +515 -0
  177. package/src/delegation/__tests__/utils.test.ts +185 -0
  178. package/src/delegation/__tests__/vc-issuer.test.ts +487 -0
  179. package/src/delegation/__tests__/vc-verifier.test.ts +1029 -0
  180. package/src/delegation/audience-validator.ts +24 -0
  181. package/src/delegation/bitstring.ts +160 -0
  182. package/src/delegation/cascading-revocation.ts +224 -0
  183. package/src/delegation/delegation-graph.ts +143 -0
  184. package/src/delegation/did-key-resolver.ts +181 -0
  185. package/src/delegation/did-web-resolver.ts +270 -0
  186. package/src/delegation/index.ts +33 -0
  187. package/src/delegation/outbound-headers.ts +193 -0
  188. package/src/delegation/outbound-proof.ts +90 -0
  189. package/src/delegation/statuslist-manager.ts +219 -0
  190. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  191. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  192. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  193. package/src/delegation/storage/memory-statuslist-storage.ts +42 -0
  194. package/src/delegation/utils.ts +189 -0
  195. package/src/delegation/vc-issuer.ts +137 -0
  196. package/src/delegation/vc-verifier.ts +440 -0
  197. package/src/index.ts +264 -0
  198. package/src/logging/__tests__/logger.test.ts +366 -0
  199. package/src/logging/index.ts +6 -0
  200. package/src/logging/logger.ts +91 -0
  201. package/src/middleware/__tests__/with-mcpi.test.ts +504 -0
  202. package/src/middleware/index.ts +16 -0
  203. package/src/middleware/with-mcpi.ts +766 -0
  204. package/src/proof/__tests__/proof-generator.test.ts +483 -0
  205. package/src/proof/__tests__/verifier.test.ts +488 -0
  206. package/src/proof/errors.ts +75 -0
  207. package/src/proof/generator.ts +255 -0
  208. package/src/proof/index.ts +22 -0
  209. package/src/proof/verifier.ts +449 -0
  210. package/src/providers/base.ts +68 -0
  211. package/src/providers/index.ts +15 -0
  212. package/src/providers/memory.ts +130 -0
  213. package/src/session/__tests__/session-manager.test.ts +342 -0
  214. package/src/session/index.ts +7 -0
  215. package/src/session/manager.ts +332 -0
  216. package/src/types/protocol.ts +596 -0
  217. package/src/utils/__tests__/base58.test.ts +281 -0
  218. package/src/utils/__tests__/base64.test.ts +239 -0
  219. package/src/utils/__tests__/crypto-service.test.ts +530 -0
  220. package/src/utils/__tests__/did-helpers.test.ts +156 -0
  221. package/src/utils/base58.ts +115 -0
  222. package/src/utils/base64.ts +116 -0
  223. package/src/utils/crypto-service.ts +209 -0
  224. package/src/utils/did-helpers.ts +210 -0
  225. package/src/utils/ed25519-constants.ts +23 -0
  226. package/src/utils/index.ts +9 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MCP-Identity
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,390 @@
1
+ # @mcp-i/core
2
+
3
+ **MCP-I protocol reference implementation** — delegation, proof, and session for the Model Context Protocol Identity (MCP-I) standard.
4
+
5
+ > This package is a [DIF TAAWG](https://identity.foundation/working-groups/agent-and-authorization.html) protocol reference implementation donated to the Decentralized Identity Foundation.
6
+
7
+ ---
8
+
9
+ ## What is MCP-I?
10
+
11
+ MCP-I (Model Context Protocol Identity) is a protocol extension for the Model Context Protocol (MCP) that adds cryptographic identity, delegation chains, and non-repudiation proofs to AI agent interactions. It enables MCP servers to verify *who* is calling (agent DID), *on whose behalf* (user delegation), and *what* was done (signed proof). Delegations are issued as W3C Verifiable Credentials with Ed25519 signatures, revocation is tracked via StatusList2021, and every tool call produces a detached JWS proof for audit trails.
12
+
13
+ Spec: [modelcontextprotocol-identity.io](https://modelcontextprotocol-identity.io)
14
+
15
+ ---
16
+
17
+ ## What this package provides
18
+
19
+ | Module | Description |
20
+ |--------|-------------|
21
+ | **delegation** | W3C VC delegation issuance (`DelegationCredentialIssuer`), verification (`DelegationCredentialVerifier`), graph management, StatusList2021 revocation, cascading revocation, outbound delegation propagation (`buildOutboundDelegationHeaders`), DID:key resolution (`createDidKeyResolver`), and DID:web resolution (`createDidWebResolver`) |
22
+ | **proof** | Platform-agnostic proof generation (`ProofGenerator`) and server-side verification (`ProofVerifier`) — JCS canonicalization, SHA-256 hashing, Ed25519 JWS signing/verification |
23
+ | **session** | Handshake validation and session management (`SessionManager`) with nonce replay prevention |
24
+ | **auth** | Authorization handshake orchestration (`verifyOrHints`) — checks delegation and returns authorization hints |
25
+ | **middleware** | MCP SDK integration (`createMCPIMiddleware`) — adds identity, sessions, and proof generation to a standard `@modelcontextprotocol/sdk` Server |
26
+ | **providers** | Abstract base classes (`CryptoProvider`, `StorageProvider`, etc.) and in-memory implementations for testing |
27
+ | **types** | Pure TypeScript interfaces for all protocol types — zero runtime dependencies |
28
+
29
+ ---
30
+
31
+ ## Quick Start
32
+
33
+ The fastest way to see MCP-I in action is the example server:
34
+
35
+ ```bash
36
+ git clone https://github.com/modelcontextprotocol-identity/mcp-i-core.git
37
+ cd mcp-i-core
38
+ pnpm install
39
+ npx tsx examples/node-server/server.ts
40
+ ```
41
+
42
+ This starts an MCP server on stdio with identity handshake and proof generation. See [`examples/node-server/README.md`](./examples/node-server/README.md) for details.
43
+
44
+ For outbound delegation propagation (forwarding delegation context to downstream services), see [`examples/outbound-delegation/README.md`](./examples/outbound-delegation/README.md).
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ npm install @mcp-i/core
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Delegation Hardening Compatibility
57
+
58
+ `createMCPIMiddleware` now enforces strict delegation-chain and status-list checks by default.
59
+
60
+ - Credentials with `parentId` require `delegation.resolveDelegationChain`.
61
+ - Credentials with `credentialStatus` require `delegation.statusListResolver`.
62
+
63
+ For temporary migration support in legacy integrations, you can opt in to compatibility mode:
64
+
65
+ ```typescript
66
+ const mcpi = createMCPIMiddleware(
67
+ {
68
+ identity,
69
+ delegation: {
70
+ allowLegacyUnsafeDelegation: true, // temporary compatibility escape hatch
71
+ },
72
+ },
73
+ cryptoProvider
74
+ );
75
+ ```
76
+
77
+ Compatibility mode weakens security guarantees and should only be used during migration.
78
+
79
+ ---
80
+
81
+ ## Examples
82
+
83
+ > Requires Node.js 20+. Save each block as `example.ts` and run with `npx tsx example.ts`.
84
+
85
+ ---
86
+
87
+ ## Example 1 — Issue a Delegation VC
88
+
89
+ ```typescript
90
+ import {
91
+ createHash,
92
+ createPrivateKey,
93
+ generateKeyPairSync,
94
+ randomBytes,
95
+ sign as nodeSign,
96
+ } from 'node:crypto';
97
+ import {
98
+ CryptoProvider,
99
+ MemoryIdentityProvider,
100
+ DelegationCredentialIssuer,
101
+ type DelegationIdentityProvider,
102
+ type VCSigningFunction,
103
+ } from '@mcp-i/core';
104
+
105
+ // Minimal Node.js CryptoProvider backed by node:crypto
106
+ class NodeCryptoProvider extends CryptoProvider {
107
+ async generateKeyPair() {
108
+ const { privateKey: pk, publicKey: pub } = generateKeyPairSync('ed25519', {
109
+ privateKeyEncoding: { type: 'pkcs8', format: 'der' },
110
+ publicKeyEncoding: { type: 'spki', format: 'der' },
111
+ });
112
+ // Ed25519 PKCS8 DER: 16-byte header + 32-byte seed
113
+ // Ed25519 SPKI DER: 12-byte header + 32-byte public key
114
+ return {
115
+ privateKey: (pk as Buffer).subarray(16).toString('base64'),
116
+ publicKey: (pub as Buffer).subarray(12).toString('base64'),
117
+ };
118
+ }
119
+ async hash(data: Uint8Array) {
120
+ return 'sha256:' + createHash('sha256').update(data).digest('hex');
121
+ }
122
+ async randomBytes(n: number) { return new Uint8Array(randomBytes(n)); }
123
+ async sign(data: Uint8Array, privateKeyBase64: string) {
124
+ const seed = Buffer.from(privateKeyBase64, 'base64').subarray(0, 32);
125
+ const hdr = Buffer.from([
126
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05,
127
+ 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
128
+ ]);
129
+ const key = createPrivateKey({ key: Buffer.concat([hdr, seed]), format: 'der', type: 'pkcs8' });
130
+ return new Uint8Array(nodeSign(null, data, key));
131
+ }
132
+ async verify(): Promise<boolean> { throw new Error('unused'); }
133
+ }
134
+
135
+ const cryptoProvider = new NodeCryptoProvider();
136
+
137
+ // MemoryIdentityProvider generates a real Ed25519 DID + key pair
138
+ const identityProvider = new MemoryIdentityProvider(cryptoProvider);
139
+ const agent = await identityProvider.getIdentity();
140
+
141
+ // Adapt AgentIdentity to the DelegationIdentityProvider interface
142
+ const identity: DelegationIdentityProvider = {
143
+ getDid: () => agent.did,
144
+ getKeyId: () => agent.kid,
145
+ getPrivateKey: () => agent.privateKey,
146
+ };
147
+
148
+ // Real Ed25519 signing function — delegates to NodeCryptoProvider
149
+ const signingFunction: VCSigningFunction = async (canonicalVC, issuerDid) => {
150
+ const sig = await cryptoProvider.sign(
151
+ new TextEncoder().encode(canonicalVC),
152
+ agent.privateKey
153
+ );
154
+ return {
155
+ type: 'Ed25519Signature2020',
156
+ created: new Date().toISOString(),
157
+ verificationMethod: `${issuerDid}#key-1`,
158
+ proofPurpose: 'assertionMethod',
159
+ proofValue: Buffer.from(sig).toString('base64url'),
160
+ };
161
+ };
162
+
163
+ const issuer = new DelegationCredentialIssuer(identity, signingFunction);
164
+
165
+ const vc = await issuer.createAndIssueDelegation({
166
+ id: 'delegation-001',
167
+ issuerDid: agent.did,
168
+ subjectDid: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuias8sisDArDJF74t',
169
+ constraints: {
170
+ scopes: ['tool:execute', 'resource:read'],
171
+ notAfter: Math.floor(Date.now() / 1000) + 3600,
172
+ },
173
+ });
174
+
175
+ console.log('VC type:', vc.type);
176
+ // ['VerifiableCredential', 'DelegationCredential']
177
+ console.log('Scopes:', vc.credentialSubject.delegation.constraints.scopes);
178
+ // ['tool:execute', 'resource:read']
179
+ console.log('Proof type:', vc.proof?.type);
180
+ // 'Ed25519Signature2020'
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Example 2 — Session Handshake
186
+
187
+ ```typescript
188
+ import { randomBytes } from 'node:crypto';
189
+ import {
190
+ CryptoProvider,
191
+ SessionManager,
192
+ MemoryNonceCacheProvider,
193
+ createHandshakeRequest,
194
+ } from '@mcp-i/core';
195
+
196
+ // SessionManager only needs randomBytes() for session ID generation
197
+ class NodeCryptoProvider extends CryptoProvider {
198
+ async randomBytes(n: number) { return new Uint8Array(randomBytes(n)); }
199
+ async generateKeyPair(): Promise<{ privateKey: string; publicKey: string }> { throw new Error('unused'); }
200
+ async hash(_: Uint8Array): Promise<string> { throw new Error('unused'); }
201
+ async sign(_: Uint8Array, __: string): Promise<Uint8Array> { throw new Error('unused'); }
202
+ async verify(_: Uint8Array, __: Uint8Array, ___: string): Promise<boolean> { throw new Error('unused'); }
203
+ }
204
+
205
+ const cryptoProvider = new NodeCryptoProvider();
206
+ const nonceCache = new MemoryNonceCacheProvider();
207
+
208
+ const sessionManager = new SessionManager(cryptoProvider, {
209
+ nonceCache,
210
+ sessionTtlMinutes: 30,
211
+ timestampSkewSeconds: 120,
212
+ serverDid: 'did:web:my-mcp-server.example.com',
213
+ });
214
+
215
+ // Client: build handshake request (uses globalThis.crypto, built into Node 20+)
216
+ const request = createHandshakeRequest('did:web:my-mcp-server.example.com');
217
+ request.agentDid = 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK';
218
+
219
+ // Server: validate it
220
+ const result = await sessionManager.validateHandshake(request);
221
+
222
+ if (result.success && result.session) {
223
+ console.log('Session ID:', result.session.sessionId);
224
+ // e.g. 'mcpi_4f3e2a1b-c7d2-4e5f-b6a3-...'
225
+ console.log('Audience:', result.session.audience);
226
+ // 'did:web:my-mcp-server.example.com'
227
+ console.log('Agent DID:', result.session.agentDid);
228
+ // 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK'
229
+ }
230
+ console.log('Stats:', sessionManager.getStats());
231
+ // { activeSessions: 1, config: { sessionTtlMinutes: 30, ... } }
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Example 3 — Generate a Tool Call Proof
237
+
238
+ ```typescript
239
+ import {
240
+ createHash,
241
+ createPrivateKey,
242
+ generateKeyPairSync,
243
+ randomBytes,
244
+ sign as nodeSign,
245
+ } from 'node:crypto';
246
+ import {
247
+ CryptoProvider,
248
+ MemoryIdentityProvider,
249
+ ProofGenerator,
250
+ SessionManager,
251
+ } from '@mcp-i/core';
252
+
253
+ class NodeCryptoProvider extends CryptoProvider {
254
+ async generateKeyPair() {
255
+ const { privateKey: pk, publicKey: pub } = generateKeyPairSync('ed25519', {
256
+ privateKeyEncoding: { type: 'pkcs8', format: 'der' },
257
+ publicKeyEncoding: { type: 'spki', format: 'der' },
258
+ });
259
+ return {
260
+ privateKey: (pk as Buffer).subarray(16).toString('base64'),
261
+ publicKey: (pub as Buffer).subarray(12).toString('base64'),
262
+ };
263
+ }
264
+ async hash(data: Uint8Array) {
265
+ return 'sha256:' + createHash('sha256').update(data).digest('hex');
266
+ }
267
+ async randomBytes(n: number) { return new Uint8Array(randomBytes(n)); }
268
+ async sign(data: Uint8Array, privateKeyBase64: string) {
269
+ const seed = Buffer.from(privateKeyBase64, 'base64').subarray(0, 32);
270
+ const hdr = Buffer.from([
271
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05,
272
+ 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
273
+ ]);
274
+ const key = createPrivateKey({ key: Buffer.concat([hdr, seed]), format: 'der', type: 'pkcs8' });
275
+ return new Uint8Array(nodeSign(null, data, key));
276
+ }
277
+ async verify(): Promise<boolean> { throw new Error('unused'); }
278
+ }
279
+
280
+ const cryptoProvider = new NodeCryptoProvider();
281
+
282
+ // MemoryIdentityProvider generates a fresh DID + Ed25519 key pair
283
+ const identityProvider = new MemoryIdentityProvider(cryptoProvider);
284
+ const agent = await identityProvider.getIdentity();
285
+
286
+ // ProofGenerator signs tool call request+response pairs with the agent's key
287
+ const generator = new ProofGenerator(agent, cryptoProvider);
288
+
289
+ const request = {
290
+ method: 'tools/call',
291
+ params: { name: 'read_file', arguments: { path: '/etc/hosts' } },
292
+ };
293
+ const response = { data: { content: '127.0.0.1 localhost' } };
294
+
295
+ // SessionContext — in production this comes from SessionManager.validateHandshake()
296
+ const session = {
297
+ sessionId: 'mcpi_demo-session',
298
+ audience: 'did:web:my-mcp-server.example.com',
299
+ nonce: SessionManager.generateNonce(),
300
+ timestamp: Math.floor(Date.now() / 1000),
301
+ createdAt: Math.floor(Date.now() / 1000),
302
+ lastActivity: Math.floor(Date.now() / 1000),
303
+ ttlMinutes: 30,
304
+ identityState: 'anonymous' as const,
305
+ };
306
+
307
+ const proof = await generator.generateProof(request, response, session);
308
+
309
+ console.log('JWS (first 40 chars):', proof.jws.slice(0, 40) + '...');
310
+ // 'eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk...'
311
+ console.log('Request hash:', proof.meta.requestHash);
312
+ // 'sha256:e3b0...'
313
+ console.log('Agent DID:', proof.meta.did);
314
+ // 'did:key:z...'
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Example 4 — MCP Server with Middleware
320
+
321
+ ```typescript
322
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
323
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
324
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
325
+ import { createMCPIMiddleware, CryptoProvider } from '@mcp-i/core';
326
+
327
+ // ... (NodeCryptoProvider as above)
328
+
329
+ const crypto = new NodeCryptoProvider();
330
+ const keys = await crypto.generateKeyPair();
331
+
332
+ const mcpi = createMCPIMiddleware({
333
+ identity: { did: 'did:key:z...', kid: 'did:key:z...#key-1', ...keys },
334
+ session: { sessionTtlMinutes: 60 },
335
+ }, crypto);
336
+
337
+ const echo = mcpi.wrapWithProof('echo', async (args) => ({
338
+ content: [{ type: 'text', text: `Echo: ${args['message']}` }],
339
+ }));
340
+
341
+ const server = new Server({ name: 'my-server', version: '1.0.0' }, { capabilities: { tools: {} } });
342
+
343
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
344
+ tools: [mcpi.handshakeTool, { name: 'echo', inputSchema: { type: 'object' } }],
345
+ }));
346
+
347
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
348
+ if (req.params.name === '_mcpi_handshake') return mcpi.handleHandshake(req.params.arguments ?? {});
349
+ if (req.params.name === 'echo') return echo(req.params.arguments ?? {}, req.params.arguments?.['sessionId']);
350
+ return { content: [{ type: 'text', text: 'Unknown tool' }], isError: true };
351
+ });
352
+
353
+ await server.connect(new StdioServerTransport());
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Example 5 — Verify a Proof with DID:key Resolution
359
+
360
+ ```typescript
361
+ import { ProofVerifier, createDidKeyResolver, CryptoProvider } from '@mcp-i/core';
362
+
363
+ // ... (NodeCryptoProvider with verify + hash)
364
+
365
+ const crypto = new NodeCryptoProvider();
366
+ const didResolver = createDidKeyResolver();
367
+
368
+ const verifier = new ProofVerifier({
369
+ cryptoProvider: crypto,
370
+ fetchPublicKeyFromDID: async (did) => {
371
+ const result = didResolver(did);
372
+ return result?.publicKeyJwk ?? null;
373
+ },
374
+ timestampSkewSeconds: 120,
375
+ });
376
+
377
+ const result = await verifier.verifyProofDetached(proof);
378
+ console.log('Valid:', result.valid);
379
+ ```
380
+
381
+ ---
382
+
383
+ ## License
384
+
385
+ MIT — see [LICENSE](./LICENSE)
386
+
387
+ ---
388
+
389
+ *This package is a DIF TAAWG protocol reference implementation.*
390
+ *Spec: [modelcontextprotocol-identity.io](https://modelcontextprotocol-identity.io)*
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Authorization Handshake — Platform-agnostic Protocol Reference
3
+ *
4
+ * Orchestrates the MCP-I authorization flow:
5
+ * 1. Check agent reputation (optional)
6
+ * 2. Verify delegation exists
7
+ * 3. Return needs_authorization error if missing
8
+ *
9
+ * Uses only the global fetch API — no Node-specific imports.
10
+ * Safe to run on Node.js, Cloudflare Workers, and any fetch-capable runtime.
11
+ */
12
+ import type { NeedsAuthorizationError } from '../types/protocol.js';
13
+ import type { DelegationRecord } from '../types/protocol.js';
14
+ import type { DelegationVerifier, VerifyDelegationResult } from './types.js';
15
+ export type { DelegationVerifier, VerifyDelegationResult };
16
+ export interface AgentReputation {
17
+ agentDid: string;
18
+ score: number;
19
+ totalInteractions: number;
20
+ successRate: number;
21
+ riskLevel: 'low' | 'medium' | 'high' | 'unknown';
22
+ updatedAt: number;
23
+ }
24
+ export interface AuthHandshakeConfig {
25
+ delegationVerifier: DelegationVerifier;
26
+ resumeTokenStore: ResumeTokenStore;
27
+ reputationService?: {
28
+ apiUrl: string;
29
+ apiKey?: string;
30
+ apiFormat?: 'v1' | 'v2';
31
+ };
32
+ authorization: {
33
+ authorizationUrl: string;
34
+ resumeTokenTtl?: number;
35
+ requireAuthForUnknown?: boolean;
36
+ minReputationScore?: number;
37
+ };
38
+ debug?: boolean;
39
+ }
40
+ export interface VerifyOrHintsResult {
41
+ authorized: boolean;
42
+ delegation?: DelegationRecord;
43
+ credential?: {
44
+ agent_did: string;
45
+ user_did: string;
46
+ scopes: string[];
47
+ authorization: {
48
+ type: 'oauth' | 'oauth2' | 'password' | 'credential' | 'webauthn' | 'siwe' | 'none';
49
+ provider?: string;
50
+ credentialType?: string;
51
+ rpId?: string;
52
+ userVerification?: 'required' | 'preferred' | 'discouraged';
53
+ chainId?: number;
54
+ domain?: string;
55
+ };
56
+ [key: string]: unknown;
57
+ };
58
+ authError?: NeedsAuthorizationError;
59
+ reputation?: AgentReputation;
60
+ reason?: string;
61
+ }
62
+ export interface ResumeTokenStore {
63
+ create(agentDid: string, scopes: string[], metadata?: Record<string, unknown>): Promise<string>;
64
+ get(token: string): Promise<{
65
+ agentDid: string;
66
+ scopes: string[];
67
+ createdAt: number;
68
+ expiresAt: number;
69
+ metadata?: Record<string, unknown>;
70
+ } | null>;
71
+ fulfill(token: string): Promise<void>;
72
+ }
73
+ export declare class MemoryResumeTokenStore implements ResumeTokenStore {
74
+ private tokens;
75
+ private ttl;
76
+ constructor(ttlMs?: number);
77
+ create(agentDid: string, scopes: string[], metadata?: Record<string, unknown>): Promise<string>;
78
+ get(token: string): Promise<{
79
+ agentDid: string;
80
+ scopes: string[];
81
+ createdAt: number;
82
+ expiresAt: number;
83
+ metadata?: Record<string, unknown>;
84
+ } | null>;
85
+ fulfill(token: string): Promise<void>;
86
+ clear(): void;
87
+ }
88
+ /**
89
+ * Verify agent delegation or return authorization hints.
90
+ *
91
+ * Orchestrates the authorization flow:
92
+ * 1. Optionally check agent reputation against threshold
93
+ * 2. Verify existing delegation via DelegationVerifier
94
+ * 3. Return authorization hints if delegation is missing/invalid
95
+ *
96
+ * @param agentDid - The agent's DID to verify
97
+ * @param scopes - Required scopes for the operation
98
+ * @param config - Authorization configuration including verifier, token store, etc.
99
+ * @param _resumeToken - Optional resume token from previous authorization attempt
100
+ * @returns Result indicating authorization status, delegation, or auth hints
101
+ */
102
+ export declare function verifyOrHints(agentDid: string, scopes: string[], config: AuthHandshakeConfig, _resumeToken?: string): Promise<VerifyOrHintsResult>;
103
+ export declare function hasSensitiveScopes(scopes: string[]): boolean;
104
+ //# sourceMappingURL=handshake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/auth/handshake.ts"],"names":[],"mappings":"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"}