@kya-os/mcp-i 1.6.2-canary.0 → 1.6.3-canary.clientinfo.20251126124133

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.
@@ -9,12 +9,12 @@ const auth_handshake_1 = require("../auth-handshake");
9
9
  const session_1 = require("../session");
10
10
  const request_context_1 = require("../request-context");
11
11
  const proof_batch_queue_1 = require("../proof-batch-queue");
12
- // Parse runtime config path from injected variable
13
- // @ts-expect-error: injected by compiler
14
12
  const rawRuntimeConfigPath = typeof RUNTIME_CONFIG_PATH !== "undefined" ? RUNTIME_CONFIG_PATH : undefined;
15
13
  // Single-parse to match single-stringify from webpack DefinePlugin
16
14
  const runtimeConfigPath = rawRuntimeConfigPath
17
- ? (typeof rawRuntimeConfigPath === 'string' ? JSON.parse(rawRuntimeConfigPath) : rawRuntimeConfigPath)
15
+ ? typeof rawRuntimeConfigPath === "string"
16
+ ? JSON.parse(rawRuntimeConfigPath)
17
+ : rawRuntimeConfigPath
18
18
  : null;
19
19
  /** Validates if a value is a valid Zod schema object */
20
20
  function isZodRawShape(value) {
@@ -68,7 +68,8 @@ async function initializeProofBatchQueue(debug) {
68
68
  return null;
69
69
  }
70
70
  const proofingConfig = runtimeConfig.proofing;
71
- if (!proofingConfig.batchQueue?.destinations || proofingConfig.batchQueue.destinations.length === 0) {
71
+ if (!proofingConfig.batchQueue?.destinations ||
72
+ proofingConfig.batchQueue.destinations.length === 0) {
72
73
  if (debug) {
73
74
  console.error("[MCPI] No proof destinations configured");
74
75
  }
@@ -113,14 +114,15 @@ async function initializeProofBatchQueue(debug) {
113
114
  return null;
114
115
  }
115
116
  }
116
- if (typeof global !== 'undefined') {
117
- global.__MCPI_HANDLERS_REGISTERED__ = global.__MCPI_HANDLERS_REGISTERED__ || false;
117
+ if (typeof global !== "undefined") {
118
+ global.__MCPI_HANDLERS_REGISTERED__ =
119
+ global.__MCPI_HANDLERS_REGISTERED__ || false;
118
120
  }
119
121
  /** Loads tools and injects them into the server */
120
122
  async function addToolsToServer(server, toolModules, identityConfig) {
121
123
  // Guard against double registration using global scope
122
124
  // Set this IMMEDIATELY to prevent race conditions
123
- if (typeof global !== 'undefined') {
125
+ if (typeof global !== "undefined") {
124
126
  if (global.__MCPI_HANDLERS_REGISTERED__) {
125
127
  if (identityConfig?.debug) {
126
128
  console.error("[MCPI] Handlers already registered, skipping duplicate registration");
@@ -149,7 +151,7 @@ async function addToolsToServer(server, toolModules, identityConfig) {
149
151
  const identity = await identityManager.ensureIdentity();
150
152
  if (identityConfig.debug) {
151
153
  console.error(`[MCPI] Identity enabled - DID: ${identity.did}`);
152
- console.error(`[MCPI] Identity path: ${identityConfig.devIdentityPath || '.mcpi/identity.json'}`);
154
+ console.error(`[MCPI] Identity path: ${identityConfig.devIdentityPath || ".mcpi/identity.json"}`);
153
155
  }
154
156
  }
155
157
  catch (error) {
@@ -157,6 +159,8 @@ async function addToolsToServer(server, toolModules, identityConfig) {
157
159
  console.error("[MCPI] Failed to initialize identity:", error);
158
160
  }
159
161
  // Continue without identity if initialization fails
162
+ // Set identityManager to null to prevent later unhandled calls to ensureIdentity()
163
+ identityManager = null;
160
164
  }
161
165
  }
162
166
  // Initialize ProofBatchQueue for proof submission (if runtime config exists)
@@ -206,12 +210,180 @@ async function addToolsToServer(server, toolModules, identityConfig) {
206
210
  });
207
211
  // Debug: log server state before registering handler
208
212
  if (identityConfig?.debug) {
209
- console.error("[MCPI] About to register handlers (tools/list, tools/call)");
213
+ console.error("[MCPI] About to register handlers (tools/list, tools/call, handshake)");
210
214
  }
211
- // NOTE: Custom handshake handler removed - it was causing registration errors
212
- // Handshake/session management should be handled via HTTP headers or custom tools
213
- // The setRequestHandler expects a Zod schema, not a request object
214
- // TODO: Implement handshake as a custom tool if needed
215
+ // Set server DID on session manager after identity is loaded
216
+ if (identityManager) {
217
+ try {
218
+ const identity = await identityManager.ensureIdentity();
219
+ sessionManager.setServerDid(identity.did);
220
+ }
221
+ catch (error) {
222
+ // If identity initialization failed earlier, ensureIdentity() may throw again
223
+ // Log but don't crash - server can operate without identity
224
+ if (identityConfig?.debug) {
225
+ console.error("[MCPI] Failed to set server DID on session manager:", error);
226
+ }
227
+ // Set to null to prevent future attempts
228
+ identityManager = null;
229
+ }
230
+ }
231
+ // Add internal handshake tool for MCP-I session establishment
232
+ // This allows MCP clients to perform a handshake and receive a sessionId
233
+ const handshakeTool = {
234
+ name: "_mcpi_handshake",
235
+ description: "Internal MCP-I handshake tool for session establishment. Clients should call this before protected tools.",
236
+ inputSchema: {
237
+ type: "object",
238
+ properties: {
239
+ nonce: {
240
+ type: "string",
241
+ description: "Unique nonce for replay prevention",
242
+ },
243
+ audience: {
244
+ type: "string",
245
+ description: "Target audience (server DID or URL)",
246
+ },
247
+ timestamp: { type: "number", description: "Unix timestamp in seconds" },
248
+ agentDid: {
249
+ type: "string",
250
+ description: "Agent DID for delegation verification (optional)",
251
+ },
252
+ clientInfo: {
253
+ type: "object",
254
+ description: "MCP client metadata (optional)",
255
+ properties: {
256
+ name: { type: "string" },
257
+ version: { type: "string" },
258
+ platform: { type: "string" },
259
+ vendor: { type: "string" },
260
+ },
261
+ },
262
+ clientProtocolVersion: {
263
+ type: "string",
264
+ description: "MCP protocol version (optional)",
265
+ },
266
+ clientCapabilities: {
267
+ type: "object",
268
+ description: "MCP client capabilities (optional)",
269
+ additionalProperties: true,
270
+ },
271
+ },
272
+ required: ["nonce", "audience", "timestamp"],
273
+ },
274
+ };
275
+ tools.push(handshakeTool);
276
+ // Handshake tool handler
277
+ toolHandlers.set("_mcpi_handshake", async (args) => {
278
+ // Validate required fields explicitly before conversion
279
+ const missingFields = [];
280
+ if (!args.nonce ||
281
+ (typeof args.nonce === "string" && args.nonce.trim().length === 0)) {
282
+ missingFields.push("nonce");
283
+ }
284
+ if (!args.audience ||
285
+ (typeof args.audience === "string" && args.audience.trim().length === 0)) {
286
+ missingFields.push("audience");
287
+ }
288
+ // Validate timestamp is present and valid
289
+ if (args.timestamp === undefined ||
290
+ args.timestamp === null ||
291
+ typeof args.timestamp !== "number" ||
292
+ args.timestamp <= 0 ||
293
+ !Number.isInteger(args.timestamp)) {
294
+ if (args.timestamp === undefined || args.timestamp === null) {
295
+ missingFields.push("timestamp");
296
+ }
297
+ else {
298
+ // Invalid format (not a positive integer)
299
+ return {
300
+ success: false,
301
+ error: {
302
+ code: "XMCP_I_EHANDSHAKE",
303
+ message: "Invalid timestamp: must be a positive integer (Unix timestamp in seconds)",
304
+ details: {
305
+ received: typeof args.timestamp,
306
+ value: args.timestamp,
307
+ },
308
+ },
309
+ };
310
+ }
311
+ }
312
+ if (missingFields.length > 0) {
313
+ return {
314
+ success: false,
315
+ error: {
316
+ code: "XMCP_I_EHANDSHAKE",
317
+ message: `Missing required field(s): ${missingFields.join(", ")}`,
318
+ details: {
319
+ missingFields,
320
+ requiredFields: ["nonce", "audience", "timestamp"],
321
+ },
322
+ },
323
+ };
324
+ }
325
+ // At this point, timestamp is guaranteed to be a valid positive integer
326
+ const timestamp = args.timestamp;
327
+ // Build handshake request from validated tool arguments
328
+ const handshakeRequest = {
329
+ nonce: String(args.nonce).trim(),
330
+ audience: String(args.audience).trim(),
331
+ timestamp,
332
+ agentDid: typeof args.agentDid === "string" && args.agentDid.trim().length > 0
333
+ ? args.agentDid.trim()
334
+ : undefined,
335
+ clientInfo: typeof args.clientInfo === "object" && args.clientInfo !== null
336
+ ? args.clientInfo
337
+ : undefined,
338
+ clientProtocolVersion: typeof args.clientProtocolVersion === "string" &&
339
+ args.clientProtocolVersion.trim().length > 0
340
+ ? args.clientProtocolVersion.trim()
341
+ : undefined,
342
+ clientCapabilities: typeof args.clientCapabilities === "object" &&
343
+ args.clientCapabilities !== null
344
+ ? args.clientCapabilities
345
+ : undefined,
346
+ };
347
+ // Double-check format (should always pass at this point, but defensive)
348
+ if (!(0, session_1.validateHandshakeFormat)(handshakeRequest)) {
349
+ return {
350
+ success: false,
351
+ error: {
352
+ code: "XMCP_I_EHANDSHAKE",
353
+ message: "Invalid handshake request format. Required: nonce, audience, timestamp",
354
+ },
355
+ };
356
+ }
357
+ // Validate handshake and create session
358
+ const result = await sessionManager.validateHandshake(handshakeRequest);
359
+ // Log clientInfo in development mode
360
+ if (identityConfig?.debug &&
361
+ result.success &&
362
+ result.session?.clientInfo) {
363
+ console.error("[MCPI] Client connected:", {
364
+ name: result.session.clientInfo.name,
365
+ version: result.session.clientInfo.version,
366
+ platform: result.session.clientInfo.platform,
367
+ vendor: result.session.clientInfo.vendor,
368
+ clientId: result.session.clientInfo.clientId,
369
+ });
370
+ }
371
+ if (result.success && result.session) {
372
+ return {
373
+ success: true,
374
+ sessionId: result.session.sessionId,
375
+ serverDid: result.session.serverDid,
376
+ ttlMinutes: result.session.ttlMinutes,
377
+ ...(result.session.clientInfo && {
378
+ clientInfo: result.session.clientInfo,
379
+ }),
380
+ };
381
+ }
382
+ return {
383
+ success: false,
384
+ error: result.error,
385
+ };
386
+ });
215
387
  // Register tools/list handler
216
388
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async (request) => {
217
389
  return {
@@ -297,7 +469,7 @@ async function addToolsToServer(server, toolModules, identityConfig) {
297
469
  ` "agentDid": "did:key:z6Mk...",\n` +
298
470
  ` "nonce": "unique-value",\n` +
299
471
  ` "audience": "server-did",\n` +
300
- ` "timestamp": ${Date.now()}\n` +
472
+ ` "timestamp": ${Math.floor(Date.now() / 1000)}\n` +
301
473
  ` }\n\n` +
302
474
  `2. **Handshake missing agentDid**: Ensure the handshake request includes the 'agentDid' field.\n\n` +
303
475
  `3. **Session expired**: The session may have expired. Try performing a new handshake.\n\n` +
@@ -309,7 +481,7 @@ async function addToolsToServer(server, toolModules, identityConfig) {
309
481
  };
310
482
  }
311
483
  if (identityConfig?.debug) {
312
- console.error(`[MCPI] Tool "${name}" requires delegation - verifying scopes: ${toolProtection.requiredScopes?.join(', ')}`);
484
+ console.error(`[MCPI] Tool "${name}" requires delegation - verifying scopes: ${toolProtection.requiredScopes?.join(", ")}`);
313
485
  }
314
486
  // Verify delegation
315
487
  const verifyResult = await (0, auth_handshake_1.verifyOrHints)(agentDid, toolProtection.requiredScopes || [], authConfig);
@@ -348,7 +520,9 @@ async function addToolsToServer(server, toolModules, identityConfig) {
348
520
  content: [
349
521
  {
350
522
  type: "text",
351
- text: typeof result === "string" ? result : JSON.stringify(result),
523
+ text: typeof result === "string"
524
+ ? result
525
+ : JSON.stringify(result),
352
526
  },
353
527
  ],
354
528
  };
@@ -365,11 +539,9 @@ async function addToolsToServer(server, toolModules, identityConfig) {
365
539
  const toolResponse = {
366
540
  data: result,
367
541
  };
368
- // Create a session context for standalone tool calls
369
- // In a full implementation, this would use proper handshake
370
- // TODO: Use proper handshake
542
+ // Reuse the active session if available, otherwise synthesize one
371
543
  const timestamp = Math.floor(Date.now() / 1000);
372
- const session = {
544
+ const proofSession = session ?? {
373
545
  sessionId: `tool-${Date.now()}`,
374
546
  nonce: `${Date.now()}`,
375
547
  audience: "client",
@@ -382,7 +554,8 @@ async function addToolsToServer(server, toolModules, identityConfig) {
382
554
  // This enables AgentShield tool auto-discovery
383
555
  let scopeId;
384
556
  const toolProtection = tool_protection_registry_1.toolProtectionRegistry.get(name);
385
- if (toolProtection?.requiredScopes && toolProtection.requiredScopes.length > 0) {
557
+ if (toolProtection?.requiredScopes &&
558
+ toolProtection.requiredScopes.length > 0) {
386
559
  // Use the first required scope as the scopeId (e.g., "files:read")
387
560
  scopeId = toolProtection.requiredScopes[0];
388
561
  }
@@ -395,9 +568,9 @@ async function addToolsToServer(server, toolModules, identityConfig) {
395
568
  }
396
569
  // Generate proof using the proof generator with scopeId
397
570
  const proofGen = new proof_1.ProofGenerator(identity);
398
- const proof = await proofGen.generateProof(toolRequest, toolResponse, session, {
571
+ const proof = await proofGen.generateProof(toolRequest, toolResponse, proofSession, {
399
572
  scopeId, // Pass scopeId for tool auto-discovery
400
- clientDid: session?.clientDid, // Pass clientDid if available
573
+ clientDid: session?.clientDid,
401
574
  });
402
575
  if (identityConfig?.debug) {
403
576
  console.error(`[MCPI] Generated proof for tool "${name}" - DID: ${proof.meta.did}`);
package/package.json CHANGED
@@ -1,45 +1,45 @@
1
1
  {
2
2
  "name": "@kya-os/mcp-i",
3
- "version": "1.6.2-canary.0",
3
+ "version": "1.6.3-canary.clientinfo.20251126124133",
4
4
  "description": "The TypeScript MCP framework with identity features built-in",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./dist/index.d.ts",
10
11
  "require": "./dist/index.js",
11
- "import": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
12
+ "import": "./dist/index.js"
13
13
  },
14
14
  "./platforms": {
15
+ "types": "./dist/identity/platforms.d.ts",
15
16
  "require": "./dist/identity/platforms.js",
16
- "import": "./dist/identity/platforms.js",
17
- "types": "./dist/identity/platforms.d.ts"
17
+ "import": "./dist/identity/platforms.js"
18
18
  },
19
19
  "./test": {
20
+ "types": "./dist/test/index.d.ts",
20
21
  "require": "./dist/test/index.js",
21
- "import": "./dist/test/index.js",
22
- "types": "./dist/test/index.d.ts"
22
+ "import": "./dist/test/index.js"
23
23
  },
24
24
  "./headers": {
25
+ "types": "./dist/runtime/headers.d.ts",
25
26
  "require": "./dist/runtime/headers.js",
26
- "import": "./dist/runtime/headers.js",
27
- "types": "./dist/runtime/headers.d.ts"
27
+ "import": "./dist/runtime/headers.js"
28
28
  },
29
29
  "./cli-internal": {
30
+ "types": "./dist/cli-adapter/index.d.ts",
30
31
  "require": "./dist/cli-adapter/index.js",
31
- "import": "./dist/cli-adapter/index.js",
32
- "types": "./dist/cli-adapter/index.d.ts"
32
+ "import": "./dist/cli-adapter/index.js"
33
33
  },
34
34
  "./config": {
35
+ "types": "./dist/config.d.ts",
35
36
  "require": "./dist/config.js",
36
- "import": "./dist/config.js",
37
- "types": "./dist/config.d.ts"
37
+ "import": "./dist/config.js"
38
38
  },
39
39
  "./runtime": {
40
+ "types": "./dist/runtime/index.d.ts",
40
41
  "require": "./dist/runtime/index.js",
41
- "import": "./dist/runtime/index.js",
42
- "types": "./dist/runtime/index.d.ts"
42
+ "import": "./dist/runtime/index.js"
43
43
  }
44
44
  },
45
45
  "files": [
@@ -63,8 +63,8 @@
63
63
  "model-context-protocol"
64
64
  ],
65
65
  "dependencies": {
66
- "@kya-os/contracts": "^1.6.2-canary.0",
67
- "@kya-os/mcp-i-core": "^1.3.7-canary.0",
66
+ "@kya-os/contracts": "^1.6.1",
67
+ "@kya-os/mcp-i-core": "^1.3.1",
68
68
  "@modelcontextprotocol/sdk": "^1.11.4",
69
69
  "@swc/core": "^1.11.24",
70
70
  "@types/express": "^5.0.1",
@@ -74,18 +74,17 @@
74
74
  "base-x": "^5.0.1",
75
75
  "chalk": "^5.2.0",
76
76
  "chokidar": "^3.6.0",
77
- "clean-webpack-plugin": "^4.0.0",
78
77
  "commander": "^10.0.0",
79
78
  "content-type": "^1.0.5",
80
79
  "cross-env": "^7.0.3",
81
- "del": "^7.0.0",
80
+ "del": "^8.0.1",
82
81
  "dotenv": "^16.5.0",
83
82
  "esbuild": "^0.25.0",
84
83
  "execa": "^9.6.0",
85
84
  "express": "^4.18.0",
86
85
  "fork-ts-checker-webpack-plugin": "^8.0.0",
87
86
  "fs-extra": "^11.3.0",
88
- "glob": "^11.0.2",
87
+ "glob": "^11.1.0",
89
88
  "handlebars": "^4.7.7",
90
89
  "jose": "^5.2.0",
91
90
  "json-canonicalize": "^2.0.0",