@kya-os/mcp-i 0.1.0-alpha.1 → 0.1.0-alpha.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -106
- package/dist/__tests__/challenge-response.test.d.ts +5 -0
- package/dist/__tests__/challenge-response.test.d.ts.map +1 -0
- package/dist/__tests__/challenge-response.test.js +217 -0
- package/dist/__tests__/challenge-response.test.js.map +1 -0
- package/dist/__tests__/crypto.test.d.ts +5 -0
- package/dist/__tests__/crypto.test.d.ts.map +1 -0
- package/dist/__tests__/crypto.test.js +153 -0
- package/dist/__tests__/crypto.test.js.map +1 -0
- package/dist/crypto.d.ts +32 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +117 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +18 -27
package/README.md
CHANGED
|
@@ -1,144 +1,217 @@
|
|
|
1
1
|
# @kya-os/mcp-i
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ultra-light MCP Identity auto-registration with cryptographic challenge-response authentication.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Enable any MCP server to get a verifiable identity with just 2 lines of code!
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🚀 **2-line integration** - Zero configuration required
|
|
10
|
+
- 🔐 **Ed25519 cryptographic signing** - Secure challenge-response authentication
|
|
11
|
+
- 🌐 **Auto-registration** - Automatic DID creation via knowthat.ai
|
|
12
|
+
- 🔏 **MCP-I Handshake support** - Full challenge-response protocol implementation
|
|
13
|
+
- 🛡️ **Replay protection** - Nonce tracking and timestamp validation
|
|
14
|
+
- 📦 **Ultra-lightweight** - Minimal dependencies
|
|
15
|
+
- ⚡ **Level 2 MCP-I conformance** - Production-ready security
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @kya-os/mcp-i
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
6
24
|
|
|
7
25
|
```typescript
|
|
8
26
|
import { MCPIdentity } from "@kya-os/mcp-i";
|
|
9
|
-
|
|
27
|
+
|
|
28
|
+
// That's it! Your MCP server now has a verifiable identity
|
|
29
|
+
const identity = await MCPIdentity.init();
|
|
10
30
|
```
|
|
11
31
|
|
|
12
|
-
##
|
|
32
|
+
## Challenge-Response Authentication
|
|
13
33
|
|
|
14
|
-
|
|
34
|
+
The package now includes full MCP-I Handshake support with cryptographic challenge-response:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// Respond to authentication challenges
|
|
38
|
+
const challenge = {
|
|
39
|
+
nonce: "a1b2c3d4e5f6...",
|
|
40
|
+
timestamp: Date.now(),
|
|
41
|
+
verifier_did: "did:web:verifier.example.com"
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const response = await identity.respondToChallenge(challenge);
|
|
45
|
+
// Returns signed response with agent's DID and signature
|
|
46
|
+
```
|
|
15
47
|
|
|
16
|
-
|
|
17
|
-
2. **Future Runs**: Loads the saved identity
|
|
18
|
-
3. **Every Response**: Adds verifiable identity metadata
|
|
19
|
-
4. **Zero Config**: Works out of the box
|
|
48
|
+
## Core Features
|
|
20
49
|
|
|
21
|
-
|
|
50
|
+
### Auto-Registration
|
|
22
51
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
52
|
+
On first run, the SDK automatically:
|
|
53
|
+
1. Registers your agent with knowthat.ai
|
|
54
|
+
2. Generates cryptographic keys (Ed25519)
|
|
55
|
+
3. Saves identity for future use
|
|
56
|
+
4. Returns a DID like `did:web:knowthat.ai:agents:your-agent-name`
|
|
28
57
|
|
|
29
|
-
|
|
58
|
+
### Cryptographic Signing
|
|
30
59
|
|
|
31
|
-
|
|
32
|
-
|
|
60
|
+
All signatures use Ed25519 for security:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Sign any message
|
|
64
|
+
const signature = await identity.sign("Hello, World!");
|
|
65
|
+
|
|
66
|
+
// Verify signatures
|
|
67
|
+
const isValid = await identity.verify(message, signature, publicKey);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### MCP Response Signing
|
|
71
|
+
|
|
72
|
+
Automatically sign MCP responses with identity metadata:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const response = {
|
|
76
|
+
content: [{ type: 'text', text: 'Task completed!' }]
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const signedResponse = await identity.signResponse(response);
|
|
80
|
+
// Includes _mcp_identity with DID, signature, and timestamp
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Capability Advertisement
|
|
84
|
+
|
|
85
|
+
Advertise your MCP-I capabilities:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const capabilities = identity.getCapabilities();
|
|
89
|
+
// {
|
|
90
|
+
// version: '1.0',
|
|
91
|
+
// did: 'did:web:knowthat.ai:agents:...',
|
|
92
|
+
// conformanceLevel: 2,
|
|
93
|
+
// handshakeSupported: true,
|
|
94
|
+
// handshakeEndpoint: '/_mcp-i/handshake'
|
|
95
|
+
// }
|
|
33
96
|
```
|
|
34
97
|
|
|
35
|
-
##
|
|
98
|
+
## Advanced Options
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const identity = await MCPIdentity.init({
|
|
102
|
+
// Custom agent metadata
|
|
103
|
+
name: 'My Amazing Agent',
|
|
104
|
+
description: 'Does amazing things',
|
|
105
|
+
repository: 'https://github.com/user/agent',
|
|
106
|
+
|
|
107
|
+
// Security options
|
|
108
|
+
timestampTolerance: 30000, // 30 seconds (default: 60)
|
|
109
|
+
enableNonceTracking: true, // Prevent replay attacks (default: true)
|
|
110
|
+
|
|
111
|
+
// Storage options
|
|
112
|
+
persistencePath: './config/identity.json'
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Security Features
|
|
117
|
+
|
|
118
|
+
- **Ed25519 signatures** - Cryptographically secure signing
|
|
119
|
+
- **Replay protection** - Tracks used nonces to prevent replay attacks
|
|
120
|
+
- **Timestamp validation** - Rejects expired challenges
|
|
121
|
+
- **Constant-time comparison** - Prevents timing attacks
|
|
122
|
+
- **Secure key storage** - Private keys never exposed in logs
|
|
123
|
+
|
|
124
|
+
## Identity Persistence
|
|
125
|
+
|
|
126
|
+
Identity is saved in multiple locations for maximum compatibility:
|
|
127
|
+
|
|
128
|
+
### Files Created:
|
|
129
|
+
1. **`.env`** - Standard environment file for Node.js
|
|
130
|
+
2. **`.env.local`** - For framework compatibility (Next.js, Vite, etc.)
|
|
131
|
+
3. **`.mcp-identity.json`** - JSON format for programmatic access
|
|
132
|
+
|
|
133
|
+
### Loading Priority:
|
|
134
|
+
1. Environment variables (if already loaded)
|
|
135
|
+
2. `.mcp-identity.json` file (most reliable)
|
|
136
|
+
|
|
137
|
+
### Environment Loading:
|
|
138
|
+
- **Plain Node.js**: Add `require('dotenv').config()` to load `.env`
|
|
139
|
+
- **Next.js/Vite**: Automatically loads `.env.local`
|
|
140
|
+
- **MCP Servers**: Typically need to configure environment loading
|
|
141
|
+
|
|
142
|
+
### Security Note:
|
|
143
|
+
Add these to your `.gitignore`:
|
|
144
|
+
```
|
|
145
|
+
.env
|
|
146
|
+
.env.local
|
|
147
|
+
.mcp-identity.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Example: Full MCP Server
|
|
36
151
|
|
|
37
152
|
```typescript
|
|
38
153
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
39
154
|
import { MCPIdentity } from "@kya-os/mcp-i";
|
|
40
155
|
|
|
41
|
-
// Initialize identity
|
|
156
|
+
// Initialize identity
|
|
42
157
|
const identity = await MCPIdentity.init({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
description: "Does amazing things with AI",
|
|
46
|
-
repository: "https://github.com/myusername/my-server",
|
|
47
|
-
categories: ["productivity", "automation"]
|
|
48
|
-
}
|
|
158
|
+
name: "Calendar Assistant",
|
|
159
|
+
description: "Helps manage your calendar"
|
|
49
160
|
});
|
|
50
161
|
|
|
51
|
-
// Create
|
|
162
|
+
// Create MCP server with identity
|
|
52
163
|
const server = new Server({
|
|
53
|
-
name: "
|
|
54
|
-
version: "1.0.0"
|
|
55
|
-
|
|
56
|
-
|
|
164
|
+
name: "calendar-assistant",
|
|
165
|
+
version: "1.0.0"
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Handle authentication challenges automatically
|
|
169
|
+
server.on("mcp-i:challenge", async (challenge) => {
|
|
170
|
+
return await identity.respondToChallenge(challenge);
|
|
57
171
|
});
|
|
58
172
|
|
|
59
|
-
//
|
|
173
|
+
// All responses are automatically signed
|
|
174
|
+
server.setRequestHandler('tools/call', async (request) => {
|
|
175
|
+
const result = { success: true };
|
|
176
|
+
return await identity.signResponse(result);
|
|
177
|
+
});
|
|
60
178
|
```
|
|
61
179
|
|
|
62
|
-
##
|
|
180
|
+
## Conformance Levels
|
|
63
181
|
|
|
64
|
-
|
|
65
|
-
|
|
182
|
+
This package implements **MCP-I Level 2** conformance:
|
|
183
|
+
- ✅ Cryptographic identity (Ed25519)
|
|
184
|
+
- ✅ Challenge-response authentication
|
|
185
|
+
- ✅ Replay protection
|
|
186
|
+
- ✅ Signed responses
|
|
187
|
+
- ✅ Timestamp validation
|
|
66
188
|
|
|
67
|
-
|
|
68
|
-
[MCP-I] ✅ Success! Your agent has been registered.
|
|
69
|
-
[MCP-I] DID: did:web:knowthat.ai:agents:my-awesome-server
|
|
70
|
-
[MCP-I] Profile: https://knowthat.ai/agents/my-awesome-server
|
|
71
|
-
[MCP-I] Identity saved to .env.local
|
|
72
|
-
```
|
|
189
|
+
## API Reference
|
|
73
190
|
|
|
74
|
-
|
|
191
|
+
### `MCPIdentity.init(options?)`
|
|
192
|
+
Initialize or load MCP identity. Auto-registers if needed.
|
|
75
193
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Agent metadata for registration
|
|
79
|
-
metadata?: {
|
|
80
|
-
name: string;
|
|
81
|
-
description?: string;
|
|
82
|
-
repository?: string;
|
|
83
|
-
categories?: string[];
|
|
84
|
-
version?: string;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// Advanced options
|
|
88
|
-
apiEndpoint?: string; // Custom API endpoint
|
|
89
|
-
autoRegister?: boolean; // Disable auto-registration
|
|
90
|
-
persistenceBackend?: string; // 'env' | 'file' | 'keychain' | 'auto'
|
|
91
|
-
persistencePath?: string; // Custom storage path
|
|
92
|
-
}
|
|
93
|
-
```
|
|
194
|
+
### `identity.respondToChallenge(challenge)`
|
|
195
|
+
Respond to an MCP-I authentication challenge.
|
|
94
196
|
|
|
95
|
-
|
|
197
|
+
### `identity.sign(message)`
|
|
198
|
+
Sign a message with Ed25519.
|
|
96
199
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
3. **System Keychain** (coming soon)
|
|
115
|
-
- macOS Keychain
|
|
116
|
-
- Windows Credential Manager
|
|
117
|
-
- Linux Secret Service
|
|
118
|
-
|
|
119
|
-
## How Identity Flows Through MCP
|
|
120
|
-
|
|
121
|
-
Once initialized, your identity automatically:
|
|
122
|
-
|
|
123
|
-
- Signs all MCP responses
|
|
124
|
-
- Responds to identity challenges
|
|
125
|
-
- Advertises capabilities
|
|
126
|
-
- Builds reputation over time
|
|
127
|
-
|
|
128
|
-
Example response with identity:
|
|
129
|
-
|
|
130
|
-
```json
|
|
131
|
-
{
|
|
132
|
-
"result": "Task completed successfully",
|
|
133
|
-
"_mcp_identity": {
|
|
134
|
-
"did": "did:web:knowthat.ai:agents:my-server",
|
|
135
|
-
"signature": "0x3045...",
|
|
136
|
-
"timestamp": "2025-01-31T10:00:00Z",
|
|
137
|
-
"conformanceLevel": 1
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
```
|
|
200
|
+
### `identity.verify(message, signature, publicKey?)`
|
|
201
|
+
Verify an Ed25519 signature.
|
|
202
|
+
|
|
203
|
+
### `identity.signResponse(response)`
|
|
204
|
+
Sign an MCP response with identity metadata.
|
|
205
|
+
|
|
206
|
+
### `identity.getCapabilities()`
|
|
207
|
+
Get MCP-I capability advertisement.
|
|
208
|
+
|
|
209
|
+
### `MCPIdentity.generateNonce()`
|
|
210
|
+
Generate a cryptographically secure nonce.
|
|
211
|
+
|
|
212
|
+
### `identity.destroy()`
|
|
213
|
+
Clean up resources (stops nonce cleanup timer).
|
|
141
214
|
|
|
142
215
|
## License
|
|
143
216
|
|
|
144
|
-
MIT
|
|
217
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge-response.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/challenge-response.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for challenge-response authentication
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const vitest_1 = require("vitest");
|
|
40
|
+
const index_1 = require("../index");
|
|
41
|
+
const crypto = __importStar(require("../crypto"));
|
|
42
|
+
// Mock axios for auto-registration
|
|
43
|
+
vitest_1.vi.mock('axios');
|
|
44
|
+
// Mock fs for identity persistence
|
|
45
|
+
vitest_1.vi.mock('fs', () => ({
|
|
46
|
+
existsSync: vitest_1.vi.fn(() => false),
|
|
47
|
+
readFileSync: vitest_1.vi.fn(),
|
|
48
|
+
writeFileSync: vitest_1.vi.fn()
|
|
49
|
+
}));
|
|
50
|
+
(0, vitest_1.describe)('MCPIdentity Challenge-Response', () => {
|
|
51
|
+
let identity;
|
|
52
|
+
let keyPair;
|
|
53
|
+
(0, vitest_1.beforeEach)(async () => {
|
|
54
|
+
// Mock environment to have pre-existing identity
|
|
55
|
+
keyPair = await crypto.generateKeyPair();
|
|
56
|
+
process.env.AGENT_DID = 'did:web:knowthat.ai:agents:test-agent';
|
|
57
|
+
process.env.AGENT_PUBLIC_KEY = keyPair.publicKey;
|
|
58
|
+
process.env.AGENT_PRIVATE_KEY = keyPair.privateKey;
|
|
59
|
+
process.env.AGENT_ID = 'agent-123';
|
|
60
|
+
process.env.AGENT_SLUG = 'test-agent';
|
|
61
|
+
identity = await index_1.MCPIdentity.init();
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.afterEach)(() => {
|
|
64
|
+
// Clean up environment
|
|
65
|
+
delete process.env.AGENT_DID;
|
|
66
|
+
delete process.env.AGENT_PUBLIC_KEY;
|
|
67
|
+
delete process.env.AGENT_PRIVATE_KEY;
|
|
68
|
+
delete process.env.AGENT_ID;
|
|
69
|
+
delete process.env.AGENT_SLUG;
|
|
70
|
+
});
|
|
71
|
+
(0, vitest_1.describe)('respondToChallenge', () => {
|
|
72
|
+
(0, vitest_1.it)('should successfully respond to a valid challenge', async () => {
|
|
73
|
+
const challenge = {
|
|
74
|
+
nonce: crypto.generateNonce(),
|
|
75
|
+
timestamp: Date.now(),
|
|
76
|
+
verifier_did: 'did:web:example.com:verifier',
|
|
77
|
+
scope: ['read', 'write']
|
|
78
|
+
};
|
|
79
|
+
const response = await identity.respondToChallenge(challenge);
|
|
80
|
+
(0, vitest_1.expect)(response).toMatchObject({
|
|
81
|
+
did: 'did:web:knowthat.ai:agents:test-agent',
|
|
82
|
+
nonce: challenge.nonce,
|
|
83
|
+
publicKey: keyPair.publicKey
|
|
84
|
+
});
|
|
85
|
+
(0, vitest_1.expect)(response.signature).toBeDefined();
|
|
86
|
+
(0, vitest_1.expect)(response.timestamp).toBeGreaterThanOrEqual(challenge.timestamp);
|
|
87
|
+
// Verify the signature
|
|
88
|
+
const messageComponents = [
|
|
89
|
+
challenge.nonce,
|
|
90
|
+
challenge.timestamp.toString(),
|
|
91
|
+
response.did,
|
|
92
|
+
challenge.verifier_did || '',
|
|
93
|
+
(challenge.scope || []).join(',')
|
|
94
|
+
];
|
|
95
|
+
const message = messageComponents.join(':');
|
|
96
|
+
const isValid = await identity.verify(message, response.signature);
|
|
97
|
+
(0, vitest_1.expect)(isValid).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)('should reject expired challenges', async () => {
|
|
100
|
+
const challenge = {
|
|
101
|
+
nonce: crypto.generateNonce(),
|
|
102
|
+
timestamp: Date.now() - 120000, // 2 minutes ago
|
|
103
|
+
};
|
|
104
|
+
await (0, vitest_1.expect)(identity.respondToChallenge(challenge))
|
|
105
|
+
.rejects.toThrow('Challenge expired');
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('should reject challenges with future timestamps', async () => {
|
|
108
|
+
const challenge = {
|
|
109
|
+
nonce: crypto.generateNonce(),
|
|
110
|
+
timestamp: Date.now() + 60000, // 1 minute in future
|
|
111
|
+
};
|
|
112
|
+
await (0, vitest_1.expect)(identity.respondToChallenge(challenge))
|
|
113
|
+
.rejects.toThrow('Challenge timestamp is in the future');
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('should reject reused nonces when tracking is enabled', async () => {
|
|
116
|
+
const challenge = {
|
|
117
|
+
nonce: crypto.generateNonce(),
|
|
118
|
+
timestamp: Date.now(),
|
|
119
|
+
};
|
|
120
|
+
// First use should succeed
|
|
121
|
+
await identity.respondToChallenge(challenge);
|
|
122
|
+
// Second use should fail
|
|
123
|
+
await (0, vitest_1.expect)(identity.respondToChallenge(challenge))
|
|
124
|
+
.rejects.toThrow('Nonce already used');
|
|
125
|
+
});
|
|
126
|
+
(0, vitest_1.it)('should handle challenges without optional fields', async () => {
|
|
127
|
+
const challenge = {
|
|
128
|
+
nonce: crypto.generateNonce(),
|
|
129
|
+
timestamp: Date.now(),
|
|
130
|
+
};
|
|
131
|
+
const response = await identity.respondToChallenge(challenge);
|
|
132
|
+
(0, vitest_1.expect)(response).toMatchObject({
|
|
133
|
+
did: 'did:web:knowthat.ai:agents:test-agent',
|
|
134
|
+
nonce: challenge.nonce,
|
|
135
|
+
});
|
|
136
|
+
// Verify signature with empty optional fields
|
|
137
|
+
const messageComponents = [
|
|
138
|
+
challenge.nonce,
|
|
139
|
+
challenge.timestamp.toString(),
|
|
140
|
+
response.did,
|
|
141
|
+
'', // No verifier_did
|
|
142
|
+
'' // No scope
|
|
143
|
+
];
|
|
144
|
+
const message = messageComponents.join(':');
|
|
145
|
+
const isValid = await identity.verify(message, response.signature);
|
|
146
|
+
(0, vitest_1.expect)(isValid).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.describe)('timestamp tolerance', () => {
|
|
150
|
+
(0, vitest_1.it)('should accept challenges within tolerance window', async () => {
|
|
151
|
+
// Create identity with 5 second tolerance
|
|
152
|
+
const strictIdentity = await index_1.MCPIdentity.init({
|
|
153
|
+
timestampTolerance: 5000
|
|
154
|
+
});
|
|
155
|
+
const challenge = {
|
|
156
|
+
nonce: crypto.generateNonce(),
|
|
157
|
+
timestamp: Date.now() - 4000, // 4 seconds ago
|
|
158
|
+
};
|
|
159
|
+
// Should succeed
|
|
160
|
+
const response = await strictIdentity.respondToChallenge(challenge);
|
|
161
|
+
(0, vitest_1.expect)(response).toBeDefined();
|
|
162
|
+
});
|
|
163
|
+
(0, vitest_1.it)('should reject challenges outside tolerance window', async () => {
|
|
164
|
+
// Create identity with 5 second tolerance
|
|
165
|
+
const strictIdentity = await index_1.MCPIdentity.init({
|
|
166
|
+
timestampTolerance: 5000
|
|
167
|
+
});
|
|
168
|
+
const challenge = {
|
|
169
|
+
nonce: crypto.generateNonce(),
|
|
170
|
+
timestamp: Date.now() - 6000, // 6 seconds ago
|
|
171
|
+
};
|
|
172
|
+
// Should fail
|
|
173
|
+
await (0, vitest_1.expect)(strictIdentity.respondToChallenge(challenge))
|
|
174
|
+
.rejects.toThrow('Challenge expired');
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
(0, vitest_1.describe)('nonce tracking', () => {
|
|
178
|
+
(0, vitest_1.it)('should allow disabling nonce tracking', async () => {
|
|
179
|
+
const identityNoTracking = await index_1.MCPIdentity.init({
|
|
180
|
+
enableNonceTracking: false
|
|
181
|
+
});
|
|
182
|
+
const challenge = {
|
|
183
|
+
nonce: crypto.generateNonce(),
|
|
184
|
+
timestamp: Date.now(),
|
|
185
|
+
};
|
|
186
|
+
// Should succeed multiple times
|
|
187
|
+
await identityNoTracking.respondToChallenge(challenge);
|
|
188
|
+
await identityNoTracking.respondToChallenge(challenge);
|
|
189
|
+
// No error thrown
|
|
190
|
+
(0, vitest_1.expect)(true).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
(0, vitest_1.describe)('getCapabilities', () => {
|
|
194
|
+
(0, vitest_1.it)('should advertise MCP-I capabilities', () => {
|
|
195
|
+
const capabilities = identity.getCapabilities();
|
|
196
|
+
(0, vitest_1.expect)(capabilities).toEqual({
|
|
197
|
+
version: '1.0',
|
|
198
|
+
did: 'did:web:knowthat.ai:agents:test-agent',
|
|
199
|
+
publicKey: keyPair.publicKey,
|
|
200
|
+
conformanceLevel: 2,
|
|
201
|
+
handshakeSupported: true,
|
|
202
|
+
handshakeEndpoint: '/_mcp-i/handshake',
|
|
203
|
+
verificationEndpoint: 'https://knowthat.ai/api/agents/did:web:knowthat.ai:agents:test-agent/verify'
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
(0, vitest_1.describe)('static methods', () => {
|
|
208
|
+
(0, vitest_1.it)('should generate nonces', () => {
|
|
209
|
+
const nonce1 = index_1.MCPIdentity.generateNonce();
|
|
210
|
+
const nonce2 = index_1.MCPIdentity.generateNonce();
|
|
211
|
+
(0, vitest_1.expect)(nonce1).toHaveLength(64);
|
|
212
|
+
(0, vitest_1.expect)(nonce2).toHaveLength(64);
|
|
213
|
+
(0, vitest_1.expect)(nonce1).not.toEqual(nonce2);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=challenge-response.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge-response.test.js","sourceRoot":"","sources":["../../src/__tests__/challenge-response.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/crypto.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|