@pcircle/evidencemcp-server 0.1.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/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +340 -0
- package/dist/index.js.map +1 -0
- package/dist/test-helpers.d.ts +51 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +170 -0
- package/dist/test-helpers.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PCIRCLE, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# @pcircle/evidencemcp-server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@pcircle/evidencemcp-server)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](tests/)
|
|
6
|
+
[](package.json)
|
|
7
|
+
|
|
8
|
+
Model Context Protocol (MCP) server for EvidenceMCP - automatically captures and encrypts LLM conversations as legal evidence.
|
|
9
|
+
|
|
10
|
+
## Why EvidenceMCP?
|
|
11
|
+
|
|
12
|
+
### For Developers & Content Creators
|
|
13
|
+
- **Prove IP Ownership** - Timestamped evidence of LLM-assisted work for copyright protection
|
|
14
|
+
- **Zero Effort** - Automatic capture via MCP protocol, no manual logging required
|
|
15
|
+
- **Legally Valid** - Git timestamps + encryption provide tamper-proof evidence
|
|
16
|
+
- **Privacy First** - All data encrypted locally, never leaves your machine
|
|
17
|
+
|
|
18
|
+
### For Researchers & Academics
|
|
19
|
+
- **Research Integrity** - Document AI-assisted research with provable timestamps
|
|
20
|
+
- **Audit Trail** - Complete conversation history for methodology transparency
|
|
21
|
+
- **Compliance Ready** - Meet institutional requirements for AI usage disclosure
|
|
22
|
+
|
|
23
|
+
### For Teams & Organizations
|
|
24
|
+
- **Risk Mitigation** - Legal protection against IP disputes over AI-generated content
|
|
25
|
+
- **Quality Assurance** - Review and audit LLM interactions for compliance
|
|
26
|
+
- **Knowledge Management** - Searchable archive of all LLM conversations
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- 🔐 **End-to-End Encryption** - XChaCha20-Poly1305 authenticated encryption
|
|
31
|
+
- 📝 **Automatic Capture** - Intercepts LLM conversations via MCP protocol
|
|
32
|
+
- 🕒 **Git Timestamps** - Provable timestamps from Git commits
|
|
33
|
+
- 📦 **Evidence Export** - ZIP archives with SHA-256 checksums
|
|
34
|
+
- 🔍 **Evidence Management** - List, retrieve, and decrypt stored evidence
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add @pcircle/evidencemcp-server
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
### 1. Set Environment Variables
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export EVIDENCEMCP_DB_PATH="./evidence.db"
|
|
48
|
+
export EVIDENCEMCP_PASSWORD="your-secure-password"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Run MCP Server
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx evidencemcp-mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. Configure Claude Desktop
|
|
58
|
+
|
|
59
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"evidencemcp": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["evidencemcp-mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"EVIDENCEMCP_DB_PATH": "/path/to/evidence.db",
|
|
69
|
+
"EVIDENCEMCP_PASSWORD": "your-password"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## MCP Tools
|
|
77
|
+
|
|
78
|
+
### capture-evidence
|
|
79
|
+
|
|
80
|
+
Capture and encrypt an LLM conversation.
|
|
81
|
+
|
|
82
|
+
**Input:**
|
|
83
|
+
- `conversationId` (string) - Unique conversation identifier
|
|
84
|
+
- `llmProvider` (string) - LLM provider name (e.g., "Claude Sonnet 4.5")
|
|
85
|
+
- `content` (string) - Conversation content
|
|
86
|
+
- `messageCount` (number) - Number of messages
|
|
87
|
+
- `tags` (string, optional) - Comma-separated tags
|
|
88
|
+
|
|
89
|
+
**Output:**
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"id": "uuid-v4",
|
|
93
|
+
"timestamp": "2024-01-24T00:00:00Z",
|
|
94
|
+
"gitCommitHash": "abc123...",
|
|
95
|
+
"success": true
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### list-evidences
|
|
100
|
+
|
|
101
|
+
List all captured evidence with pagination.
|
|
102
|
+
|
|
103
|
+
**Input:**
|
|
104
|
+
- `limit` (number, optional) - Maximum results
|
|
105
|
+
- `offset` (number, optional) - Pagination offset
|
|
106
|
+
|
|
107
|
+
**Output:**
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"evidences": [
|
|
111
|
+
{
|
|
112
|
+
"id": "uuid",
|
|
113
|
+
"timestamp": "2024-01-24T00:00:00Z",
|
|
114
|
+
"conversationId": "conv-001",
|
|
115
|
+
"llmProvider": "Claude Sonnet 4.5",
|
|
116
|
+
"messageCount": 10,
|
|
117
|
+
"tags": "legal,contract"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"total": 1
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### get-evidence
|
|
125
|
+
|
|
126
|
+
Retrieve and decrypt specific evidence.
|
|
127
|
+
|
|
128
|
+
**Input:**
|
|
129
|
+
- `id` (string) - Evidence ID
|
|
130
|
+
|
|
131
|
+
**Output:**
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"id": "uuid",
|
|
135
|
+
"timestamp": "2024-01-24T00:00:00Z",
|
|
136
|
+
"conversationId": "conv-001",
|
|
137
|
+
"llmProvider": "Claude Sonnet 4.5",
|
|
138
|
+
"content": "User: ...\nAssistant: ...",
|
|
139
|
+
"messageCount": 10,
|
|
140
|
+
"gitInfo": {
|
|
141
|
+
"commitHash": "abc123",
|
|
142
|
+
"timestamp": "2024-01-24T00:00:00Z"
|
|
143
|
+
},
|
|
144
|
+
"tags": "legal"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### export-evidences
|
|
149
|
+
|
|
150
|
+
Export evidences to encrypted ZIP archive.
|
|
151
|
+
|
|
152
|
+
**Input:**
|
|
153
|
+
- `evidenceIds` (string[], optional) - Specific IDs (empty = all)
|
|
154
|
+
- `includeGitInfo` (boolean, optional) - Include Git timestamps
|
|
155
|
+
|
|
156
|
+
**Output:**
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"filename": "evidence-export-2024-01-24.zip",
|
|
160
|
+
"checksum": "sha256-hash",
|
|
161
|
+
"evidenceCount": 5,
|
|
162
|
+
"success": true
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## MCP Resources
|
|
167
|
+
|
|
168
|
+
### evidence://{id}
|
|
169
|
+
|
|
170
|
+
Access decrypted evidence content via URI.
|
|
171
|
+
|
|
172
|
+
**Example:**
|
|
173
|
+
```
|
|
174
|
+
evidence://550e8400-e29b-41d4-a716-446655440000
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Returns plain text content of the evidence.
|
|
178
|
+
|
|
179
|
+
## Programmatic Usage
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { EvidenceMCPServer } from '@pcircle/evidencemcp-server';
|
|
183
|
+
|
|
184
|
+
const server = new EvidenceMCPServer({
|
|
185
|
+
dbPath: './evidence.db',
|
|
186
|
+
password: 'your-password'
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
await server.start();
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Security
|
|
193
|
+
|
|
194
|
+
- **Encryption**: XChaCha20-Poly1305 (256-bit keys)
|
|
195
|
+
- **Key Derivation**: Argon2id (OWASP recommended params)
|
|
196
|
+
- **Content Integrity**: SHA-256 hashing
|
|
197
|
+
- **Local Storage**: SQLite with encrypted BLOB fields
|
|
198
|
+
|
|
199
|
+
⚠️ **Important**: Store your `EVIDENCEMCP_PASSWORD` securely (e.g., macOS Keychain). Loss of password means permanent data loss.
|
|
200
|
+
|
|
201
|
+
## Architecture
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
┌─────────────────┐
|
|
205
|
+
│ LLM Client │ (Claude Desktop, ChatGPT, etc.)
|
|
206
|
+
│ (MCP Client) │
|
|
207
|
+
└────────┬────────┘
|
|
208
|
+
│ MCP Protocol (stdio)
|
|
209
|
+
▼
|
|
210
|
+
┌─────────────────┐
|
|
211
|
+
│ EvidenceMCP MCP │
|
|
212
|
+
│ Server │
|
|
213
|
+
├─────────────────┤
|
|
214
|
+
│ Tools: │
|
|
215
|
+
│ - capture │
|
|
216
|
+
│ - list │
|
|
217
|
+
│ - export │
|
|
218
|
+
│ - get │
|
|
219
|
+
├─────────────────┤
|
|
220
|
+
│ Resources: │
|
|
221
|
+
│ - evidence:// │
|
|
222
|
+
└────────┬────────┘
|
|
223
|
+
│
|
|
224
|
+
▼
|
|
225
|
+
┌─────────────────┐ ┌──────────────┐
|
|
226
|
+
│ @evidencemcp/ │────▶│ XChaCha20 │
|
|
227
|
+
│ crypto │ │ -Poly1305 │
|
|
228
|
+
└─────────────────┘ └──────────────┘
|
|
229
|
+
│
|
|
230
|
+
▼
|
|
231
|
+
┌─────────────────┐ ┌──────────────┐
|
|
232
|
+
│ @evidencemcp/ │────▶│ SQLite │
|
|
233
|
+
│ storage │ │ (encrypted) │
|
|
234
|
+
└─────────────────┘ └──────────────┘
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Troubleshooting
|
|
238
|
+
|
|
239
|
+
### "EVIDENCEMCP_PASSWORD environment variable required"
|
|
240
|
+
|
|
241
|
+
**Problem**: Server fails to start with this error message.
|
|
242
|
+
|
|
243
|
+
**Solution**:
|
|
244
|
+
1. Ensure `EVIDENCEMCP_PASSWORD` is set in your environment
|
|
245
|
+
2. For Claude Desktop, verify the `env` section in `claude_desktop_config.json`:
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"mcpServers": {
|
|
249
|
+
"evidencemcp": {
|
|
250
|
+
"env": {
|
|
251
|
+
"EVIDENCEMCP_PASSWORD": "your-secure-password"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
3. For command line: `export EVIDENCEMCP_PASSWORD="your-password"`
|
|
258
|
+
4. Never commit passwords to version control
|
|
259
|
+
|
|
260
|
+
### "Database locked" or "SQLITE_BUSY"
|
|
261
|
+
|
|
262
|
+
**Problem**: Multiple processes trying to access the same database file.
|
|
263
|
+
|
|
264
|
+
**Solution**:
|
|
265
|
+
1. Ensure only one EvidenceMCP instance is running
|
|
266
|
+
2. Check for orphaned processes: `ps aux | grep evidencemcp-mcp`
|
|
267
|
+
3. Use unique database paths for different instances:
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"evidencemcp-dev": {
|
|
271
|
+
"env": {
|
|
272
|
+
"EVIDENCEMCP_DB_PATH": "/Users/you/evidencemcp-dev.db"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"evidencemcp-prod": {
|
|
276
|
+
"env": {
|
|
277
|
+
"EVIDENCEMCP_DB_PATH": "/Users/you/evidencemcp-prod.db"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### "Git not found" or "Git command failed"
|
|
284
|
+
|
|
285
|
+
**Problem**: Git timestamp capture fails.
|
|
286
|
+
|
|
287
|
+
**Solution**:
|
|
288
|
+
1. Install Git if not present: `brew install git` (macOS) or `apt-get install git` (Linux)
|
|
289
|
+
2. Verify Git is in PATH: `which git`
|
|
290
|
+
3. Git timestamps are optional - evidence capture will succeed without them
|
|
291
|
+
4. Check `.git` directory exists if running in a repository
|
|
292
|
+
|
|
293
|
+
### "Permission denied" on database file
|
|
294
|
+
|
|
295
|
+
**Problem**: Cannot read/write database file.
|
|
296
|
+
|
|
297
|
+
**Solution**:
|
|
298
|
+
1. Check file permissions: `ls -l /path/to/evidence.db`
|
|
299
|
+
2. Ensure the directory exists and is writable
|
|
300
|
+
3. Verify the user running Claude Desktop has write access
|
|
301
|
+
4. On macOS, grant Full Disk Access if needed (System Settings → Privacy & Security)
|
|
302
|
+
|
|
303
|
+
### "Failed to decrypt evidence" or "Wrong password"
|
|
304
|
+
|
|
305
|
+
**Problem**: Cannot decrypt previously stored evidence.
|
|
306
|
+
|
|
307
|
+
**Solution**:
|
|
308
|
+
1. Verify you're using the same password that was used to encrypt
|
|
309
|
+
2. Passwords are case-sensitive
|
|
310
|
+
3. Check for trailing spaces or special characters in password
|
|
311
|
+
4. If password is lost, evidence cannot be recovered (by design)
|
|
312
|
+
|
|
313
|
+
### "Export failed" or "ZIP creation error"
|
|
314
|
+
|
|
315
|
+
**Problem**: Evidence export fails.
|
|
316
|
+
|
|
317
|
+
**Solution**:
|
|
318
|
+
1. Ensure sufficient disk space
|
|
319
|
+
2. Check write permissions in current directory
|
|
320
|
+
3. Verify evidence IDs exist: use `list-evidences` first
|
|
321
|
+
4. Try exporting single evidence item to isolate the issue
|
|
322
|
+
|
|
323
|
+
### High memory usage
|
|
324
|
+
|
|
325
|
+
**Problem**: Server consuming excessive memory.
|
|
326
|
+
|
|
327
|
+
**Solution**:
|
|
328
|
+
1. Evidence files are loaded into memory during encryption/decryption
|
|
329
|
+
2. For large conversations (>10MB), use pagination with `list-evidences`
|
|
330
|
+
3. Export in smaller batches instead of all at once
|
|
331
|
+
4. Restart Claude Desktop to free memory
|
|
332
|
+
|
|
333
|
+
### TypeScript errors in development
|
|
334
|
+
|
|
335
|
+
**Problem**: TypeScript compilation errors.
|
|
336
|
+
|
|
337
|
+
**Solution**:
|
|
338
|
+
1. Ensure you're using TypeScript 5.9+: `pnpm add -D typescript@^5.9.3`
|
|
339
|
+
2. Clean build artifacts: `pnpm clean && pnpm build`
|
|
340
|
+
3. Check Node.js version: `node --version` (requires 22+)
|
|
341
|
+
4. Verify dependencies: `pnpm install`
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
MIT - See LICENSE file
|
|
346
|
+
|
|
347
|
+
## Support
|
|
348
|
+
|
|
349
|
+
- Issues: https://github.com/evidencemcp/evidencemcp/issues
|
|
350
|
+
- Docs: https://evidencemcp.dev
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import type { ServerConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* EvidenceMCP Server
|
|
5
|
+
*
|
|
6
|
+
* Captures LLM conversations and stores them as encrypted evidence
|
|
7
|
+
* with Git timestamps and export capabilities.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EvidenceMCPServer {
|
|
10
|
+
private server;
|
|
11
|
+
private config;
|
|
12
|
+
private db;
|
|
13
|
+
private derivedKey;
|
|
14
|
+
constructor(config: ServerConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Derive encryption key from password (lazy initialization)
|
|
17
|
+
*/
|
|
18
|
+
private getDerivedKey;
|
|
19
|
+
/**
|
|
20
|
+
* Register MCP tools for evidence management
|
|
21
|
+
*/
|
|
22
|
+
private registerTools;
|
|
23
|
+
/**
|
|
24
|
+
* Register MCP resources for evidence access
|
|
25
|
+
*/
|
|
26
|
+
private registerResources;
|
|
27
|
+
/**
|
|
28
|
+
* Start the MCP server with stdio transport
|
|
29
|
+
*/
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export { EvidenceMCPTestHelpers } from './test-helpers.js';
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAOA,OAAO,KAAK,EAAE,YAAY,EAAyB,MAAM,YAAY,CAAC;AAGtE;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,UAAU,CAA2B;gBAEjC,MAAM,EAAE,YAAY;IAsBhC;;OAEG;YACW,aAAa;IAQ3B;;OAEG;IACH,OAAO,CAAC,aAAa;IA0QrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0CzB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B;AA4BD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { EvidenceDatabase, getCurrentCommit } from '@evidencemcp/storage';
|
|
5
|
+
import { deriveKey, encrypt, decrypt } from '@evidencemcp/crypto';
|
|
6
|
+
import * as z from 'zod';
|
|
7
|
+
import * as crypto from 'crypto';
|
|
8
|
+
/**
|
|
9
|
+
* EvidenceMCP Server
|
|
10
|
+
*
|
|
11
|
+
* Captures LLM conversations and stores them as encrypted evidence
|
|
12
|
+
* with Git timestamps and export capabilities.
|
|
13
|
+
*/
|
|
14
|
+
export class EvidenceMCPServer {
|
|
15
|
+
server;
|
|
16
|
+
config;
|
|
17
|
+
db;
|
|
18
|
+
derivedKey = null;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
try {
|
|
22
|
+
// Initialize database with error handling
|
|
23
|
+
this.db = new EvidenceDatabase(config.dbPath);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
27
|
+
throw new Error(`Failed to initialize database: ${errorMsg}`);
|
|
28
|
+
}
|
|
29
|
+
// Initialize MCP server
|
|
30
|
+
this.server = new McpServer({
|
|
31
|
+
name: config.name || 'traceguard-mcp',
|
|
32
|
+
version: config.version || '0.1.0'
|
|
33
|
+
});
|
|
34
|
+
// Register tools and resources (will implement in later steps)
|
|
35
|
+
this.registerTools();
|
|
36
|
+
this.registerResources();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derive encryption key from password (lazy initialization)
|
|
40
|
+
*/
|
|
41
|
+
async getDerivedKey() {
|
|
42
|
+
if (!this.derivedKey) {
|
|
43
|
+
const result = await deriveKey(this.config.password);
|
|
44
|
+
this.derivedKey = result.key;
|
|
45
|
+
}
|
|
46
|
+
return this.derivedKey;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Register MCP tools for evidence management
|
|
50
|
+
*/
|
|
51
|
+
registerTools() {
|
|
52
|
+
// Tool 1: capture-evidence
|
|
53
|
+
this.server.registerTool('capture-evidence', {
|
|
54
|
+
title: 'Capture Evidence',
|
|
55
|
+
description: 'Capture and encrypt LLM conversation as evidence',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
conversationId: z.string().describe('Conversation ID'),
|
|
58
|
+
llmProvider: z.string().describe('LLM provider name (e.g., Claude Sonnet 4.5)'),
|
|
59
|
+
content: z.string().describe('Conversation content (messages, prompts, responses)'),
|
|
60
|
+
messageCount: z.number().int().positive().describe('Number of messages'),
|
|
61
|
+
tags: z.string().optional().describe('Optional tags (comma-separated)')
|
|
62
|
+
},
|
|
63
|
+
outputSchema: {
|
|
64
|
+
id: z.string(),
|
|
65
|
+
timestamp: z.string(),
|
|
66
|
+
gitCommitHash: z.string().nullable(),
|
|
67
|
+
success: z.boolean()
|
|
68
|
+
}
|
|
69
|
+
}, async (params) => {
|
|
70
|
+
try {
|
|
71
|
+
// Input validation
|
|
72
|
+
if (!params.content || params.content.trim().length === 0) {
|
|
73
|
+
throw new Error('Content cannot be empty');
|
|
74
|
+
}
|
|
75
|
+
if (params.messageCount <= 0) {
|
|
76
|
+
throw new Error('Message count must be positive');
|
|
77
|
+
}
|
|
78
|
+
// Derive encryption key
|
|
79
|
+
const key = await this.getDerivedKey();
|
|
80
|
+
// Encrypt content
|
|
81
|
+
const encrypted = await encrypt(params.content, key);
|
|
82
|
+
// Get Git timestamp
|
|
83
|
+
const gitInfo = await getCurrentCommit();
|
|
84
|
+
// Calculate content hash
|
|
85
|
+
const hash = crypto.createHash('sha256');
|
|
86
|
+
hash.update(params.content);
|
|
87
|
+
const contentHash = hash.digest('hex');
|
|
88
|
+
// Store evidence
|
|
89
|
+
const id = this.db.create({
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
conversationId: params.conversationId,
|
|
92
|
+
llmProvider: params.llmProvider,
|
|
93
|
+
encryptedContent: encrypted.ciphertext,
|
|
94
|
+
nonce: encrypted.nonce,
|
|
95
|
+
contentHash,
|
|
96
|
+
messageCount: params.messageCount,
|
|
97
|
+
gitCommitHash: gitInfo?.commitHash || null,
|
|
98
|
+
gitTimestamp: gitInfo?.timestamp || null,
|
|
99
|
+
tags: params.tags || null
|
|
100
|
+
});
|
|
101
|
+
const output = {
|
|
102
|
+
id,
|
|
103
|
+
timestamp: new Date().toISOString(),
|
|
104
|
+
gitCommitHash: gitInfo?.commitHash || null,
|
|
105
|
+
success: true
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
content: [{
|
|
109
|
+
type: 'text',
|
|
110
|
+
text: `Evidence captured successfully. ID: ${id}`
|
|
111
|
+
}],
|
|
112
|
+
structuredContent: output
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
117
|
+
throw new Error(`[Tool: capture-evidence] ${errorMsg}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Tool 2: list-evidences
|
|
121
|
+
this.server.registerTool('list-evidences', {
|
|
122
|
+
title: 'List Evidences',
|
|
123
|
+
description: 'List all captured evidence with pagination',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
limit: z.number().int().positive().optional().describe('Maximum results'),
|
|
126
|
+
offset: z.number().int().min(0).optional().describe('Pagination offset')
|
|
127
|
+
},
|
|
128
|
+
outputSchema: {
|
|
129
|
+
evidences: z.array(z.object({
|
|
130
|
+
id: z.string(),
|
|
131
|
+
timestamp: z.string(),
|
|
132
|
+
conversationId: z.string(),
|
|
133
|
+
llmProvider: z.string(),
|
|
134
|
+
messageCount: z.number(),
|
|
135
|
+
tags: z.string().nullable()
|
|
136
|
+
})),
|
|
137
|
+
total: z.number()
|
|
138
|
+
}
|
|
139
|
+
}, async (params) => {
|
|
140
|
+
try {
|
|
141
|
+
// Input validation
|
|
142
|
+
if (params.limit !== undefined && params.limit <= 0) {
|
|
143
|
+
throw new Error('Limit must be positive');
|
|
144
|
+
}
|
|
145
|
+
if (params.offset !== undefined && params.offset < 0) {
|
|
146
|
+
throw new Error('Offset cannot be negative');
|
|
147
|
+
}
|
|
148
|
+
const evidences = this.db.list({
|
|
149
|
+
limit: params.limit,
|
|
150
|
+
offset: params.offset
|
|
151
|
+
});
|
|
152
|
+
const output = {
|
|
153
|
+
evidences: evidences.map(e => ({
|
|
154
|
+
id: e.id,
|
|
155
|
+
timestamp: e.timestamp,
|
|
156
|
+
conversationId: e.conversationId,
|
|
157
|
+
llmProvider: e.llmProvider,
|
|
158
|
+
messageCount: e.messageCount,
|
|
159
|
+
tags: e.tags
|
|
160
|
+
})),
|
|
161
|
+
total: evidences.length
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
content: [{
|
|
165
|
+
type: 'text',
|
|
166
|
+
text: `Found ${evidences.length} evidence(s)`
|
|
167
|
+
}],
|
|
168
|
+
structuredContent: output
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
173
|
+
throw new Error(`[Tool: list-evidences] ${errorMsg}`);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
// Tool 3: export-evidences
|
|
177
|
+
this.server.registerTool('export-evidences', {
|
|
178
|
+
title: 'Export Evidences',
|
|
179
|
+
description: 'Export evidences to encrypted ZIP archive',
|
|
180
|
+
inputSchema: {
|
|
181
|
+
evidenceIds: z.array(z.string()).optional().describe('Specific IDs (empty = all)'),
|
|
182
|
+
includeGitInfo: z.boolean().optional().describe('Include Git timestamps')
|
|
183
|
+
},
|
|
184
|
+
outputSchema: {
|
|
185
|
+
filename: z.string(),
|
|
186
|
+
checksum: z.string(),
|
|
187
|
+
evidenceCount: z.number(),
|
|
188
|
+
success: z.boolean()
|
|
189
|
+
}
|
|
190
|
+
}, async (params) => {
|
|
191
|
+
try {
|
|
192
|
+
const { exportEvidences } = await import('@evidencemcp/storage');
|
|
193
|
+
const result = await exportEvidences(this.db, {
|
|
194
|
+
evidenceIds: params.evidenceIds,
|
|
195
|
+
includeGitInfo: params.includeGitInfo ?? false
|
|
196
|
+
});
|
|
197
|
+
// Write ZIP to file
|
|
198
|
+
const fs = await import('fs');
|
|
199
|
+
fs.writeFileSync(result.filename, result.zipData);
|
|
200
|
+
const output = {
|
|
201
|
+
filename: result.filename,
|
|
202
|
+
checksum: result.checksum,
|
|
203
|
+
evidenceCount: result.evidenceCount,
|
|
204
|
+
success: true
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
content: [{
|
|
208
|
+
type: 'text',
|
|
209
|
+
text: `Exported ${result.evidenceCount} evidence(s) to ${result.filename}`
|
|
210
|
+
}],
|
|
211
|
+
structuredContent: output
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
216
|
+
throw new Error(`[Tool: export-evidences] ${errorMsg}`);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
// Tool 4: get-evidence
|
|
220
|
+
this.server.registerTool('get-evidence', {
|
|
221
|
+
title: 'Get Evidence',
|
|
222
|
+
description: 'Retrieve and decrypt specific evidence by ID',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
id: z.string().describe('Evidence ID')
|
|
225
|
+
},
|
|
226
|
+
outputSchema: {
|
|
227
|
+
id: z.string(),
|
|
228
|
+
timestamp: z.string(),
|
|
229
|
+
conversationId: z.string(),
|
|
230
|
+
llmProvider: z.string(),
|
|
231
|
+
content: z.string(),
|
|
232
|
+
messageCount: z.number(),
|
|
233
|
+
gitInfo: z.object({
|
|
234
|
+
commitHash: z.string(),
|
|
235
|
+
timestamp: z.string()
|
|
236
|
+
}).nullable(),
|
|
237
|
+
tags: z.string().nullable()
|
|
238
|
+
}
|
|
239
|
+
}, async (params) => {
|
|
240
|
+
try {
|
|
241
|
+
const evidence = this.db.findById(params.id);
|
|
242
|
+
if (!evidence) {
|
|
243
|
+
throw new Error(`Evidence not found: ${params.id}`);
|
|
244
|
+
}
|
|
245
|
+
// Decrypt content
|
|
246
|
+
const { decrypt } = await import('@evidencemcp/crypto');
|
|
247
|
+
const key = await this.getDerivedKey();
|
|
248
|
+
const decrypted = decrypt(evidence.encryptedContent, evidence.nonce, key);
|
|
249
|
+
const output = {
|
|
250
|
+
id: evidence.id,
|
|
251
|
+
timestamp: evidence.timestamp,
|
|
252
|
+
conversationId: evidence.conversationId,
|
|
253
|
+
llmProvider: evidence.llmProvider,
|
|
254
|
+
content: decrypted,
|
|
255
|
+
messageCount: evidence.messageCount,
|
|
256
|
+
gitInfo: evidence.gitCommitHash ? {
|
|
257
|
+
commitHash: evidence.gitCommitHash,
|
|
258
|
+
timestamp: evidence.gitTimestamp
|
|
259
|
+
} : null,
|
|
260
|
+
tags: evidence.tags
|
|
261
|
+
};
|
|
262
|
+
return {
|
|
263
|
+
content: [{
|
|
264
|
+
type: 'text',
|
|
265
|
+
text: `Evidence ID: ${evidence.id}\nContent: ${decrypted.substring(0, 100)}...`
|
|
266
|
+
}],
|
|
267
|
+
structuredContent: output
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
272
|
+
throw new Error(`[Tool: get-evidence] ${errorMsg}`);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Register MCP resources for evidence access
|
|
278
|
+
*/
|
|
279
|
+
registerResources() {
|
|
280
|
+
// Resource: evidence://{id}
|
|
281
|
+
this.server.registerResource('evidence', new ResourceTemplate('evidence://{id}', { list: undefined }), {
|
|
282
|
+
title: 'Evidence Content',
|
|
283
|
+
description: 'Access encrypted evidence record by ID',
|
|
284
|
+
mimeType: 'text/plain'
|
|
285
|
+
}, async (uri, { id }) => {
|
|
286
|
+
try {
|
|
287
|
+
// Find evidence by ID
|
|
288
|
+
const evidence = this.db.findById(id);
|
|
289
|
+
if (!evidence) {
|
|
290
|
+
throw new Error(`Evidence with ID ${id} not found`);
|
|
291
|
+
}
|
|
292
|
+
// Decrypt content using correct 3-argument signature
|
|
293
|
+
const key = await this.getDerivedKey();
|
|
294
|
+
const decrypted = decrypt(evidence.encryptedContent, evidence.nonce, key);
|
|
295
|
+
return {
|
|
296
|
+
contents: [{
|
|
297
|
+
uri: uri.href,
|
|
298
|
+
mimeType: 'text/plain',
|
|
299
|
+
text: decrypted
|
|
300
|
+
}]
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
305
|
+
throw new Error(`Failed to access evidence resource: ${errorMsg}`);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Start the MCP server with stdio transport
|
|
311
|
+
*/
|
|
312
|
+
async start() {
|
|
313
|
+
const transport = new StdioServerTransport();
|
|
314
|
+
await this.server.connect(transport);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// CLI entry point
|
|
318
|
+
async function main() {
|
|
319
|
+
// Read config from environment variables
|
|
320
|
+
const config = {
|
|
321
|
+
dbPath: process.env.EVIDENCEMCP_DB_PATH || './evidence.db',
|
|
322
|
+
password: process.env.EVIDENCEMCP_PASSWORD || ''
|
|
323
|
+
};
|
|
324
|
+
if (!config.password) {
|
|
325
|
+
console.error('Error: EVIDENCEMCP_PASSWORD environment variable required');
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
const server = new EvidenceMCPServer(config);
|
|
329
|
+
await server.start();
|
|
330
|
+
}
|
|
331
|
+
// Run if called directly
|
|
332
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
333
|
+
main().catch((error) => {
|
|
334
|
+
console.error('Server error:', error);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
// Export test helpers for testing
|
|
339
|
+
export { EvidenceMCPTestHelpers } from './test-helpers.js';
|
|
340
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Helper Utilities for EvidenceMCP Server
|
|
3
|
+
*
|
|
4
|
+
* This module provides type-safe testing utilities without exposing
|
|
5
|
+
* internal implementation details through `as any` casts.
|
|
6
|
+
*/
|
|
7
|
+
import type { EvidenceMCPServer } from './index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Tool information for testing
|
|
10
|
+
*/
|
|
11
|
+
export interface ToolInfo {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resource information for testing
|
|
17
|
+
*/
|
|
18
|
+
export interface ResourceInfo {
|
|
19
|
+
name: string;
|
|
20
|
+
uriTemplate: string;
|
|
21
|
+
description: string;
|
|
22
|
+
mimeType: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Test Helpers for EvidenceMCP Server
|
|
26
|
+
*/
|
|
27
|
+
export declare class EvidenceMCPTestHelpers {
|
|
28
|
+
private server;
|
|
29
|
+
constructor(server: EvidenceMCPServer);
|
|
30
|
+
/**
|
|
31
|
+
* Get list of registered tools (for testing)
|
|
32
|
+
*/
|
|
33
|
+
getTools(): Promise<ToolInfo[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Get list of registered resources (for testing)
|
|
36
|
+
*/
|
|
37
|
+
getResources(): Promise<ResourceInfo[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Read a resource by URI (for testing)
|
|
40
|
+
*/
|
|
41
|
+
readResource(uri: string): Promise<any>;
|
|
42
|
+
/**
|
|
43
|
+
* Execute a tool by name (for testing)
|
|
44
|
+
*/
|
|
45
|
+
executeTool(toolName: string, params: any): Promise<any>;
|
|
46
|
+
/**
|
|
47
|
+
* Call a tool directly (for testing)
|
|
48
|
+
*/
|
|
49
|
+
callTool(name: string, params: any): Promise<any>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwCD;;GAEG;AACH,qBAAa,sBAAsB;IACrB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAE7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAwBrC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IA8B7C;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IA2C7C;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IA4B9D;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;CAQxD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Helper Utilities for EvidenceMCP Server
|
|
3
|
+
*
|
|
4
|
+
* This module provides type-safe testing utilities without exposing
|
|
5
|
+
* internal implementation details through `as any` casts.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Helper to safely access registry using Reflection API
|
|
9
|
+
*/
|
|
10
|
+
function getRegistry(obj, key) {
|
|
11
|
+
return Reflect.get(obj, key);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract items from Map, Array, or Object registry
|
|
15
|
+
*/
|
|
16
|
+
function extractFromRegistry(registry, mapExtractor, arrayExtractor, objectExtractor) {
|
|
17
|
+
if (!registry) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
// Check if it's a Map
|
|
21
|
+
if (registry instanceof Map || (registry && typeof registry.entries === 'function')) {
|
|
22
|
+
return mapExtractor(registry.entries());
|
|
23
|
+
}
|
|
24
|
+
// Check if it's an Array
|
|
25
|
+
if (Array.isArray(registry)) {
|
|
26
|
+
return arrayExtractor(registry);
|
|
27
|
+
}
|
|
28
|
+
// Check if it's an Object
|
|
29
|
+
if (typeof registry === 'object') {
|
|
30
|
+
return objectExtractor(Object.entries(registry));
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Test Helpers for EvidenceMCP Server
|
|
36
|
+
*/
|
|
37
|
+
export class EvidenceMCPTestHelpers {
|
|
38
|
+
server;
|
|
39
|
+
constructor(server) {
|
|
40
|
+
this.server = server;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get list of registered tools (for testing)
|
|
44
|
+
*/
|
|
45
|
+
async getTools() {
|
|
46
|
+
const serverInternal = this.server;
|
|
47
|
+
const tools = getRegistry(serverInternal.server, '_registeredTools');
|
|
48
|
+
return extractFromRegistry(tools,
|
|
49
|
+
// Map extractor
|
|
50
|
+
(entries) => Array.from(entries).map(([name, tool]) => ({
|
|
51
|
+
name,
|
|
52
|
+
description: tool.description || tool.title
|
|
53
|
+
})),
|
|
54
|
+
// Array extractor
|
|
55
|
+
(items) => items.map((tool) => ({
|
|
56
|
+
name: tool.name,
|
|
57
|
+
description: tool.description
|
|
58
|
+
})),
|
|
59
|
+
// Object extractor
|
|
60
|
+
(entries) => entries.map(([name, tool]) => ({
|
|
61
|
+
name,
|
|
62
|
+
description: tool.description || tool.title
|
|
63
|
+
})));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get list of registered resources (for testing)
|
|
67
|
+
*/
|
|
68
|
+
async getResources() {
|
|
69
|
+
const serverInternal = this.server;
|
|
70
|
+
const templates = getRegistry(serverInternal.server, '_registeredResourceTemplates');
|
|
71
|
+
return extractFromRegistry(templates,
|
|
72
|
+
// Map extractor
|
|
73
|
+
(entries) => Array.from(entries).map(([name, template]) => ({
|
|
74
|
+
name,
|
|
75
|
+
uriTemplate: template.uriTemplate,
|
|
76
|
+
description: template.description || '',
|
|
77
|
+
mimeType: template.mimeType || 'text/plain'
|
|
78
|
+
})),
|
|
79
|
+
// Array extractor
|
|
80
|
+
(items) => items.map((template) => ({
|
|
81
|
+
name: template.name,
|
|
82
|
+
uriTemplate: template.uriTemplate,
|
|
83
|
+
description: template.description || '',
|
|
84
|
+
mimeType: template.mimeType || 'text/plain'
|
|
85
|
+
})),
|
|
86
|
+
// Object extractor
|
|
87
|
+
(entries) => entries.map(([name, template]) => ({
|
|
88
|
+
name,
|
|
89
|
+
uriTemplate: template.resourceTemplate?._uriTemplate?.template || template.uriTemplate || '',
|
|
90
|
+
description: template.metadata?.description || template.description || '',
|
|
91
|
+
mimeType: template.metadata?.mimeType || template.mimeType || 'text/plain'
|
|
92
|
+
})));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Read a resource by URI (for testing)
|
|
96
|
+
*/
|
|
97
|
+
async readResource(uri) {
|
|
98
|
+
const serverInternal = this.server;
|
|
99
|
+
const templates = getRegistry(serverInternal.server, '_registeredResourceTemplates');
|
|
100
|
+
if (!templates) {
|
|
101
|
+
throw new Error('No resources registered');
|
|
102
|
+
}
|
|
103
|
+
// Parse URI to get resource name and ID
|
|
104
|
+
const match = uri.match(/^(\w+):\/\/(.+)$/);
|
|
105
|
+
if (!match) {
|
|
106
|
+
throw new Error('Unknown resource');
|
|
107
|
+
}
|
|
108
|
+
const [, resourceName, id] = match;
|
|
109
|
+
// Find matching template
|
|
110
|
+
let handler = null;
|
|
111
|
+
if (templates instanceof Map) {
|
|
112
|
+
handler = templates.get(resourceName);
|
|
113
|
+
}
|
|
114
|
+
else if (Array.isArray(templates)) {
|
|
115
|
+
handler = templates.find((t) => t.name === resourceName);
|
|
116
|
+
}
|
|
117
|
+
else if (typeof templates === 'object') {
|
|
118
|
+
handler = templates[resourceName];
|
|
119
|
+
}
|
|
120
|
+
if (!handler) {
|
|
121
|
+
throw new Error('Unknown resource');
|
|
122
|
+
}
|
|
123
|
+
// The handler might be in readCallback or handler field
|
|
124
|
+
const handlerFn = handler.readCallback || handler.handler;
|
|
125
|
+
if (!handlerFn) {
|
|
126
|
+
throw new Error('Unknown resource');
|
|
127
|
+
}
|
|
128
|
+
// Call the handler with parsed parameters
|
|
129
|
+
const result = await handlerFn({ href: uri }, { id });
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Execute a tool by name (for testing)
|
|
134
|
+
*/
|
|
135
|
+
async executeTool(toolName, params) {
|
|
136
|
+
const serverInternal = this.server;
|
|
137
|
+
const tools = getRegistry(serverInternal.server, '_registeredTools');
|
|
138
|
+
if (!tools) {
|
|
139
|
+
throw new Error('No tools registered');
|
|
140
|
+
}
|
|
141
|
+
// Find the tool
|
|
142
|
+
let tool = null;
|
|
143
|
+
if (tools instanceof Map) {
|
|
144
|
+
tool = tools.get(toolName);
|
|
145
|
+
}
|
|
146
|
+
else if (Array.isArray(tools)) {
|
|
147
|
+
tool = tools.find((t) => t.name === toolName);
|
|
148
|
+
}
|
|
149
|
+
else if (typeof tools === 'object') {
|
|
150
|
+
tool = tools[toolName];
|
|
151
|
+
}
|
|
152
|
+
if (!tool || !tool.handler) {
|
|
153
|
+
throw new Error(`Tool ${toolName} not found`);
|
|
154
|
+
}
|
|
155
|
+
// Execute the tool handler
|
|
156
|
+
const result = await tool.handler(params);
|
|
157
|
+
return result.structuredContent || result;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Call a tool directly (for testing)
|
|
161
|
+
*/
|
|
162
|
+
async callTool(name, params) {
|
|
163
|
+
const result = await this.executeTool(name, params);
|
|
164
|
+
// Wrap in expected response format for compatibility
|
|
165
|
+
return {
|
|
166
|
+
structuredContent: result
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for EvidenceMCP Server
|
|
3
|
+
*/
|
|
4
|
+
export interface ServerConfig {
|
|
5
|
+
/** Path to encrypted evidence database */
|
|
6
|
+
dbPath: string;
|
|
7
|
+
/** Password for encrypting/decrypting evidence */
|
|
8
|
+
password: string;
|
|
9
|
+
/** Server name (for MCP protocol) */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** Server version */
|
|
12
|
+
version?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Evidence capture request parameters
|
|
16
|
+
*/
|
|
17
|
+
export interface CaptureEvidenceParams {
|
|
18
|
+
/** Conversation ID (e.g., Claude session ID) */
|
|
19
|
+
conversationId: string;
|
|
20
|
+
/** LLM provider name */
|
|
21
|
+
llmProvider: string;
|
|
22
|
+
/** Conversation content (messages, prompts, responses) */
|
|
23
|
+
content: string;
|
|
24
|
+
/** Number of messages in conversation */
|
|
25
|
+
messageCount: number;
|
|
26
|
+
/** Optional tags for categorization */
|
|
27
|
+
tags?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Evidence list request parameters
|
|
31
|
+
*/
|
|
32
|
+
export interface ListEvidencesParams {
|
|
33
|
+
/** Maximum number of results */
|
|
34
|
+
limit?: number;
|
|
35
|
+
/** Offset for pagination */
|
|
36
|
+
offset?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Evidence export request parameters
|
|
40
|
+
*/
|
|
41
|
+
export interface ExportEvidencesParams {
|
|
42
|
+
/** Specific evidence IDs to export (empty = all) */
|
|
43
|
+
evidenceIds?: string[];
|
|
44
|
+
/** Include git info in export */
|
|
45
|
+
includeGitInfo?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get evidence request parameters
|
|
49
|
+
*/
|
|
50
|
+
export interface GetEvidenceParams {
|
|
51
|
+
/** Evidence ID to retrieve */
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IAEf,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IAEjB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,cAAc,EAAE,MAAM,CAAC;IAEvB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IAEpB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAEhB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IAErB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB,iCAAiC;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pcircle/evidencemcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model Context Protocol (MCP) server for EvidenceMCP - automatically capture and encrypt LLM conversations as legal evidence with Git timestamps",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"llm",
|
|
9
|
+
"evidence",
|
|
10
|
+
"encryption",
|
|
11
|
+
"evidencemcp",
|
|
12
|
+
"claude",
|
|
13
|
+
"chatgpt",
|
|
14
|
+
"legal",
|
|
15
|
+
"audit",
|
|
16
|
+
"timestamp"
|
|
17
|
+
],
|
|
18
|
+
"author": "PCIRCLE, LLC",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"bin": {
|
|
24
|
+
"evidencemcp": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/PCIRCLE-AI/evidencemcp-server.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/PCIRCLE-AI/evidencemcp-server/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://evidencemcp.cc",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"dev": "tsc --watch",
|
|
42
|
+
"test": "vitest",
|
|
43
|
+
"test:run": "vitest run",
|
|
44
|
+
"clean": "rm -rf dist",
|
|
45
|
+
"prepublishOnly": "pnpm clean && pnpm build && pnpm test:run"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
49
|
+
"@evidencemcp/crypto": "workspace:*",
|
|
50
|
+
"@evidencemcp/storage": "workspace:*",
|
|
51
|
+
"zod": "^3.23.8"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^22.10.5",
|
|
55
|
+
"tsx": "^4.21.0",
|
|
56
|
+
"typescript": "^5.9.3",
|
|
57
|
+
"vitest": "^1.6.1"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=22.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|