@mcp-i/core 0.1.0 → 1.1.0-canary.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/README.md +43 -20
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.d.ts +5 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +5 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/with-mcpi-server.d.ts +62 -0
- package/dist/middleware/with-mcpi-server.d.ts.map +1 -0
- package/dist/middleware/with-mcpi-server.js +94 -0
- package/dist/middleware/with-mcpi-server.js.map +1 -0
- package/dist/middleware/with-mcpi.d.ts +25 -10
- package/dist/middleware/with-mcpi.d.ts.map +1 -1
- package/dist/middleware/with-mcpi.js +21 -7
- package/dist/middleware/with-mcpi.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/node-crypto.d.ts +26 -0
- package/dist/providers/node-crypto.d.ts.map +1 -0
- package/dist/providers/node-crypto.js +69 -0
- package/dist/providers/node-crypto.js.map +1 -0
- package/package.json +8 -3
- package/src/__tests__/integration/mcp-enhance-server.test.ts +311 -0
- package/src/__tests__/integration/mcp-transport-context7.test.ts +413 -0
- package/src/__tests__/integration/mcp-transport.test.ts +390 -0
- package/src/index.ts +5 -0
- package/src/middleware/index.ts +10 -1
- package/src/middleware/with-mcpi-server.ts +185 -0
- package/src/middleware/with-mcpi.ts +35 -13
- package/src/providers/index.ts +2 -0
- package/src/providers/node-crypto.ts +107 -0
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP-I Middleware
|
|
2
|
+
* MCP-I Middleware — Core Implementation
|
|
3
3
|
*
|
|
4
|
-
* Adds identity, session management, and proof generation to
|
|
5
|
-
* MCP SDK Server.
|
|
4
|
+
* Adds identity, session management, and proof generation to MCP servers.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* For most use cases, prefer the high-level `withMCPI()` adapter from
|
|
7
|
+
* `./with-mcpi-server.ts` which auto-registers the handshake tool and
|
|
8
|
+
* auto-attaches proofs to all tool responses:
|
|
9
|
+
*
|
|
10
|
+
* import { withMCPI } from '@mcp-i/core';
|
|
11
|
+
* await withMCPI(server, { crypto: new NodeCryptoProvider() });
|
|
12
|
+
*
|
|
13
|
+
* `createMCPIMiddleware()` in this file is the lower-level API used
|
|
14
|
+
* internally by `withMCPI()` and for advanced use cases like the
|
|
15
|
+
* low-level `Server` API or custom request handler patterns.
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
18
|
import {
|
|
@@ -115,9 +120,11 @@ export interface MCPIToolDefinition {
|
|
|
115
120
|
};
|
|
116
121
|
}
|
|
117
122
|
|
|
118
|
-
export interface MCPIToolHandler
|
|
123
|
+
export interface MCPIToolHandler<
|
|
124
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
125
|
+
> {
|
|
119
126
|
(
|
|
120
|
-
args:
|
|
127
|
+
args: T,
|
|
121
128
|
sessionId?: string,
|
|
122
129
|
): Promise<{
|
|
123
130
|
content: Array<{ type: string; text: string; [key: string]: unknown }>;
|
|
@@ -138,6 +145,9 @@ export interface MCPIServer {
|
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
export interface MCPIMiddleware {
|
|
148
|
+
/** The identity config used by this middleware instance */
|
|
149
|
+
identity: MCPIIdentityConfig;
|
|
150
|
+
|
|
141
151
|
/** The SessionManager instance for manual session operations */
|
|
142
152
|
sessionManager: SessionManager;
|
|
143
153
|
|
|
@@ -163,7 +173,10 @@ export interface MCPIMiddleware {
|
|
|
163
173
|
* Wrap a tool handler to automatically generate proofs.
|
|
164
174
|
* Returns a new handler that appends proof metadata to the response.
|
|
165
175
|
*/
|
|
166
|
-
wrapWithProof
|
|
176
|
+
wrapWithProof<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
177
|
+
toolName: string,
|
|
178
|
+
handler: MCPIToolHandler<T>,
|
|
179
|
+
): MCPIToolHandler;
|
|
167
180
|
|
|
168
181
|
/**
|
|
169
182
|
* Wrap a tool handler to require a valid W3C Delegation Credential.
|
|
@@ -253,6 +266,14 @@ function validateScopeAttenuation(
|
|
|
253
266
|
/**
|
|
254
267
|
* Create MCP-I middleware for a standard MCP SDK Server.
|
|
255
268
|
*
|
|
269
|
+
* For most use cases, prefer {@link withMCPI} from `./with-mcpi-server.ts`
|
|
270
|
+
* which wraps this function and auto-registers handshake + auto-attaches proofs.
|
|
271
|
+
*
|
|
272
|
+
* Use `createMCPIMiddleware` directly when:
|
|
273
|
+
* - You use the low-level `Server` API (not `McpServer`)
|
|
274
|
+
* - You need custom request handler patterns
|
|
275
|
+
* - You want per-tool control over proof/delegation wrapping
|
|
276
|
+
*
|
|
256
277
|
* @param config - Agent identity and session configuration
|
|
257
278
|
* @param cryptoProvider - Platform-specific crypto implementation
|
|
258
279
|
* @returns Middleware components for session management and proof generation
|
|
@@ -394,12 +415,12 @@ export function createMCPIMiddleware(
|
|
|
394
415
|
return undefined;
|
|
395
416
|
}
|
|
396
417
|
|
|
397
|
-
function wrapWithProof(
|
|
418
|
+
function wrapWithProof<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
398
419
|
toolName: string,
|
|
399
|
-
handler: MCPIToolHandler
|
|
420
|
+
handler: MCPIToolHandler<T>,
|
|
400
421
|
): MCPIToolHandler {
|
|
401
422
|
return async (args: Record<string, unknown>, sessionId?: string) => {
|
|
402
|
-
const result = await handler(args, sessionId);
|
|
423
|
+
const result = await handler(args as T, sessionId);
|
|
403
424
|
|
|
404
425
|
if (result.isError) {
|
|
405
426
|
return result;
|
|
@@ -756,6 +777,7 @@ export function createMCPIMiddleware(
|
|
|
756
777
|
}
|
|
757
778
|
|
|
758
779
|
return {
|
|
780
|
+
identity: config.identity,
|
|
759
781
|
sessionManager,
|
|
760
782
|
proofGenerator,
|
|
761
783
|
handshakeTool,
|
package/src/providers/index.ts
CHANGED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js CryptoProvider
|
|
3
|
+
*
|
|
4
|
+
* Ed25519 crypto backed by Node.js built-in `node:crypto`.
|
|
5
|
+
* Use this on any Node.js 20+ server.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { NodeCryptoProvider } from '@mcp-i/core/providers';
|
|
10
|
+
* import { withMCPI } from '@mcp-i/core/middleware';
|
|
11
|
+
*
|
|
12
|
+
* await withMCPI(server, { crypto: new NodeCryptoProvider() });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
createHash,
|
|
18
|
+
createPrivateKey,
|
|
19
|
+
createPublicKey,
|
|
20
|
+
generateKeyPairSync,
|
|
21
|
+
sign,
|
|
22
|
+
verify,
|
|
23
|
+
randomBytes,
|
|
24
|
+
} from "node:crypto";
|
|
25
|
+
import { CryptoProvider } from "./base.js";
|
|
26
|
+
|
|
27
|
+
/** PKCS8 DER header for Ed25519 private keys (16 bytes) */
|
|
28
|
+
const ED25519_PKCS8_PREFIX = Buffer.from(
|
|
29
|
+
"302e020100300506032b657004220420",
|
|
30
|
+
"hex",
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
/** SPKI DER header for Ed25519 public keys (12 bytes) */
|
|
34
|
+
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
35
|
+
|
|
36
|
+
export class NodeCryptoProvider extends CryptoProvider {
|
|
37
|
+
async sign(
|
|
38
|
+
data: Uint8Array,
|
|
39
|
+
privateKeyBase64: string,
|
|
40
|
+
): Promise<Uint8Array> {
|
|
41
|
+
const privateKey = Buffer.from(privateKeyBase64, "base64");
|
|
42
|
+
|
|
43
|
+
// Handle both raw 32-byte and full 64-byte Ed25519 keys
|
|
44
|
+
const keyBytes =
|
|
45
|
+
privateKey.length === 64 ? privateKey.subarray(0, 32) : privateKey;
|
|
46
|
+
|
|
47
|
+
const keyObject = createPrivateKey({
|
|
48
|
+
key: Buffer.concat([ED25519_PKCS8_PREFIX, keyBytes]),
|
|
49
|
+
format: "der",
|
|
50
|
+
type: "pkcs8",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return new Uint8Array(sign(null, Buffer.from(data), keyObject));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async verify(
|
|
57
|
+
data: Uint8Array,
|
|
58
|
+
signature: Uint8Array,
|
|
59
|
+
publicKeyBase64: string,
|
|
60
|
+
): Promise<boolean> {
|
|
61
|
+
try {
|
|
62
|
+
const keyObject = createPublicKey({
|
|
63
|
+
key: Buffer.concat([
|
|
64
|
+
ED25519_SPKI_PREFIX,
|
|
65
|
+
Buffer.from(publicKeyBase64, "base64"),
|
|
66
|
+
]),
|
|
67
|
+
format: "der",
|
|
68
|
+
type: "spki",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return verify(
|
|
72
|
+
null,
|
|
73
|
+
Buffer.from(data),
|
|
74
|
+
keyObject,
|
|
75
|
+
Buffer.from(signature),
|
|
76
|
+
);
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async generateKeyPair(): Promise<{
|
|
83
|
+
privateKey: string;
|
|
84
|
+
publicKey: string;
|
|
85
|
+
}> {
|
|
86
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
87
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
88
|
+
privateKeyEncoding: { type: "pkcs8", format: "der" },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
privateKey: (privateKey as Buffer).subarray(16, 48).toString("base64"),
|
|
93
|
+
publicKey: (publicKey as Buffer).subarray(12, 44).toString("base64"),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async hash(data: Uint8Array): Promise<string> {
|
|
98
|
+
const hex = createHash("sha256")
|
|
99
|
+
.update(Buffer.from(data))
|
|
100
|
+
.digest("hex");
|
|
101
|
+
return `sha256:${hex}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async randomBytes(length: number): Promise<Uint8Array> {
|
|
105
|
+
return new Uint8Array(randomBytes(length));
|
|
106
|
+
}
|
|
107
|
+
}
|