@kya-os/mcp-i 0.1.0-alpha.2.2 → 0.1.0-alpha.2.4
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 +258 -58
- package/dist/auto.d.ts +0 -12
- package/dist/auto.js +3 -14
- package/dist/crypto.d.ts +10 -26
- package/dist/crypto.js +117 -37
- package/dist/dev-helper.d.ts +3 -0
- package/dist/dev-helper.js +54 -0
- package/dist/encrypted-storage.d.ts +11 -0
- package/dist/encrypted-storage.js +73 -0
- package/dist/index.d.ts +33 -48
- package/dist/index.js +267 -191
- package/dist/logger.d.ts +32 -0
- package/dist/logger.js +66 -0
- package/dist/registry/index.d.ts +12 -0
- package/dist/registry/index.js +56 -0
- package/dist/registry/knowthat.d.ts +13 -0
- package/dist/registry/knowthat.js +88 -0
- package/dist/rotation.d.ts +35 -0
- package/dist/rotation.js +102 -0
- package/dist/storage.d.ts +41 -0
- package/dist/storage.js +163 -0
- package/dist/transport.d.ts +34 -0
- package/dist/transport.js +207 -0
- package/dist/types.d.ts +80 -17
- package/dist/types.js +0 -4
- package/package.json +36 -8
- package/dist/__tests__/challenge-response.test.d.ts +0 -5
- package/dist/__tests__/challenge-response.test.d.ts.map +0 -1
- package/dist/__tests__/challenge-response.test.js +0 -218
- package/dist/__tests__/challenge-response.test.js.map +0 -1
- package/dist/__tests__/crypto.test.d.ts +0 -5
- package/dist/__tests__/crypto.test.d.ts.map +0 -1
- package/dist/__tests__/crypto.test.js +0 -153
- package/dist/__tests__/crypto.test.js.map +0 -1
- package/dist/auto-enhance.d.ts +0 -41
- package/dist/auto-enhance.d.ts.map +0 -1
- package/dist/auto-enhance.js +0 -193
- package/dist/auto-enhance.js.map +0 -1
- package/dist/auto-init.d.ts +0 -12
- package/dist/auto-init.d.ts.map +0 -1
- package/dist/auto-init.js +0 -166
- package/dist/auto-init.js.map +0 -1
- package/dist/auto.d.ts.map +0 -1
- package/dist/auto.js.map +0 -1
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/patch.d.ts +0 -22
- package/dist/patch.d.ts.map +0 -1
- package/dist/patch.js +0 -164
- package/dist/patch.js.map +0 -1
- package/dist/transparent.d.ts +0 -40
- package/dist/transparent.d.ts.map +0 -1
- package/dist/transparent.js +0 -167
- package/dist/transparent.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +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
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
3
|
if (k2 === undefined) k2 = k;
|
|
19
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -50,94 +35,227 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
50
35
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
51
36
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
52
37
|
};
|
|
53
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
54
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
55
|
-
};
|
|
56
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
-
exports.MCPIdentity = 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;
|
|
58
40
|
exports.enableMCPIdentity = enableMCPIdentity;
|
|
59
|
-
|
|
60
|
-
const fs = __importStar(require("fs"));
|
|
61
|
-
const path = __importStar(require("path"));
|
|
41
|
+
exports.createMCPMiddleware = createMCPMiddleware;
|
|
62
42
|
const crypto = __importStar(require("./crypto"));
|
|
63
|
-
|
|
43
|
+
const storage_1 = require("./storage");
|
|
44
|
+
const transport_1 = require("./transport");
|
|
45
|
+
const logger_1 = require("./logger");
|
|
46
|
+
const rotation_1 = require("./rotation");
|
|
64
47
|
__exportStar(require("./types"), exports);
|
|
65
|
-
|
|
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; } });
|
|
66
68
|
let globalIdentity = null;
|
|
67
69
|
class MCPIdentity {
|
|
68
70
|
constructor(identity, options = {}) {
|
|
69
71
|
this.usedNonces = new Set();
|
|
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)();
|
|
70
79
|
this.did = identity.did;
|
|
71
80
|
this.publicKey = identity.publicKey;
|
|
72
81
|
this.privateKey = identity.privateKey;
|
|
73
|
-
this.
|
|
82
|
+
this.encryptionPassword = options.encryptionPassword;
|
|
83
|
+
this.timestampTolerance = options.timestampTolerance || 60000;
|
|
74
84
|
this.enableNonceTracking = options.enableNonceTracking !== false;
|
|
75
|
-
|
|
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
|
+
}
|
|
76
104
|
if (this.enableNonceTracking) {
|
|
77
105
|
this.startNonceCleanup();
|
|
78
106
|
}
|
|
79
107
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Initialize MCP Identity - the main entry point
|
|
82
|
-
*/
|
|
83
108
|
static async init(options) {
|
|
84
|
-
|
|
85
|
-
if (globalIdentity
|
|
109
|
+
const logger = options?.logger || (0, logger_1.getLogger)();
|
|
110
|
+
if (globalIdentity) {
|
|
86
111
|
return globalIdentity;
|
|
87
112
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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();
|
|
120
|
+
if (identity) {
|
|
121
|
+
logger.info('Loaded existing identity:', identity.did);
|
|
122
|
+
globalIdentity = new MCPIdentity(identity, options);
|
|
123
|
+
return globalIdentity;
|
|
124
|
+
}
|
|
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 = {
|
|
132
|
+
name: options?.name || process.env.MCP_SERVER_NAME || 'Unnamed MCP Server',
|
|
133
|
+
description: options?.description,
|
|
134
|
+
repository: options?.repository,
|
|
135
|
+
directories: options?.directories,
|
|
136
|
+
isDraft: options?.mode === 'development'
|
|
137
|
+
};
|
|
138
|
+
logger.info('Generating cryptographic keys...');
|
|
139
|
+
const keyPair = await crypto.generateKeyPair();
|
|
140
|
+
const response = await autoRegister(transport, {
|
|
141
|
+
...registrationData,
|
|
142
|
+
apiEndpoint,
|
|
143
|
+
directories: options?.directories
|
|
144
|
+
});
|
|
145
|
+
identity = {
|
|
146
|
+
did: response.did,
|
|
147
|
+
publicKey: keyPair.publicKey,
|
|
148
|
+
privateKey: keyPair.privateKey,
|
|
149
|
+
agentId: response.agent.id,
|
|
150
|
+
agentSlug: response.agent.slug,
|
|
151
|
+
registeredAt: new Date().toISOString(),
|
|
152
|
+
directories: options?.directories || 'verified'
|
|
153
|
+
};
|
|
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);
|
|
120
166
|
}
|
|
121
167
|
globalIdentity = new MCPIdentity(identity, options);
|
|
122
168
|
return globalIdentity;
|
|
123
169
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.logger.error('Key rotation failed:', result.error);
|
|
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:')) {
|
|
205
|
+
try {
|
|
206
|
+
this.decryptedPrivateKey = await crypto.decrypt(this.privateKey, this.encryptionPassword);
|
|
207
|
+
this.logger.debug('Private key decrypted successfully');
|
|
208
|
+
return this.decryptedPrivateKey;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.logger.error('Failed to decrypt private key:', error);
|
|
212
|
+
throw new Error('Invalid encryption password');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return this.privateKey;
|
|
216
|
+
}
|
|
127
217
|
async sign(message) {
|
|
128
|
-
|
|
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
|
+
};
|
|
129
254
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Verify a signature against a public key
|
|
132
|
-
*/
|
|
133
255
|
async verify(message, signature, publicKey) {
|
|
134
256
|
return crypto.verify(message, signature, publicKey || this.publicKey);
|
|
135
257
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Respond to an MCP-I challenge
|
|
138
|
-
*/
|
|
139
258
|
async respondToChallenge(challenge) {
|
|
140
|
-
// Validate timestamp to prevent replay attacks
|
|
141
259
|
const now = Date.now();
|
|
142
260
|
const challengeAge = now - challenge.timestamp;
|
|
143
261
|
if (challengeAge > this.timestampTolerance) {
|
|
@@ -146,14 +264,12 @@ class MCPIdentity {
|
|
|
146
264
|
if (challengeAge < 0) {
|
|
147
265
|
throw new Error('Challenge timestamp is in the future');
|
|
148
266
|
}
|
|
149
|
-
// Check for nonce reuse if tracking is enabled
|
|
150
267
|
if (this.enableNonceTracking) {
|
|
151
268
|
if (this.usedNonces.has(challenge.nonce)) {
|
|
152
269
|
throw new Error('Nonce already used');
|
|
153
270
|
}
|
|
154
271
|
this.usedNonces.add(challenge.nonce);
|
|
155
272
|
}
|
|
156
|
-
// Create the message to sign
|
|
157
273
|
const messageComponents = [
|
|
158
274
|
challenge.nonce,
|
|
159
275
|
challenge.timestamp.toString(),
|
|
@@ -162,9 +278,7 @@ class MCPIdentity {
|
|
|
162
278
|
(challenge.scope || []).join(',')
|
|
163
279
|
];
|
|
164
280
|
const message = messageComponents.join(':');
|
|
165
|
-
// Sign the challenge
|
|
166
281
|
const signature = await this.sign(message);
|
|
167
|
-
// Return the response
|
|
168
282
|
return {
|
|
169
283
|
did: this.did,
|
|
170
284
|
signature,
|
|
@@ -173,35 +287,29 @@ class MCPIdentity {
|
|
|
173
287
|
publicKey: this.publicKey
|
|
174
288
|
};
|
|
175
289
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Get MCP-I capabilities for advertisement
|
|
178
|
-
*/
|
|
179
290
|
getCapabilities() {
|
|
180
291
|
return {
|
|
181
292
|
version: '1.0',
|
|
182
293
|
did: this.did,
|
|
183
294
|
publicKey: this.publicKey,
|
|
184
|
-
conformanceLevel: 2,
|
|
295
|
+
conformanceLevel: 2,
|
|
185
296
|
handshakeSupported: true,
|
|
186
297
|
handshakeEndpoint: '/_mcp-i/handshake',
|
|
187
|
-
verificationEndpoint: `https://knowthat.ai/api/agents/${this.did}/verify
|
|
298
|
+
verificationEndpoint: `https://knowthat.ai/api/agents/${this.did}/verify`,
|
|
299
|
+
registry: 'knowthat.ai'
|
|
188
300
|
};
|
|
189
301
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Sign an MCP response with identity metadata
|
|
192
|
-
*/
|
|
193
302
|
async signResponse(response) {
|
|
194
303
|
const timestamp = new Date().toISOString();
|
|
195
304
|
const responseWithIdentity = {
|
|
196
305
|
...response,
|
|
197
306
|
_mcp_identity: {
|
|
198
307
|
did: this.did,
|
|
199
|
-
signature: '',
|
|
308
|
+
signature: '',
|
|
200
309
|
timestamp,
|
|
201
310
|
conformanceLevel: 2
|
|
202
311
|
}
|
|
203
312
|
};
|
|
204
|
-
// Sign the response content (excluding the signature field)
|
|
205
313
|
const contentToSign = JSON.stringify({
|
|
206
314
|
...response,
|
|
207
315
|
_mcp_identity: {
|
|
@@ -213,174 +321,142 @@ class MCPIdentity {
|
|
|
213
321
|
responseWithIdentity._mcp_identity.signature = await this.sign(contentToSign);
|
|
214
322
|
return responseWithIdentity;
|
|
215
323
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Generate a new nonce for challenges
|
|
218
|
-
*/
|
|
219
324
|
static generateNonce() {
|
|
220
|
-
return crypto.
|
|
325
|
+
return crypto.generateNonceSync();
|
|
326
|
+
}
|
|
327
|
+
getDirectories() {
|
|
328
|
+
return this.directories;
|
|
221
329
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Clean up old nonces periodically to prevent memory leaks
|
|
224
|
-
*/
|
|
225
330
|
startNonceCleanup() {
|
|
226
|
-
// Clean up nonces older than 2x the timestamp tolerance
|
|
227
331
|
this.nonceCleanupInterval = setInterval(() => {
|
|
228
|
-
// In a production system, you'd track nonce timestamps
|
|
229
|
-
// For now, we'll clear all nonces periodically
|
|
230
332
|
if (this.usedNonces.size > 10000) {
|
|
231
333
|
this.usedNonces.clear();
|
|
232
334
|
}
|
|
233
335
|
}, this.timestampTolerance * 2);
|
|
234
336
|
}
|
|
235
|
-
/**
|
|
236
|
-
* Clean up resources
|
|
237
|
-
*/
|
|
238
337
|
destroy() {
|
|
239
338
|
if (this.nonceCleanupInterval) {
|
|
240
339
|
clearInterval(this.nonceCleanupInterval);
|
|
241
340
|
}
|
|
242
341
|
this.usedNonces.clear();
|
|
342
|
+
this.precomputed.signatureCache.clear();
|
|
343
|
+
}
|
|
344
|
+
extractAgentName() {
|
|
345
|
+
return process.env.MCP_SERVER_NAME || 'Unknown Agent';
|
|
346
|
+
}
|
|
347
|
+
extractAgentId() {
|
|
348
|
+
return process.env.AGENT_ID || '';
|
|
349
|
+
}
|
|
350
|
+
extractAgentSlug() {
|
|
351
|
+
const parts = this.did.split(':');
|
|
352
|
+
return parts[parts.length - 1];
|
|
353
|
+
}
|
|
354
|
+
async persistIdentity() {
|
|
355
|
+
try {
|
|
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);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
this.logger.error('Failed to persist identity:', error);
|
|
369
|
+
}
|
|
243
370
|
}
|
|
244
371
|
}
|
|
245
372
|
exports.MCPIdentity = MCPIdentity;
|
|
246
|
-
/**
|
|
247
|
-
* Enable MCP Identity for any MCP server
|
|
248
|
-
* This is the main integration point that patches the MCP Server
|
|
249
|
-
*/
|
|
250
373
|
async function enableMCPIdentity(options) {
|
|
251
374
|
const identity = await MCPIdentity.init(options);
|
|
252
|
-
// Try to patch MCP Server if available
|
|
253
375
|
try {
|
|
254
376
|
patchMCPServer(identity);
|
|
255
377
|
}
|
|
256
378
|
catch (error) {
|
|
257
|
-
|
|
379
|
+
const logger = (0, logger_1.getLogger)();
|
|
380
|
+
logger.debug('MCP Server not found, identity initialized for manual use');
|
|
258
381
|
}
|
|
259
382
|
return identity;
|
|
260
383
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// Try to import the MCP SDK
|
|
267
|
-
const MCPModule = require('@modelcontextprotocol/sdk/server/index.js');
|
|
268
|
-
const OriginalServer = MCPModule.Server;
|
|
269
|
-
if (!OriginalServer) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
// Store original methods
|
|
273
|
-
const originalSetRequestHandler = OriginalServer.prototype.setRequestHandler;
|
|
274
|
-
const originalConnect = OriginalServer.prototype.connect;
|
|
275
|
-
// Patch setRequestHandler to wrap all responses
|
|
276
|
-
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) {
|
|
277
389
|
const wrappedHandler = async (...args) => {
|
|
278
390
|
const result = await handler(...args);
|
|
279
|
-
// If result has content, sign it
|
|
280
391
|
if (result && typeof result === 'object' && 'content' in result) {
|
|
281
|
-
|
|
282
|
-
return signed;
|
|
392
|
+
return await identity.signResponse(result);
|
|
283
393
|
}
|
|
284
394
|
return result;
|
|
285
395
|
};
|
|
286
|
-
return originalSetRequestHandler
|
|
396
|
+
return originalSetRequestHandler(method, wrappedHandler);
|
|
287
397
|
};
|
|
288
|
-
|
|
289
|
-
OriginalServer.prototype.connect = async function (transport) {
|
|
290
|
-
// Add MCP-I capabilities to server info
|
|
398
|
+
server.connect = async function (transport) {
|
|
291
399
|
if (this.serverInfo && this.serverInfo.capabilities) {
|
|
292
400
|
this.serverInfo.capabilities['mcp-i'] = identity.getCapabilities();
|
|
293
401
|
}
|
|
294
|
-
// Set up MCP-I handshake handler
|
|
295
402
|
this.setRequestHandler('mcp-i/challenge', async (request) => {
|
|
296
403
|
return identity.respondToChallenge(request.params);
|
|
297
404
|
});
|
|
298
|
-
|
|
299
|
-
return originalConnect.call(this, transport);
|
|
405
|
+
return originalConnect(transport);
|
|
300
406
|
};
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
// MCP SDK not available, that's okay
|
|
305
|
-
}
|
|
407
|
+
};
|
|
306
408
|
}
|
|
307
|
-
|
|
308
|
-
async function loadIdentity(customPath) {
|
|
309
|
-
// Check environment variables first (already loaded by process)
|
|
310
|
-
if (process.env.AGENT_DID && process.env.AGENT_PUBLIC_KEY && process.env.AGENT_PRIVATE_KEY) {
|
|
311
|
-
return {
|
|
312
|
-
did: process.env.AGENT_DID,
|
|
313
|
-
publicKey: process.env.AGENT_PUBLIC_KEY,
|
|
314
|
-
privateKey: process.env.AGENT_PRIVATE_KEY,
|
|
315
|
-
agentId: process.env.AGENT_ID || '',
|
|
316
|
-
agentSlug: process.env.AGENT_SLUG || '',
|
|
317
|
-
registeredAt: new Date().toISOString()
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
// Check JSON file (most reliable for programmatic access)
|
|
321
|
-
const filePath = customPath || path.join(process.cwd(), '.mcp-identity.json');
|
|
409
|
+
function patchMCPServer(identity) {
|
|
322
410
|
try {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
411
|
+
const MCPModule = require('@modelcontextprotocol/sdk/server/index.js');
|
|
412
|
+
const OriginalServer = MCPModule.Server;
|
|
413
|
+
if (!OriginalServer) {
|
|
414
|
+
return;
|
|
326
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');
|
|
327
427
|
}
|
|
328
|
-
catch {
|
|
329
|
-
// Ignore errors
|
|
428
|
+
catch (error) {
|
|
330
429
|
}
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
async function saveIdentity(identity, customPath) {
|
|
334
|
-
// Save to .env (standard) and .env.local (for frameworks)
|
|
335
|
-
const envContent = `
|
|
336
|
-
# MCP-I Identity (auto-generated)
|
|
337
|
-
AGENT_DID="${identity.did}"
|
|
338
|
-
AGENT_PUBLIC_KEY="${identity.publicKey}"
|
|
339
|
-
AGENT_PRIVATE_KEY="${identity.privateKey}"
|
|
340
|
-
AGENT_ID="${identity.agentId}"
|
|
341
|
-
AGENT_SLUG="${identity.agentSlug}"
|
|
342
|
-
`;
|
|
343
|
-
// Save to .env for standard Node.js compatibility
|
|
344
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
345
|
-
fs.writeFileSync(envPath, envContent.trim());
|
|
346
|
-
// Also save to .env.local for framework compatibility (Next.js, Vite, etc.)
|
|
347
|
-
const envLocalPath = path.join(process.cwd(), '.env.local');
|
|
348
|
-
fs.writeFileSync(envLocalPath, envContent.trim());
|
|
349
|
-
// Also save as JSON for programmatic access
|
|
350
|
-
const filePath = customPath || path.join(process.cwd(), '.mcp-identity.json');
|
|
351
|
-
fs.writeFileSync(filePath, JSON.stringify(identity, null, 2));
|
|
352
|
-
console.log('[MCP-I] Identity saved to .env, .env.local, and .mcp-identity.json');
|
|
353
430
|
}
|
|
354
|
-
async function autoRegister(options) {
|
|
431
|
+
async function autoRegister(transport, options) {
|
|
355
432
|
try {
|
|
356
|
-
const response = await
|
|
433
|
+
const response = await transport.post(`${options.apiEndpoint}/api/agents/auto-register`, {
|
|
357
434
|
metadata: {
|
|
358
435
|
name: options.name,
|
|
359
436
|
description: options.description,
|
|
360
437
|
repository: options.repository,
|
|
361
|
-
version: '1.0.0'
|
|
438
|
+
version: '1.0.0',
|
|
439
|
+
isDraft: options.isDraft,
|
|
440
|
+
directories: options.directories || 'verified'
|
|
362
441
|
},
|
|
363
442
|
clientInfo: {
|
|
364
|
-
sdkVersion: '0.
|
|
443
|
+
sdkVersion: '0.3.0',
|
|
365
444
|
language: 'typescript',
|
|
366
|
-
platform: 'node'
|
|
445
|
+
platform: 'node'
|
|
367
446
|
}
|
|
368
447
|
}, {
|
|
369
448
|
timeout: 30000,
|
|
370
449
|
headers: {
|
|
371
450
|
'Content-Type': 'application/json',
|
|
372
|
-
'User-Agent': '@kya-os/mcp-i/0.
|
|
451
|
+
'User-Agent': '@kya-os/mcp-i/0.3.0'
|
|
373
452
|
}
|
|
374
453
|
});
|
|
375
454
|
return response.data;
|
|
376
455
|
}
|
|
377
456
|
catch (error) {
|
|
378
|
-
if (error.
|
|
457
|
+
if (error.message?.includes('429')) {
|
|
379
458
|
throw new Error('Rate limit exceeded. Please try again later.');
|
|
380
459
|
}
|
|
381
|
-
throw new Error(error.
|
|
382
|
-
error.message ||
|
|
383
|
-
'Failed to auto-register agent');
|
|
460
|
+
throw new Error(error.message || 'Failed to auto-register agent');
|
|
384
461
|
}
|
|
385
462
|
}
|
|
386
|
-
//# sourceMappingURL=index.js.map
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
2
|
+
export interface Logger {
|
|
3
|
+
debug(message: string, ...args: any[]): void;
|
|
4
|
+
info(message: string, ...args: any[]): void;
|
|
5
|
+
warn(message: string, ...args: any[]): void;
|
|
6
|
+
error(message: string, ...args: any[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare class SilentLogger implements Logger {
|
|
9
|
+
debug(): void;
|
|
10
|
+
info(): void;
|
|
11
|
+
warn(): void;
|
|
12
|
+
error(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare class ConsoleLogger implements Logger {
|
|
15
|
+
private prefix;
|
|
16
|
+
private level;
|
|
17
|
+
constructor(prefix?: string, level?: LogLevel);
|
|
18
|
+
private shouldLog;
|
|
19
|
+
debug(message: string, ...args: any[]): void;
|
|
20
|
+
info(message: string, ...args: any[]): void;
|
|
21
|
+
warn(message: string, ...args: any[]): void;
|
|
22
|
+
error(message: string, ...args: any[]): void;
|
|
23
|
+
}
|
|
24
|
+
export declare class LoggerFactory {
|
|
25
|
+
private static instance;
|
|
26
|
+
static setLogger(logger: Logger): void;
|
|
27
|
+
static getLogger(): Logger;
|
|
28
|
+
static createConsoleLogger(level?: LogLevel): Logger;
|
|
29
|
+
static createSilentLogger(): Logger;
|
|
30
|
+
static reset(): void;
|
|
31
|
+
}
|
|
32
|
+
export declare function getLogger(): Logger;
|