@kya-os/mcp-i 0.1.0-alpha.2.3 → 0.1.0-alpha.2.5

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 (58) hide show
  1. package/README.md +192 -216
  2. package/dist/auto.d.ts +0 -12
  3. package/dist/auto.js +3 -14
  4. package/dist/crypto.d.ts +10 -26
  5. package/dist/crypto.js +117 -37
  6. package/dist/dev-helper.d.ts +3 -0
  7. package/dist/dev-helper.js +46 -0
  8. package/dist/encrypted-storage.d.ts +11 -0
  9. package/dist/encrypted-storage.js +73 -0
  10. package/dist/index.d.ts +29 -106
  11. package/dist/index.js +225 -392
  12. package/dist/logger.d.ts +32 -0
  13. package/dist/logger.js +66 -0
  14. package/dist/registry/index.d.ts +0 -31
  15. package/dist/registry/index.js +2 -42
  16. package/dist/registry/knowthat.d.ts +3 -18
  17. package/dist/registry/knowthat.js +10 -35
  18. package/dist/rotation.d.ts +35 -0
  19. package/dist/rotation.js +102 -0
  20. package/dist/storage.d.ts +41 -0
  21. package/dist/storage.js +163 -0
  22. package/dist/transport.d.ts +35 -0
  23. package/dist/transport.js +189 -0
  24. package/dist/types.d.ts +72 -99
  25. package/dist/types.js +0 -4
  26. package/package.json +16 -6
  27. package/dist/__tests__/challenge-response.test.d.ts +0 -5
  28. package/dist/__tests__/challenge-response.test.d.ts.map +0 -1
  29. package/dist/__tests__/challenge-response.test.js +0 -218
  30. package/dist/__tests__/challenge-response.test.js.map +0 -1
  31. package/dist/__tests__/crypto.test.d.ts +0 -5
  32. package/dist/__tests__/crypto.test.d.ts.map +0 -1
  33. package/dist/__tests__/crypto.test.js +0 -153
  34. package/dist/__tests__/crypto.test.js.map +0 -1
  35. package/dist/auto.d.ts.map +0 -1
  36. package/dist/auto.js.map +0 -1
  37. package/dist/crypto.d.ts.map +0 -1
  38. package/dist/crypto.js.map +0 -1
  39. package/dist/index.d.ts.map +0 -1
  40. package/dist/index.js.map +0 -1
  41. package/dist/registry/cursor.d.ts +0 -25
  42. package/dist/registry/cursor.d.ts.map +0 -1
  43. package/dist/registry/cursor.js +0 -108
  44. package/dist/registry/cursor.js.map +0 -1
  45. package/dist/registry/glama.d.ts +0 -25
  46. package/dist/registry/glama.d.ts.map +0 -1
  47. package/dist/registry/glama.js +0 -111
  48. package/dist/registry/glama.js.map +0 -1
  49. package/dist/registry/index.d.ts.map +0 -1
  50. package/dist/registry/index.js.map +0 -1
  51. package/dist/registry/knowthat.d.ts.map +0 -1
  52. package/dist/registry/knowthat.js.map +0 -1
  53. package/dist/registry/smithery.d.ts +0 -29
  54. package/dist/registry/smithery.d.ts.map +0 -1
  55. package/dist/registry/smithery.js +0 -119
  56. package/dist/registry/smithery.js.map +0 -1
  57. package/dist/types.d.ts.map +0 -1
  58. package/dist/types.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,27 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * @kya-os/mcp-i - Ultra-light MCP Identity auto-registration
4
- *
5
- * Enable any MCP server to get a verifiable identity with just 2 lines of code:
6
- *
7
- * ```typescript
8
- * import "@kya-os/mcp-i/auto"; // That's it! Your server now has identity
9
- * ```
10
- *
11
- * Or with configuration:
12
- * ```typescript
13
- * import { enableMCPIdentity } from "@kya-os/mcp-i";
14
- * await enableMCPIdentity({ name: "My Amazing Agent" });
15
- * ```
16
- *
17
- * Future multi-registry support:
18
- * ```typescript
19
- * await enableMCPIdentity({
20
- * name: "My Agent",
21
- * // Additional registries will be supported as directories adopt MCP-I
22
- * });
23
- * ```
24
- */
25
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
3
  if (k2 === undefined) k2 = k;
27
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -58,123 +35,113 @@ var __importStar = (this && this.__importStar) || (function () {
58
35
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
59
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
60
37
  };
61
- var __importDefault = (this && this.__importDefault) || function (mod) {
62
- return (mod && mod.__esModule) ? mod : { "default": mod };
63
- };
64
38
  Object.defineProperty(exports, "__esModule", { value: true });
65
- exports.MCPIdentity = exports.resolveRegistries = exports.REGISTRY_TIERS = exports.RegistryFactory = void 0;
39
+ exports.MCPIdentity = exports.showAgentStatus = exports.initWithDevExperience = exports.KeyRotationManager = exports.RuntimeDetector = exports.TransportFactory = exports.FileStorage = exports.MemoryStorage = exports.StorageFactory = exports.SilentLogger = exports.ConsoleLogger = exports.LoggerFactory = exports.resolveRegistries = exports.REGISTRY_TIERS = exports.RegistryFactory = void 0;
66
40
  exports.enableMCPIdentity = enableMCPIdentity;
67
- const axios_1 = __importDefault(require("axios"));
68
- const fs = __importStar(require("fs"));
69
- const path = __importStar(require("path"));
41
+ exports.createMCPMiddleware = createMCPMiddleware;
70
42
  const crypto = __importStar(require("./crypto"));
71
- const registry_1 = require("./registry");
72
- // Re-export types and registry utilities for convenience
43
+ const storage_1 = require("./storage");
44
+ const transport_1 = require("./transport");
45
+ const logger_1 = require("./logger");
46
+ const rotation_1 = require("./rotation");
73
47
  __exportStar(require("./types"), exports);
74
- var registry_2 = require("./registry");
75
- Object.defineProperty(exports, "RegistryFactory", { enumerable: true, get: function () { return registry_2.RegistryFactory; } });
76
- Object.defineProperty(exports, "REGISTRY_TIERS", { enumerable: true, get: function () { return registry_2.REGISTRY_TIERS; } });
77
- Object.defineProperty(exports, "resolveRegistries", { enumerable: true, get: function () { return registry_2.resolveRegistries; } });
78
- // Global identity instance
48
+ var registry_1 = require("./registry");
49
+ Object.defineProperty(exports, "RegistryFactory", { enumerable: true, get: function () { return registry_1.RegistryFactory; } });
50
+ Object.defineProperty(exports, "REGISTRY_TIERS", { enumerable: true, get: function () { return registry_1.REGISTRY_TIERS; } });
51
+ Object.defineProperty(exports, "resolveRegistries", { enumerable: true, get: function () { return registry_1.resolveRegistries; } });
52
+ var logger_2 = require("./logger");
53
+ Object.defineProperty(exports, "LoggerFactory", { enumerable: true, get: function () { return logger_2.LoggerFactory; } });
54
+ Object.defineProperty(exports, "ConsoleLogger", { enumerable: true, get: function () { return logger_2.ConsoleLogger; } });
55
+ Object.defineProperty(exports, "SilentLogger", { enumerable: true, get: function () { return logger_2.SilentLogger; } });
56
+ var storage_2 = require("./storage");
57
+ Object.defineProperty(exports, "StorageFactory", { enumerable: true, get: function () { return storage_2.StorageFactory; } });
58
+ Object.defineProperty(exports, "MemoryStorage", { enumerable: true, get: function () { return storage_2.MemoryStorage; } });
59
+ Object.defineProperty(exports, "FileStorage", { enumerable: true, get: function () { return storage_2.FileStorage; } });
60
+ var transport_2 = require("./transport");
61
+ Object.defineProperty(exports, "TransportFactory", { enumerable: true, get: function () { return transport_2.TransportFactory; } });
62
+ Object.defineProperty(exports, "RuntimeDetector", { enumerable: true, get: function () { return transport_2.RuntimeDetector; } });
63
+ var rotation_2 = require("./rotation");
64
+ Object.defineProperty(exports, "KeyRotationManager", { enumerable: true, get: function () { return rotation_2.KeyRotationManager; } });
65
+ var dev_helper_1 = require("./dev-helper");
66
+ Object.defineProperty(exports, "initWithDevExperience", { enumerable: true, get: function () { return dev_helper_1.initWithDevExperience; } });
67
+ Object.defineProperty(exports, "showAgentStatus", { enumerable: true, get: function () { return dev_helper_1.showAgentStatus; } });
79
68
  let globalIdentity = null;
80
69
  class MCPIdentity {
81
70
  constructor(identity, options = {}) {
82
71
  this.usedNonces = new Set();
83
- this.registryAdapters = new Map();
72
+ if (options.logger) {
73
+ logger_1.LoggerFactory.setLogger(options.logger);
74
+ }
75
+ else if (options.logLevel && options.logLevel !== 'silent') {
76
+ logger_1.LoggerFactory.setLogger(logger_1.LoggerFactory.createConsoleLogger(options.logLevel));
77
+ }
78
+ this.logger = (0, logger_1.getLogger)();
84
79
  this.did = identity.did;
85
80
  this.publicKey = identity.publicKey;
86
81
  this.privateKey = identity.privateKey;
87
- this.timestampTolerance = options.timestampTolerance || 60000; // 60 seconds
82
+ this.encryptionPassword = options.encryptionPassword;
83
+ this.timestampTolerance = options.timestampTolerance || 60000;
88
84
  this.enableNonceTracking = options.enableNonceTracking !== false;
89
- // Multi-registry initialization
90
- this.didHost = identity.didHost || 'knowthat';
91
- this.registries = identity.registries || [
92
- {
93
- name: this.didHost,
94
- status: 'active',
95
- type: 'primary',
96
- registeredAt: identity.registeredAt
97
- }
98
- ];
99
- // Start nonce cleanup if tracking is enabled
85
+ this.directories = identity.directories || 'verified';
86
+ this.storage = storage_1.StorageFactory.create({
87
+ storage: options.storage,
88
+ customPath: options.persistencePath,
89
+ memoryKey: options.memoryKey || this.did,
90
+ encryptionPassword: options.encryptionPassword
91
+ });
92
+ this.transport = transport_1.TransportFactory.create({
93
+ transport: options.transport
94
+ });
95
+ this.precomputed = {
96
+ did: this.did,
97
+ publicKey: this.publicKey,
98
+ didBytes: new TextEncoder().encode(this.did),
99
+ signatureCache: new Map()
100
+ };
101
+ if (options.storage !== 'memory') {
102
+ this.rotationManager = new rotation_1.KeyRotationManager(identity, this.transport, {});
103
+ }
100
104
  if (this.enableNonceTracking) {
101
105
  this.startNonceCleanup();
102
106
  }
103
107
  }
104
- /**
105
- * Initialize MCP Identity - the main entry point
106
- *
107
- * IMPORTANT: This only makes API calls in these cases:
108
- * 1. First time ever (no identity exists) - registers with all specified registries
109
- * 2. Adding new registries to existing identity - only calls the new registries
110
- *
111
- * After initial registration, all subsequent calls load from disk with NO API calls.
112
- */
113
108
  static async init(options) {
114
- // Return existing global identity if already initialized
109
+ const logger = options?.logger || (0, logger_1.getLogger)();
115
110
  if (globalIdentity) {
116
- // Check if we need to sync to new registries
117
- if (options?.registries) {
118
- const requestedRegistries = (0, registry_1.resolveRegistries)(options.registries);
119
- await globalIdentity.syncToRegistries(requestedRegistries);
120
- }
121
111
  return globalIdentity;
122
112
  }
123
- // Try to load existing identity
124
- let identity = await loadIdentity(options?.persistencePath);
125
- // Handle existing identity
113
+ const storage = storage_1.StorageFactory.create({
114
+ storage: options?.storage,
115
+ customPath: options?.persistencePath,
116
+ memoryKey: options?.memoryKey,
117
+ encryptionPassword: options?.encryptionPassword
118
+ });
119
+ let identity = await storage.load();
126
120
  if (identity) {
127
- console.log('[MCP-I] Loaded existing identity:', identity.did);
121
+ logger.info('Loaded existing identity:', identity.did);
128
122
  globalIdentity = new MCPIdentity(identity, options);
129
- // Sync to any new registries specified in options
130
- if (options?.registries) {
131
- const requestedRegistries = (0, registry_1.resolveRegistries)(options.registries);
132
- await globalIdentity.syncToRegistries(requestedRegistries);
133
- }
134
123
  return globalIdentity;
135
124
  }
136
- // No existing identity - need to create new one
137
- console.log('[MCP-I] No existing identity found, creating new identity...');
138
- // Resolve which registries to use
139
- const registriesToUse = (0, registry_1.resolveRegistries)(options?.registries);
140
- const primaryRegistry = options?.didHost || 'knowthat';
141
- // Ensure primary registry is first
142
- const orderedRegistries = [
143
- primaryRegistry,
144
- ...registriesToUse.filter(r => r !== primaryRegistry)
145
- ];
146
- console.log('[MCP-I] Publishing to registries:', orderedRegistries.join(', '));
147
- // Create DID at primary registry (KnowThat by default)
148
- const primaryAdapter = registry_1.RegistryFactory.getAdapter(primaryRegistry);
149
- if (!primaryAdapter || primaryAdapter.type !== 'primary') {
150
- throw new Error(`Primary registry ${primaryRegistry} not available or not a primary registry`);
151
- }
152
- const publishData = {
153
- did: '', // Will be filled after registration
125
+ logger.info('No existing identity found, creating new identity...');
126
+ const transport = transport_1.TransportFactory.create({
127
+ transport: options?.transport
128
+ });
129
+ const apiEndpoint = options?.apiEndpoint || 'https://knowthat.ai';
130
+ logger.info('Registering with knowthat.ai...');
131
+ const registrationData = {
154
132
  name: options?.name || process.env.MCP_SERVER_NAME || 'Unnamed MCP Server',
155
133
  description: options?.description,
156
134
  repository: options?.repository,
157
- publicKey: '', // Will be filled after key generation
158
- metadata: {}
135
+ directories: options?.directories,
136
+ isDraft: options?.mode === 'development'
159
137
  };
160
- // Generate keys first
161
- console.log('[MCP-I] Generating cryptographic keys...');
138
+ logger.info('Generating cryptographic keys...');
162
139
  const keyPair = await crypto.generateKeyPair();
163
- publishData.publicKey = keyPair.publicKey;
164
- // Register with primary registry
165
- console.log(`[MCP-I] Registering with primary registry: ${primaryRegistry}`);
166
- const primaryResult = await primaryAdapter.publish(publishData);
167
- if (!primaryResult.success) {
168
- throw new Error(`Failed to register with primary registry: ${primaryResult.error}`);
169
- }
170
- // Get the full registration response (this is a bit hacky but maintains compatibility)
171
- const response = await autoRegister({
172
- name: publishData.name,
173
- description: publishData.description,
174
- repository: publishData.repository,
175
- apiEndpoint: primaryRegistry === 'knowthat' ? 'https://knowthat.ai' : options?.apiEndpoint || 'https://knowthat.ai'
140
+ const response = await autoRegister(transport, {
141
+ ...registrationData,
142
+ apiEndpoint,
143
+ directories: options?.directories
176
144
  });
177
- // Create persisted identity
178
145
  identity = {
179
146
  did: response.did,
180
147
  publicKey: keyPair.publicKey,
@@ -182,144 +149,113 @@ class MCPIdentity {
182
149
  agentId: response.agent.id,
183
150
  agentSlug: response.agent.slug,
184
151
  registeredAt: new Date().toISOString(),
185
- didHost: primaryRegistry,
186
- registries: [{
187
- name: primaryRegistry,
188
- status: 'active',
189
- type: 'primary',
190
- registeredAt: new Date().toISOString(),
191
- registryAgentId: response.agent.id
192
- }]
152
+ directories: options?.directories || 'verified'
193
153
  };
194
- // Save identity before publishing to other registries
195
- await saveIdentity(identity, options?.persistencePath);
196
- console.log('[MCP-I] ✅ Success! Your agent has been registered.');
197
- console.log(`[MCP-I] DID: ${response.did}`);
198
- console.log(`[MCP-I] Profile: ${response.agent.url}`);
199
- // Create MCPIdentity instance
200
- globalIdentity = new MCPIdentity(identity, options);
201
- // Publish to additional registries
202
- if (orderedRegistries.length > 1) {
203
- console.log('[MCP-I] Publishing to additional registries...');
204
- await globalIdentity.syncToRegistries(orderedRegistries.slice(1));
154
+ await storage.save(identity);
155
+ logger.info('✅ Success! Your agent has been registered.');
156
+ logger.info(`DID: ${response.did}`);
157
+ logger.info(`Profile: ${response.agent.url}`);
158
+ if (response.agent.claimUrl) {
159
+ logger.info(`Claim your agent: ${response.agent.claimUrl}`);
160
+ }
161
+ if (options?.directories && options.directories !== 'none') {
162
+ const dirMessage = options.directories === 'verified'
163
+ ? 'Your agent will be submitted to all verified directories'
164
+ : `Your agent will be submitted to: ${options.directories.join(', ')}`;
165
+ logger.info(dirMessage);
205
166
  }
167
+ globalIdentity = new MCPIdentity(identity, options);
206
168
  return globalIdentity;
207
169
  }
208
- /**
209
- * Sync identity to additional registries
210
- *
211
- * RATE LIMITED: Each registry can only be synced once per minute to prevent spam.
212
- * Skips registries that are already active.
213
- */
214
- async syncToRegistries(registryNames) {
215
- const publishData = {
216
- did: this.did,
217
- name: this.extractAgentName(),
218
- description: '', // Would need to store this
219
- repository: '', // Would need to store this
220
- publicKey: this.publicKey,
221
- agentId: this.extractAgentId(),
222
- agentSlug: this.extractAgentSlug(),
223
- metadata: {}
224
- };
225
- for (const registryName of registryNames) {
226
- // Skip if already registered
227
- if (this.registries.some(r => r.name === registryName && r.status === 'active')) {
228
- continue;
170
+ async enableAutoRotation(policy) {
171
+ if (!this.rotationManager) {
172
+ throw new Error('Key rotation not available in memory storage mode');
173
+ }
174
+ this.rotationManager.setupAutoRotation((result) => {
175
+ if (result.success) {
176
+ this.logger.info('Keys rotated successfully');
177
+ this.persistIdentity();
229
178
  }
230
- const adapter = registry_1.RegistryFactory.getAdapter(registryName);
231
- if (!adapter) {
232
- console.warn(`[MCP-I] Registry ${registryName} not available, skipping`);
233
- continue;
179
+ else {
180
+ this.logger.error('Key rotation failed:', result.error);
234
181
  }
182
+ });
183
+ }
184
+ async rotateKeys(reason) {
185
+ if (!this.rotationManager) {
186
+ throw new Error('Key rotation not available in memory storage mode');
187
+ }
188
+ const result = await this.rotationManager.rotateKeys(reason);
189
+ if (result.success) {
190
+ await this.persistIdentity();
191
+ }
192
+ return result;
193
+ }
194
+ checkKeyHealth() {
195
+ if (!this.rotationManager) {
196
+ return null;
197
+ }
198
+ return this.rotationManager.checkKeyHealth();
199
+ }
200
+ async getPrivateKey() {
201
+ if (this.decryptedPrivateKey) {
202
+ return this.decryptedPrivateKey;
203
+ }
204
+ if (this.encryptionPassword && this.privateKey.startsWith('enc:')) {
235
205
  try {
236
- console.log(`[MCP-I] Publishing to ${registryName}...`);
237
- const result = await adapter.publish(publishData);
238
- if (result.success) {
239
- // Update registry status
240
- const existingIndex = this.registries.findIndex(r => r.name === registryName);
241
- const newStatus = {
242
- name: registryName,
243
- status: 'active',
244
- type: adapter.type,
245
- registeredAt: new Date().toISOString(),
246
- registryAgentId: result.registryAgentId
247
- };
248
- if (existingIndex >= 0) {
249
- this.registries[existingIndex] = newStatus;
250
- }
251
- else {
252
- this.registries.push(newStatus);
253
- }
254
- console.log(`[MCP-I] ✅ Published to ${registryName}: ${result.profileUrl || 'success'}`);
255
- }
256
- else {
257
- console.error(`[MCP-I] ❌ Failed to publish to ${registryName}: ${result.error}`);
258
- // Update registry status with error
259
- this.registries.push({
260
- name: registryName,
261
- status: 'failed',
262
- type: adapter.type,
263
- error: result.error,
264
- lastSyncAt: new Date().toISOString()
265
- });
266
- }
206
+ this.decryptedPrivateKey = await crypto.decrypt(this.privateKey, this.encryptionPassword);
207
+ this.logger.debug('Private key decrypted successfully');
208
+ return this.decryptedPrivateKey;
267
209
  }
268
210
  catch (error) {
269
- console.error(`[MCP-I] Error publishing to ${registryName}:`, error.message);
270
- this.registries.push({
271
- name: registryName,
272
- status: 'failed',
273
- type: 'secondary',
274
- error: error.message,
275
- lastSyncAt: new Date().toISOString()
276
- });
211
+ this.logger.error('Failed to decrypt private key:', error);
212
+ throw new Error('Invalid encryption password');
277
213
  }
278
214
  }
279
- // Save updated registry status
280
- await this.persistRegistryStatus();
281
- }
282
- /**
283
- * Add a new registry
284
- */
285
- async addRegistry(registryName) {
286
- await this.syncToRegistries([registryName]);
287
- }
288
- /**
289
- * Add multiple registries
290
- */
291
- async addRegistries(registryNames) {
292
- await this.syncToRegistries(registryNames);
293
- }
294
- /**
295
- * Get current registry status
296
- */
297
- getRegistryStatus() {
298
- return [...this.registries];
299
- }
300
- /**
301
- * Check if registered with a specific registry
302
- */
303
- isRegisteredWith(registryName) {
304
- return this.registries.some(r => r.name === registryName && r.status === 'active');
215
+ return this.privateKey;
305
216
  }
306
- /**
307
- * Sign a message with the agent's private key using Ed25519
308
- */
309
217
  async sign(message) {
310
- return crypto.sign(message, this.privateKey);
218
+ const messageStr = typeof message === 'string' ? message : message.toString('base64');
219
+ const cached = this.precomputed.signatureCache.get(messageStr);
220
+ if (cached) {
221
+ return cached;
222
+ }
223
+ const privateKey = await this.getPrivateKey();
224
+ const signature = await crypto.sign(message, privateKey);
225
+ if (this.precomputed.signatureCache.size > 100) {
226
+ const firstKey = this.precomputed.signatureCache.keys().next().value;
227
+ if (firstKey) {
228
+ this.precomputed.signatureCache.delete(firstKey);
229
+ }
230
+ }
231
+ this.precomputed.signatureCache.set(messageStr, signature);
232
+ if (this.rotationManager) {
233
+ this.rotationManager.incrementSignatureCount();
234
+ }
235
+ return signature;
236
+ }
237
+ async requestEditAccess() {
238
+ const timestamp = Date.now();
239
+ const message = `edit-request:${this.did}:knowthat.ai:${timestamp}`;
240
+ const signature = await this.sign(message);
241
+ const baseUrl = 'https://knowthat.ai';
242
+ const editUrl = new URL(`${baseUrl}/agents/edit`);
243
+ editUrl.searchParams.set('did', this.did);
244
+ editUrl.searchParams.set('timestamp', timestamp.toString());
245
+ editUrl.searchParams.set('signature', signature);
246
+ const claimUrl = new URL(`${baseUrl}/agents/claim`);
247
+ claimUrl.searchParams.set('did', this.did);
248
+ claimUrl.searchParams.set('timestamp', timestamp.toString());
249
+ claimUrl.searchParams.set('signature', signature);
250
+ return {
251
+ editUrl: editUrl.toString(),
252
+ claimUrl: claimUrl.toString()
253
+ };
311
254
  }
312
- /**
313
- * Verify a signature against a public key
314
- */
315
255
  async verify(message, signature, publicKey) {
316
256
  return crypto.verify(message, signature, publicKey || this.publicKey);
317
257
  }
318
- /**
319
- * Respond to an MCP-I challenge
320
- */
321
258
  async respondToChallenge(challenge) {
322
- // Validate timestamp to prevent replay attacks
323
259
  const now = Date.now();
324
260
  const challengeAge = now - challenge.timestamp;
325
261
  if (challengeAge > this.timestampTolerance) {
@@ -328,14 +264,12 @@ class MCPIdentity {
328
264
  if (challengeAge < 0) {
329
265
  throw new Error('Challenge timestamp is in the future');
330
266
  }
331
- // Check for nonce reuse if tracking is enabled
332
267
  if (this.enableNonceTracking) {
333
268
  if (this.usedNonces.has(challenge.nonce)) {
334
269
  throw new Error('Nonce already used');
335
270
  }
336
271
  this.usedNonces.add(challenge.nonce);
337
272
  }
338
- // Create the message to sign
339
273
  const messageComponents = [
340
274
  challenge.nonce,
341
275
  challenge.timestamp.toString(),
@@ -344,9 +278,7 @@ class MCPIdentity {
344
278
  (challenge.scope || []).join(',')
345
279
  ];
346
280
  const message = messageComponents.join(':');
347
- // Sign the challenge
348
281
  const signature = await this.sign(message);
349
- // Return the response
350
282
  return {
351
283
  did: this.did,
352
284
  signature,
@@ -355,43 +287,29 @@ class MCPIdentity {
355
287
  publicKey: this.publicKey
356
288
  };
357
289
  }
358
- /**
359
- * Get MCP-I capabilities for advertisement
360
- */
361
290
  getCapabilities() {
362
- const activeRegistries = this.registries.filter(r => r.status === 'active');
363
- const secondaryRegistries = activeRegistries
364
- .filter(r => r.type === 'secondary')
365
- .map(r => r.name);
366
291
  return {
367
292
  version: '1.0',
368
293
  did: this.did,
369
294
  publicKey: this.publicKey,
370
- conformanceLevel: 2, // Level 2: Full crypto with challenge-response
295
+ conformanceLevel: 2,
371
296
  handshakeSupported: true,
372
297
  handshakeEndpoint: '/_mcp-i/handshake',
373
- verificationEndpoint: `https://${this.didHost === 'knowthat' ? 'knowthat.ai' : this.didHost}/api/agents/${this.did}/verify`,
374
- registries: {
375
- primary: this.didHost,
376
- secondary: secondaryRegistries
377
- }
298
+ verificationEndpoint: `https://knowthat.ai/api/agents/${this.did}/verify`,
299
+ registry: 'knowthat.ai'
378
300
  };
379
301
  }
380
- /**
381
- * Sign an MCP response with identity metadata
382
- */
383
302
  async signResponse(response) {
384
303
  const timestamp = new Date().toISOString();
385
304
  const responseWithIdentity = {
386
305
  ...response,
387
306
  _mcp_identity: {
388
307
  did: this.did,
389
- signature: '', // Will be filled below
308
+ signature: '',
390
309
  timestamp,
391
310
  conformanceLevel: 2
392
311
  }
393
312
  };
394
- // Sign the response content (excluding the signature field)
395
313
  const contentToSign = JSON.stringify({
396
314
  ...response,
397
315
  _mcp_identity: {
@@ -403,227 +321,142 @@ class MCPIdentity {
403
321
  responseWithIdentity._mcp_identity.signature = await this.sign(contentToSign);
404
322
  return responseWithIdentity;
405
323
  }
406
- /**
407
- * Generate a new nonce for challenges
408
- */
409
324
  static generateNonce() {
410
- return crypto.generateNonce();
325
+ return crypto.generateNonceSync();
411
326
  }
412
- /**
413
- * Request edit access to agent profile
414
- * Returns a signed URL for editing the agent on the registry
415
- */
416
- async requestEditAccess(registryName) {
417
- const registry = registryName || this.didHost;
418
- const timestamp = Date.now();
419
- const message = `edit-request:${this.did}:${registry}:${timestamp}`;
420
- const signature = await this.sign(message);
421
- // Construct edit URL with proof of ownership
422
- const baseUrl = registry === 'knowthat'
423
- ? 'https://knowthat.ai'
424
- : `https://${registry}`;
425
- const editUrl = new URL(`${baseUrl}/agents/edit`);
426
- editUrl.searchParams.set('did', this.did);
427
- editUrl.searchParams.set('timestamp', timestamp.toString());
428
- editUrl.searchParams.set('signature', signature);
429
- return editUrl.toString();
327
+ getDirectories() {
328
+ return this.directories;
430
329
  }
431
- /**
432
- * Clean up old nonces periodically to prevent memory leaks
433
- */
434
330
  startNonceCleanup() {
435
- // Clean up nonces older than 2x the timestamp tolerance
436
331
  this.nonceCleanupInterval = setInterval(() => {
437
- // In a production system, you'd track nonce timestamps
438
- // For now, we'll clear all nonces periodically
439
332
  if (this.usedNonces.size > 10000) {
440
333
  this.usedNonces.clear();
441
334
  }
442
335
  }, this.timestampTolerance * 2);
443
336
  }
444
- /**
445
- * Clean up resources
446
- */
447
337
  destroy() {
448
338
  if (this.nonceCleanupInterval) {
449
339
  clearInterval(this.nonceCleanupInterval);
450
340
  }
451
341
  this.usedNonces.clear();
342
+ this.precomputed.signatureCache.clear();
452
343
  }
453
- /**
454
- * Helper to extract agent name from DID
455
- */
456
344
  extractAgentName() {
457
- // Try to get from persisted data or environment
458
345
  return process.env.MCP_SERVER_NAME || 'Unknown Agent';
459
346
  }
460
- /**
461
- * Helper to extract agent ID
462
- */
463
347
  extractAgentId() {
464
348
  return process.env.AGENT_ID || '';
465
349
  }
466
- /**
467
- * Helper to extract agent slug
468
- */
469
350
  extractAgentSlug() {
470
351
  const parts = this.did.split(':');
471
352
  return parts[parts.length - 1];
472
353
  }
473
- /**
474
- * Persist updated registry status
475
- */
476
- async persistRegistryStatus() {
354
+ async persistIdentity() {
477
355
  try {
478
- const filePath = path.join(process.cwd(), '.mcp-identity.json');
479
- const current = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
480
- current.registries = this.registries;
481
- fs.writeFileSync(filePath, JSON.stringify(current, null, 2));
356
+ const identity = {
357
+ did: this.did,
358
+ publicKey: this.publicKey,
359
+ privateKey: this.privateKey,
360
+ agentId: this.extractAgentId(),
361
+ agentSlug: this.extractAgentSlug(),
362
+ registeredAt: new Date().toISOString(),
363
+ directories: this.directories
364
+ };
365
+ await this.storage.save(identity);
482
366
  }
483
367
  catch (error) {
484
- console.error('[MCP-I] Failed to persist registry status:', error);
368
+ this.logger.error('Failed to persist identity:', error);
485
369
  }
486
370
  }
487
371
  }
488
372
  exports.MCPIdentity = MCPIdentity;
489
- /**
490
- * Enable MCP Identity for any MCP server
491
- * This is the main integration point that patches the MCP Server
492
- */
493
373
  async function enableMCPIdentity(options) {
494
374
  const identity = await MCPIdentity.init(options);
495
- // Try to patch MCP Server if available
496
375
  try {
497
376
  patchMCPServer(identity);
498
377
  }
499
378
  catch (error) {
500
- console.log('[MCP-I] MCP Server not found, identity initialized for manual use');
379
+ const logger = (0, logger_1.getLogger)();
380
+ logger.debug('MCP Server not found, identity initialized for manual use');
501
381
  }
502
382
  return identity;
503
383
  }
504
- /**
505
- * Patch the MCP Server to automatically add identity
506
- */
507
- function patchMCPServer(identity) {
508
- try {
509
- // Try to import the MCP SDK
510
- const MCPModule = require('@modelcontextprotocol/sdk/server/index.js');
511
- const OriginalServer = MCPModule.Server;
512
- if (!OriginalServer) {
513
- return;
514
- }
515
- // Store original methods
516
- const originalSetRequestHandler = OriginalServer.prototype.setRequestHandler;
517
- const originalConnect = OriginalServer.prototype.connect;
518
- // Patch setRequestHandler to wrap all responses
519
- OriginalServer.prototype.setRequestHandler = function (method, handler) {
384
+ function createMCPMiddleware(identity) {
385
+ return (server) => {
386
+ const originalSetRequestHandler = server.setRequestHandler.bind(server);
387
+ const originalConnect = server.connect.bind(server);
388
+ server.setRequestHandler = function (method, handler) {
520
389
  const wrappedHandler = async (...args) => {
521
390
  const result = await handler(...args);
522
- // If result has content, sign it
523
391
  if (result && typeof result === 'object' && 'content' in result) {
524
- const signed = await identity.signResponse(result);
525
- return signed;
392
+ return await identity.signResponse(result);
526
393
  }
527
394
  return result;
528
395
  };
529
- return originalSetRequestHandler.call(this, method, wrappedHandler);
396
+ return originalSetRequestHandler(method, wrappedHandler);
530
397
  };
531
- // Patch connect to advertise MCP-I capabilities
532
- OriginalServer.prototype.connect = async function (transport) {
533
- // Add MCP-I capabilities to server info
398
+ server.connect = async function (transport) {
534
399
  if (this.serverInfo && this.serverInfo.capabilities) {
535
400
  this.serverInfo.capabilities['mcp-i'] = identity.getCapabilities();
536
401
  }
537
- // Set up MCP-I handshake handler
538
402
  this.setRequestHandler('mcp-i/challenge', async (request) => {
539
403
  return identity.respondToChallenge(request.params);
540
404
  });
541
- // Call original connect
542
- return originalConnect.call(this, transport);
405
+ return originalConnect(transport);
543
406
  };
544
- console.log('[MCP-I] ✨ MCP Server patched - all responses will be automatically signed');
545
- }
546
- catch (error) {
547
- // MCP SDK not available, that's okay
548
- }
407
+ };
549
408
  }
550
- // Helper functions (inline to keep package standalone)
551
- async function loadIdentity(customPath) {
552
- // Check environment variables first (already loaded by process)
553
- if (process.env.AGENT_DID && process.env.AGENT_PUBLIC_KEY && process.env.AGENT_PRIVATE_KEY) {
554
- const identity = {
555
- did: process.env.AGENT_DID,
556
- publicKey: process.env.AGENT_PUBLIC_KEY,
557
- privateKey: process.env.AGENT_PRIVATE_KEY,
558
- agentId: process.env.AGENT_ID || '',
559
- agentSlug: process.env.AGENT_SLUG || '',
560
- registeredAt: new Date().toISOString(),
561
- didHost: process.env.AGENT_DID_HOST || 'knowthat'
562
- };
563
- // Try to load registry status from file
564
- try {
565
- const filePath = customPath || path.join(process.cwd(), '.mcp-identity.json');
566
- if (fs.existsSync(filePath)) {
567
- const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
568
- if (fileContent.registries) {
569
- identity.registries = fileContent.registries;
570
- }
571
- }
572
- }
573
- catch {
574
- // Ignore errors
575
- }
576
- return identity;
577
- }
578
- // Check JSON file (most reliable for programmatic access)
579
- const filePath = customPath || path.join(process.cwd(), '.mcp-identity.json');
409
+ function patchMCPServer(identity) {
580
410
  try {
581
- if (fs.existsSync(filePath)) {
582
- const content = fs.readFileSync(filePath, 'utf-8');
583
- return JSON.parse(content);
411
+ const MCPModule = require('@modelcontextprotocol/sdk/server/index.js');
412
+ const OriginalServer = MCPModule.Server;
413
+ if (!OriginalServer) {
414
+ return;
584
415
  }
416
+ const middleware = createMCPMiddleware(identity);
417
+ const OriginalConstructor = OriginalServer;
418
+ MCPModule.Server = function (...args) {
419
+ const instance = new OriginalConstructor(...args);
420
+ middleware(instance, identity);
421
+ return instance;
422
+ };
423
+ Object.setPrototypeOf(MCPModule.Server, OriginalConstructor);
424
+ Object.setPrototypeOf(MCPModule.Server.prototype, OriginalConstructor.prototype);
425
+ const logger = (0, logger_1.getLogger)();
426
+ logger.info('✨ MCP Server patched - all responses will be automatically signed');
585
427
  }
586
- catch {
587
- // Ignore errors
428
+ catch (error) {
588
429
  }
589
- return null;
590
- }
591
- async function saveIdentity(identity, customPath) {
592
- // Save as JSON for programmatic access
593
- const filePath = customPath || path.join(process.cwd(), '.mcp-identity.json');
594
- fs.writeFileSync(filePath, JSON.stringify(identity, null, 2));
595
- console.log('[MCP-I] Identity saved to .mcp-identity.json');
596
430
  }
597
- async function autoRegister(options) {
431
+ async function autoRegister(transport, options) {
598
432
  try {
599
- const response = await axios_1.default.post(`${options.apiEndpoint}/api/agents/auto-register`, {
433
+ const response = await transport.post(`${options.apiEndpoint}/api/agents/auto-register`, {
600
434
  metadata: {
601
435
  name: options.name,
602
436
  description: options.description,
603
437
  repository: options.repository,
604
- version: '1.0.0'
438
+ version: '1.0.0',
439
+ isDraft: options.isDraft,
440
+ directories: options.directories || 'verified'
605
441
  },
606
442
  clientInfo: {
607
- sdkVersion: '0.2.0',
443
+ sdkVersion: '0.3.0',
608
444
  language: 'typescript',
609
- platform: 'node' // Always node for MCP servers
445
+ platform: 'node'
610
446
  }
611
447
  }, {
612
448
  timeout: 30000,
613
449
  headers: {
614
450
  'Content-Type': 'application/json',
615
- 'User-Agent': '@kya-os/mcp-i/0.2.0'
451
+ 'User-Agent': '@kya-os/mcp-i/0.3.0'
616
452
  }
617
453
  });
618
454
  return response.data;
619
455
  }
620
456
  catch (error) {
621
- if (error.response?.status === 429) {
457
+ if (error.message?.includes('429')) {
622
458
  throw new Error('Rate limit exceeded. Please try again later.');
623
459
  }
624
- throw new Error(error.response?.data?.message ||
625
- error.message ||
626
- 'Failed to auto-register agent');
460
+ throw new Error(error.message || 'Failed to auto-register agent');
627
461
  }
628
462
  }
629
- //# sourceMappingURL=index.js.map