@rovn-ai/mcp-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/README.md +64 -0
- package/dist/server.d.ts +577 -0
- package/dist/server.js +436 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @rovn/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for [Rovn](https://rovn.io) — AI Agent governance tools for Claude, GPT, Cursor, and any MCP-compatible agent.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @rovn/mcp-server --url https://rovn.io --email you@example.com
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with an existing API key:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @rovn/mcp-server --url https://rovn.io --api-key rovn_...
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Claude Desktop / Claude Code Config
|
|
18
|
+
|
|
19
|
+
Add to your MCP configuration:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"rovn": {
|
|
25
|
+
"command": "npx",
|
|
26
|
+
"args": ["@rovn/mcp-server", "--url", "https://rovn.io", "--email", "you@example.com"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Available Tools
|
|
33
|
+
|
|
34
|
+
| Tool | Description |
|
|
35
|
+
|------|-------------|
|
|
36
|
+
| `rovn_register` | Register agent with Rovn. Returns API key and agent ID. |
|
|
37
|
+
| `rovn_log_activity` | Log what the agent has done. |
|
|
38
|
+
| `rovn_check_action` | Pre-flight check — is this action allowed? |
|
|
39
|
+
| `rovn_request_approval` | Request owner approval for risky actions. |
|
|
40
|
+
| `rovn_get_tasks` | Get tasks assigned to this agent. |
|
|
41
|
+
| `rovn_update_task` | Update task status. |
|
|
42
|
+
| `rovn_get_report_card` | Get performance report card with grades. |
|
|
43
|
+
| `rovn_get_trust_score` | Get Trust Score (0-100). |
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Zero dependencies** — uses only Node.js built-in APIs
|
|
48
|
+
- **Auto-logging** — governance tool calls are automatically recorded
|
|
49
|
+
- **HTTP hardening** — 15s timeout, status-specific error messages, safe JSON parsing
|
|
50
|
+
- **Register reuse** — validates existing credentials before re-registering
|
|
51
|
+
- **29 tests** — comprehensive test coverage
|
|
52
|
+
|
|
53
|
+
## CLI Arguments
|
|
54
|
+
|
|
55
|
+
| Flag | Env Variable | Default | Description |
|
|
56
|
+
|------|-------------|---------|-------------|
|
|
57
|
+
| `--url` | `ROVN_URL` | `https://rovn.io` | Rovn server URL |
|
|
58
|
+
| `--email` | `ROVN_OWNER_EMAIL` | — | Owner email for agent registration |
|
|
59
|
+
| `--api-key` | `ROVN_API_KEY` | — | Existing API key |
|
|
60
|
+
| `--agent-id` | `ROVN_AGENT_ID` | — | Existing agent ID |
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Rovn MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes Rovn governance tools via the Model Context Protocol (MCP).
|
|
6
|
+
* Any MCP-compatible agent (Claude, Cursor, GPT, etc.) can use these tools
|
|
7
|
+
* to register, report activities, check policies, and request approvals.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx @rovn/mcp-server --url https://rovn.io --email owner@example.com
|
|
11
|
+
*
|
|
12
|
+
* Or with an existing API key:
|
|
13
|
+
* npx @rovn/mcp-server --url https://rovn.io --api-key rovn_...
|
|
14
|
+
*
|
|
15
|
+
* Claude Desktop / Claude Code config:
|
|
16
|
+
* {
|
|
17
|
+
* "mcpServers": {
|
|
18
|
+
* "rovn": {
|
|
19
|
+
* "command": "npx",
|
|
20
|
+
* "args": ["@rovn/mcp-server", "--url", "https://rovn.io", "--email", "me@example.com"]
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
export interface ServerConfig {
|
|
26
|
+
rovnUrl: string;
|
|
27
|
+
ownerEmail: string;
|
|
28
|
+
apiKey: string;
|
|
29
|
+
agentId: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function getArg(args: string[], flag: string): string | undefined;
|
|
32
|
+
export declare function createConfig(args: string[]): ServerConfig;
|
|
33
|
+
export declare function requireAgent(cfg: ServerConfig): string | null;
|
|
34
|
+
export declare function rovnPost(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
35
|
+
export declare function rovnGet(path: string): Promise<Record<string, unknown>>;
|
|
36
|
+
export declare function rovnPatch(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
37
|
+
export declare const TOOLS: ({
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: "object";
|
|
42
|
+
properties: {
|
|
43
|
+
name: {
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
};
|
|
47
|
+
description: {
|
|
48
|
+
type: string;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
type: {
|
|
52
|
+
type: string;
|
|
53
|
+
description: string;
|
|
54
|
+
};
|
|
55
|
+
capabilities: {
|
|
56
|
+
type: string;
|
|
57
|
+
items: {
|
|
58
|
+
type: string;
|
|
59
|
+
};
|
|
60
|
+
description: string;
|
|
61
|
+
};
|
|
62
|
+
title?: undefined;
|
|
63
|
+
metadata?: undefined;
|
|
64
|
+
action?: undefined;
|
|
65
|
+
context?: undefined;
|
|
66
|
+
urgency?: undefined;
|
|
67
|
+
cost?: undefined;
|
|
68
|
+
status?: undefined;
|
|
69
|
+
task_id?: undefined;
|
|
70
|
+
days?: undefined;
|
|
71
|
+
};
|
|
72
|
+
required: string[];
|
|
73
|
+
};
|
|
74
|
+
} | {
|
|
75
|
+
name: string;
|
|
76
|
+
description: string;
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object";
|
|
79
|
+
properties: {
|
|
80
|
+
title: {
|
|
81
|
+
type: string;
|
|
82
|
+
description: string;
|
|
83
|
+
};
|
|
84
|
+
type: {
|
|
85
|
+
type: string;
|
|
86
|
+
description: string;
|
|
87
|
+
};
|
|
88
|
+
description: {
|
|
89
|
+
type: string;
|
|
90
|
+
description: string;
|
|
91
|
+
};
|
|
92
|
+
metadata: {
|
|
93
|
+
type: string;
|
|
94
|
+
description: string;
|
|
95
|
+
};
|
|
96
|
+
name?: undefined;
|
|
97
|
+
capabilities?: undefined;
|
|
98
|
+
action?: undefined;
|
|
99
|
+
context?: undefined;
|
|
100
|
+
urgency?: undefined;
|
|
101
|
+
cost?: undefined;
|
|
102
|
+
status?: undefined;
|
|
103
|
+
task_id?: undefined;
|
|
104
|
+
days?: undefined;
|
|
105
|
+
};
|
|
106
|
+
required: string[];
|
|
107
|
+
};
|
|
108
|
+
} | {
|
|
109
|
+
name: string;
|
|
110
|
+
description: string;
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object";
|
|
113
|
+
properties: {
|
|
114
|
+
action: {
|
|
115
|
+
type: string;
|
|
116
|
+
description: string;
|
|
117
|
+
};
|
|
118
|
+
context: {
|
|
119
|
+
type: string;
|
|
120
|
+
description: string;
|
|
121
|
+
};
|
|
122
|
+
urgency: {
|
|
123
|
+
type: string;
|
|
124
|
+
enum: string[];
|
|
125
|
+
description: string;
|
|
126
|
+
};
|
|
127
|
+
cost: {
|
|
128
|
+
type: string;
|
|
129
|
+
description: string;
|
|
130
|
+
};
|
|
131
|
+
name?: undefined;
|
|
132
|
+
description?: undefined;
|
|
133
|
+
type?: undefined;
|
|
134
|
+
capabilities?: undefined;
|
|
135
|
+
title?: undefined;
|
|
136
|
+
metadata?: undefined;
|
|
137
|
+
status?: undefined;
|
|
138
|
+
task_id?: undefined;
|
|
139
|
+
days?: undefined;
|
|
140
|
+
};
|
|
141
|
+
required: string[];
|
|
142
|
+
};
|
|
143
|
+
} | {
|
|
144
|
+
name: string;
|
|
145
|
+
description: string;
|
|
146
|
+
inputSchema: {
|
|
147
|
+
type: "object";
|
|
148
|
+
properties: {
|
|
149
|
+
title: {
|
|
150
|
+
type: string;
|
|
151
|
+
description: string;
|
|
152
|
+
};
|
|
153
|
+
type: {
|
|
154
|
+
type: string;
|
|
155
|
+
description: string;
|
|
156
|
+
};
|
|
157
|
+
description: {
|
|
158
|
+
type: string;
|
|
159
|
+
description: string;
|
|
160
|
+
};
|
|
161
|
+
urgency: {
|
|
162
|
+
type: string;
|
|
163
|
+
enum: string[];
|
|
164
|
+
description: string;
|
|
165
|
+
};
|
|
166
|
+
name?: undefined;
|
|
167
|
+
capabilities?: undefined;
|
|
168
|
+
metadata?: undefined;
|
|
169
|
+
action?: undefined;
|
|
170
|
+
context?: undefined;
|
|
171
|
+
cost?: undefined;
|
|
172
|
+
status?: undefined;
|
|
173
|
+
task_id?: undefined;
|
|
174
|
+
days?: undefined;
|
|
175
|
+
};
|
|
176
|
+
required: string[];
|
|
177
|
+
};
|
|
178
|
+
} | {
|
|
179
|
+
name: string;
|
|
180
|
+
description: string;
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: "object";
|
|
183
|
+
properties: {
|
|
184
|
+
status: {
|
|
185
|
+
type: string;
|
|
186
|
+
enum: string[];
|
|
187
|
+
description: string;
|
|
188
|
+
};
|
|
189
|
+
name?: undefined;
|
|
190
|
+
description?: undefined;
|
|
191
|
+
type?: undefined;
|
|
192
|
+
capabilities?: undefined;
|
|
193
|
+
title?: undefined;
|
|
194
|
+
metadata?: undefined;
|
|
195
|
+
action?: undefined;
|
|
196
|
+
context?: undefined;
|
|
197
|
+
urgency?: undefined;
|
|
198
|
+
cost?: undefined;
|
|
199
|
+
task_id?: undefined;
|
|
200
|
+
days?: undefined;
|
|
201
|
+
};
|
|
202
|
+
required?: undefined;
|
|
203
|
+
};
|
|
204
|
+
} | {
|
|
205
|
+
name: string;
|
|
206
|
+
description: string;
|
|
207
|
+
inputSchema: {
|
|
208
|
+
type: "object";
|
|
209
|
+
properties: {
|
|
210
|
+
task_id: {
|
|
211
|
+
type: string;
|
|
212
|
+
description: string;
|
|
213
|
+
};
|
|
214
|
+
status: {
|
|
215
|
+
type: string;
|
|
216
|
+
enum: string[];
|
|
217
|
+
description: string;
|
|
218
|
+
};
|
|
219
|
+
name?: undefined;
|
|
220
|
+
description?: undefined;
|
|
221
|
+
type?: undefined;
|
|
222
|
+
capabilities?: undefined;
|
|
223
|
+
title?: undefined;
|
|
224
|
+
metadata?: undefined;
|
|
225
|
+
action?: undefined;
|
|
226
|
+
context?: undefined;
|
|
227
|
+
urgency?: undefined;
|
|
228
|
+
cost?: undefined;
|
|
229
|
+
days?: undefined;
|
|
230
|
+
};
|
|
231
|
+
required: string[];
|
|
232
|
+
};
|
|
233
|
+
} | {
|
|
234
|
+
name: string;
|
|
235
|
+
description: string;
|
|
236
|
+
inputSchema: {
|
|
237
|
+
type: "object";
|
|
238
|
+
properties: {
|
|
239
|
+
days: {
|
|
240
|
+
type: string;
|
|
241
|
+
description: string;
|
|
242
|
+
};
|
|
243
|
+
name?: undefined;
|
|
244
|
+
description?: undefined;
|
|
245
|
+
type?: undefined;
|
|
246
|
+
capabilities?: undefined;
|
|
247
|
+
title?: undefined;
|
|
248
|
+
metadata?: undefined;
|
|
249
|
+
action?: undefined;
|
|
250
|
+
context?: undefined;
|
|
251
|
+
urgency?: undefined;
|
|
252
|
+
cost?: undefined;
|
|
253
|
+
status?: undefined;
|
|
254
|
+
task_id?: undefined;
|
|
255
|
+
};
|
|
256
|
+
required?: undefined;
|
|
257
|
+
};
|
|
258
|
+
} | {
|
|
259
|
+
name: string;
|
|
260
|
+
description: string;
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: "object";
|
|
263
|
+
properties: {
|
|
264
|
+
name?: undefined;
|
|
265
|
+
description?: undefined;
|
|
266
|
+
type?: undefined;
|
|
267
|
+
capabilities?: undefined;
|
|
268
|
+
title?: undefined;
|
|
269
|
+
metadata?: undefined;
|
|
270
|
+
action?: undefined;
|
|
271
|
+
context?: undefined;
|
|
272
|
+
urgency?: undefined;
|
|
273
|
+
cost?: undefined;
|
|
274
|
+
status?: undefined;
|
|
275
|
+
task_id?: undefined;
|
|
276
|
+
days?: undefined;
|
|
277
|
+
};
|
|
278
|
+
required?: undefined;
|
|
279
|
+
};
|
|
280
|
+
})[];
|
|
281
|
+
export declare function handleRequest(request: {
|
|
282
|
+
id: number;
|
|
283
|
+
method: string;
|
|
284
|
+
params?: Record<string, unknown>;
|
|
285
|
+
}): Promise<{
|
|
286
|
+
content: {
|
|
287
|
+
type: string;
|
|
288
|
+
text: string;
|
|
289
|
+
}[];
|
|
290
|
+
isError: boolean;
|
|
291
|
+
} | {
|
|
292
|
+
protocolVersion: string;
|
|
293
|
+
capabilities: {
|
|
294
|
+
tools: {};
|
|
295
|
+
};
|
|
296
|
+
serverInfo: {
|
|
297
|
+
name: string;
|
|
298
|
+
version: string;
|
|
299
|
+
};
|
|
300
|
+
tools?: undefined;
|
|
301
|
+
error?: undefined;
|
|
302
|
+
} | {
|
|
303
|
+
tools: ({
|
|
304
|
+
name: string;
|
|
305
|
+
description: string;
|
|
306
|
+
inputSchema: {
|
|
307
|
+
type: "object";
|
|
308
|
+
properties: {
|
|
309
|
+
name: {
|
|
310
|
+
type: string;
|
|
311
|
+
description: string;
|
|
312
|
+
};
|
|
313
|
+
description: {
|
|
314
|
+
type: string;
|
|
315
|
+
description: string;
|
|
316
|
+
};
|
|
317
|
+
type: {
|
|
318
|
+
type: string;
|
|
319
|
+
description: string;
|
|
320
|
+
};
|
|
321
|
+
capabilities: {
|
|
322
|
+
type: string;
|
|
323
|
+
items: {
|
|
324
|
+
type: string;
|
|
325
|
+
};
|
|
326
|
+
description: string;
|
|
327
|
+
};
|
|
328
|
+
title?: undefined;
|
|
329
|
+
metadata?: undefined;
|
|
330
|
+
action?: undefined;
|
|
331
|
+
context?: undefined;
|
|
332
|
+
urgency?: undefined;
|
|
333
|
+
cost?: undefined;
|
|
334
|
+
status?: undefined;
|
|
335
|
+
task_id?: undefined;
|
|
336
|
+
days?: undefined;
|
|
337
|
+
};
|
|
338
|
+
required: string[];
|
|
339
|
+
};
|
|
340
|
+
} | {
|
|
341
|
+
name: string;
|
|
342
|
+
description: string;
|
|
343
|
+
inputSchema: {
|
|
344
|
+
type: "object";
|
|
345
|
+
properties: {
|
|
346
|
+
title: {
|
|
347
|
+
type: string;
|
|
348
|
+
description: string;
|
|
349
|
+
};
|
|
350
|
+
type: {
|
|
351
|
+
type: string;
|
|
352
|
+
description: string;
|
|
353
|
+
};
|
|
354
|
+
description: {
|
|
355
|
+
type: string;
|
|
356
|
+
description: string;
|
|
357
|
+
};
|
|
358
|
+
metadata: {
|
|
359
|
+
type: string;
|
|
360
|
+
description: string;
|
|
361
|
+
};
|
|
362
|
+
name?: undefined;
|
|
363
|
+
capabilities?: undefined;
|
|
364
|
+
action?: undefined;
|
|
365
|
+
context?: undefined;
|
|
366
|
+
urgency?: undefined;
|
|
367
|
+
cost?: undefined;
|
|
368
|
+
status?: undefined;
|
|
369
|
+
task_id?: undefined;
|
|
370
|
+
days?: undefined;
|
|
371
|
+
};
|
|
372
|
+
required: string[];
|
|
373
|
+
};
|
|
374
|
+
} | {
|
|
375
|
+
name: string;
|
|
376
|
+
description: string;
|
|
377
|
+
inputSchema: {
|
|
378
|
+
type: "object";
|
|
379
|
+
properties: {
|
|
380
|
+
action: {
|
|
381
|
+
type: string;
|
|
382
|
+
description: string;
|
|
383
|
+
};
|
|
384
|
+
context: {
|
|
385
|
+
type: string;
|
|
386
|
+
description: string;
|
|
387
|
+
};
|
|
388
|
+
urgency: {
|
|
389
|
+
type: string;
|
|
390
|
+
enum: string[];
|
|
391
|
+
description: string;
|
|
392
|
+
};
|
|
393
|
+
cost: {
|
|
394
|
+
type: string;
|
|
395
|
+
description: string;
|
|
396
|
+
};
|
|
397
|
+
name?: undefined;
|
|
398
|
+
description?: undefined;
|
|
399
|
+
type?: undefined;
|
|
400
|
+
capabilities?: undefined;
|
|
401
|
+
title?: undefined;
|
|
402
|
+
metadata?: undefined;
|
|
403
|
+
status?: undefined;
|
|
404
|
+
task_id?: undefined;
|
|
405
|
+
days?: undefined;
|
|
406
|
+
};
|
|
407
|
+
required: string[];
|
|
408
|
+
};
|
|
409
|
+
} | {
|
|
410
|
+
name: string;
|
|
411
|
+
description: string;
|
|
412
|
+
inputSchema: {
|
|
413
|
+
type: "object";
|
|
414
|
+
properties: {
|
|
415
|
+
title: {
|
|
416
|
+
type: string;
|
|
417
|
+
description: string;
|
|
418
|
+
};
|
|
419
|
+
type: {
|
|
420
|
+
type: string;
|
|
421
|
+
description: string;
|
|
422
|
+
};
|
|
423
|
+
description: {
|
|
424
|
+
type: string;
|
|
425
|
+
description: string;
|
|
426
|
+
};
|
|
427
|
+
urgency: {
|
|
428
|
+
type: string;
|
|
429
|
+
enum: string[];
|
|
430
|
+
description: string;
|
|
431
|
+
};
|
|
432
|
+
name?: undefined;
|
|
433
|
+
capabilities?: undefined;
|
|
434
|
+
metadata?: undefined;
|
|
435
|
+
action?: undefined;
|
|
436
|
+
context?: undefined;
|
|
437
|
+
cost?: undefined;
|
|
438
|
+
status?: undefined;
|
|
439
|
+
task_id?: undefined;
|
|
440
|
+
days?: undefined;
|
|
441
|
+
};
|
|
442
|
+
required: string[];
|
|
443
|
+
};
|
|
444
|
+
} | {
|
|
445
|
+
name: string;
|
|
446
|
+
description: string;
|
|
447
|
+
inputSchema: {
|
|
448
|
+
type: "object";
|
|
449
|
+
properties: {
|
|
450
|
+
status: {
|
|
451
|
+
type: string;
|
|
452
|
+
enum: string[];
|
|
453
|
+
description: string;
|
|
454
|
+
};
|
|
455
|
+
name?: undefined;
|
|
456
|
+
description?: undefined;
|
|
457
|
+
type?: undefined;
|
|
458
|
+
capabilities?: undefined;
|
|
459
|
+
title?: undefined;
|
|
460
|
+
metadata?: undefined;
|
|
461
|
+
action?: undefined;
|
|
462
|
+
context?: undefined;
|
|
463
|
+
urgency?: undefined;
|
|
464
|
+
cost?: undefined;
|
|
465
|
+
task_id?: undefined;
|
|
466
|
+
days?: undefined;
|
|
467
|
+
};
|
|
468
|
+
required?: undefined;
|
|
469
|
+
};
|
|
470
|
+
} | {
|
|
471
|
+
name: string;
|
|
472
|
+
description: string;
|
|
473
|
+
inputSchema: {
|
|
474
|
+
type: "object";
|
|
475
|
+
properties: {
|
|
476
|
+
task_id: {
|
|
477
|
+
type: string;
|
|
478
|
+
description: string;
|
|
479
|
+
};
|
|
480
|
+
status: {
|
|
481
|
+
type: string;
|
|
482
|
+
enum: string[];
|
|
483
|
+
description: string;
|
|
484
|
+
};
|
|
485
|
+
name?: undefined;
|
|
486
|
+
description?: undefined;
|
|
487
|
+
type?: undefined;
|
|
488
|
+
capabilities?: undefined;
|
|
489
|
+
title?: undefined;
|
|
490
|
+
metadata?: undefined;
|
|
491
|
+
action?: undefined;
|
|
492
|
+
context?: undefined;
|
|
493
|
+
urgency?: undefined;
|
|
494
|
+
cost?: undefined;
|
|
495
|
+
days?: undefined;
|
|
496
|
+
};
|
|
497
|
+
required: string[];
|
|
498
|
+
};
|
|
499
|
+
} | {
|
|
500
|
+
name: string;
|
|
501
|
+
description: string;
|
|
502
|
+
inputSchema: {
|
|
503
|
+
type: "object";
|
|
504
|
+
properties: {
|
|
505
|
+
days: {
|
|
506
|
+
type: string;
|
|
507
|
+
description: string;
|
|
508
|
+
};
|
|
509
|
+
name?: undefined;
|
|
510
|
+
description?: undefined;
|
|
511
|
+
type?: undefined;
|
|
512
|
+
capabilities?: undefined;
|
|
513
|
+
title?: undefined;
|
|
514
|
+
metadata?: undefined;
|
|
515
|
+
action?: undefined;
|
|
516
|
+
context?: undefined;
|
|
517
|
+
urgency?: undefined;
|
|
518
|
+
cost?: undefined;
|
|
519
|
+
status?: undefined;
|
|
520
|
+
task_id?: undefined;
|
|
521
|
+
};
|
|
522
|
+
required?: undefined;
|
|
523
|
+
};
|
|
524
|
+
} | {
|
|
525
|
+
name: string;
|
|
526
|
+
description: string;
|
|
527
|
+
inputSchema: {
|
|
528
|
+
type: "object";
|
|
529
|
+
properties: {
|
|
530
|
+
name?: undefined;
|
|
531
|
+
description?: undefined;
|
|
532
|
+
type?: undefined;
|
|
533
|
+
capabilities?: undefined;
|
|
534
|
+
title?: undefined;
|
|
535
|
+
metadata?: undefined;
|
|
536
|
+
action?: undefined;
|
|
537
|
+
context?: undefined;
|
|
538
|
+
urgency?: undefined;
|
|
539
|
+
cost?: undefined;
|
|
540
|
+
status?: undefined;
|
|
541
|
+
task_id?: undefined;
|
|
542
|
+
days?: undefined;
|
|
543
|
+
};
|
|
544
|
+
required?: undefined;
|
|
545
|
+
};
|
|
546
|
+
})[];
|
|
547
|
+
protocolVersion?: undefined;
|
|
548
|
+
capabilities?: undefined;
|
|
549
|
+
serverInfo?: undefined;
|
|
550
|
+
error?: undefined;
|
|
551
|
+
} | {
|
|
552
|
+
error: {
|
|
553
|
+
code: number;
|
|
554
|
+
message: string;
|
|
555
|
+
};
|
|
556
|
+
protocolVersion?: undefined;
|
|
557
|
+
capabilities?: undefined;
|
|
558
|
+
serverInfo?: undefined;
|
|
559
|
+
tools?: undefined;
|
|
560
|
+
} | null>;
|
|
561
|
+
export declare function handleToolCall(params: {
|
|
562
|
+
name: string;
|
|
563
|
+
arguments: Record<string, unknown>;
|
|
564
|
+
}): Promise<{
|
|
565
|
+
content: {
|
|
566
|
+
type: string;
|
|
567
|
+
text: string;
|
|
568
|
+
}[];
|
|
569
|
+
isError: boolean;
|
|
570
|
+
}>;
|
|
571
|
+
export declare function toolResult(res: Record<string, unknown>): {
|
|
572
|
+
content: {
|
|
573
|
+
type: string;
|
|
574
|
+
text: string;
|
|
575
|
+
}[];
|
|
576
|
+
isError: boolean;
|
|
577
|
+
};
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Rovn MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Exposes Rovn governance tools via the Model Context Protocol (MCP).
|
|
7
|
+
* Any MCP-compatible agent (Claude, Cursor, GPT, etc.) can use these tools
|
|
8
|
+
* to register, report activities, check policies, and request approvals.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* npx @rovn/mcp-server --url https://rovn.io --email owner@example.com
|
|
12
|
+
*
|
|
13
|
+
* Or with an existing API key:
|
|
14
|
+
* npx @rovn/mcp-server --url https://rovn.io --api-key rovn_...
|
|
15
|
+
*
|
|
16
|
+
* Claude Desktop / Claude Code config:
|
|
17
|
+
* {
|
|
18
|
+
* "mcpServers": {
|
|
19
|
+
* "rovn": {
|
|
20
|
+
* "command": "npx",
|
|
21
|
+
* "args": ["@rovn/mcp-server", "--url", "https://rovn.io", "--email", "me@example.com"]
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.TOOLS = void 0;
|
|
28
|
+
exports.getArg = getArg;
|
|
29
|
+
exports.createConfig = createConfig;
|
|
30
|
+
exports.requireAgent = requireAgent;
|
|
31
|
+
exports.rovnPost = rovnPost;
|
|
32
|
+
exports.rovnGet = rovnGet;
|
|
33
|
+
exports.rovnPatch = rovnPatch;
|
|
34
|
+
exports.handleRequest = handleRequest;
|
|
35
|
+
exports.handleToolCall = handleToolCall;
|
|
36
|
+
exports.toolResult = toolResult;
|
|
37
|
+
const readline_1 = require("readline");
|
|
38
|
+
function getArg(args, flag) {
|
|
39
|
+
const idx = args.indexOf(flag);
|
|
40
|
+
return idx >= 0 ? args[idx + 1] : undefined;
|
|
41
|
+
}
|
|
42
|
+
function createConfig(args) {
|
|
43
|
+
return {
|
|
44
|
+
rovnUrl: getArg(args, '--url') ?? process.env.ROVN_URL ?? 'https://rovn.io',
|
|
45
|
+
ownerEmail: getArg(args, '--email') ?? process.env.ROVN_OWNER_EMAIL ?? '',
|
|
46
|
+
apiKey: getArg(args, '--api-key') ?? process.env.ROVN_API_KEY ?? '',
|
|
47
|
+
agentId: getArg(args, '--agent-id') ?? process.env.ROVN_AGENT_ID ?? '',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const config = createConfig(process.argv.slice(2));
|
|
51
|
+
function requireAgent(cfg) {
|
|
52
|
+
if (!cfg.agentId || !cfg.apiKey) {
|
|
53
|
+
return 'Not registered. Call rovn_register first.';
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
// ─── HTTP Client (hardened) ─────────────────────────────────
|
|
58
|
+
const HTTP_TIMEOUT = 15000;
|
|
59
|
+
function httpStatusMessage(status) {
|
|
60
|
+
if (status === 401 || status === 403)
|
|
61
|
+
return 'Authentication failed — check your API key or call rovn_register';
|
|
62
|
+
if (status === 404)
|
|
63
|
+
return 'Resource not found';
|
|
64
|
+
if (status >= 500)
|
|
65
|
+
return `Server error (${status}) — try again later`;
|
|
66
|
+
return `Request failed (${status})`;
|
|
67
|
+
}
|
|
68
|
+
async function safeFetch(url, init) {
|
|
69
|
+
let res;
|
|
70
|
+
try {
|
|
71
|
+
res = await fetch(url, {
|
|
72
|
+
...init,
|
|
73
|
+
signal: AbortSignal.timeout(HTTP_TIMEOUT),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (err instanceof DOMException && err.name === 'TimeoutError') {
|
|
78
|
+
return { success: false, error: 'Request timed out — check your network connection' };
|
|
79
|
+
}
|
|
80
|
+
return { success: false, error: 'Could not connect to server — verify the URL and network' };
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
let serverMsg = '';
|
|
84
|
+
try {
|
|
85
|
+
const body = await res.json();
|
|
86
|
+
serverMsg = body.error ?? '';
|
|
87
|
+
}
|
|
88
|
+
catch { /* ignore */ }
|
|
89
|
+
return { success: false, error: serverMsg || httpStatusMessage(res.status) };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
return (await res.json());
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return { success: false, error: 'Invalid response from server (non-JSON)' };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function rovnPost(path, body) {
|
|
99
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
100
|
+
if (config.apiKey)
|
|
101
|
+
headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
102
|
+
return safeFetch(`${config.rovnUrl}${path}`, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers,
|
|
105
|
+
body: JSON.stringify(body),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async function rovnGet(path) {
|
|
109
|
+
const headers = {};
|
|
110
|
+
if (config.apiKey)
|
|
111
|
+
headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
112
|
+
return safeFetch(`${config.rovnUrl}${path}`, { headers });
|
|
113
|
+
}
|
|
114
|
+
async function rovnPatch(path, body) {
|
|
115
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
116
|
+
if (config.apiKey)
|
|
117
|
+
headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
118
|
+
return safeFetch(`${config.rovnUrl}${path}`, {
|
|
119
|
+
method: 'PATCH',
|
|
120
|
+
headers,
|
|
121
|
+
body: JSON.stringify(body),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// ─── Auto-Logging (fire-and-forget) ─────────────────────────
|
|
125
|
+
function autoLog(title, type = 'governance') {
|
|
126
|
+
if (!config.agentId || !config.apiKey)
|
|
127
|
+
return;
|
|
128
|
+
// Fire-and-forget — don't await, don't block the tool response
|
|
129
|
+
rovnPost(`/api/agents/${config.agentId}/activities`, {
|
|
130
|
+
type,
|
|
131
|
+
title,
|
|
132
|
+
metadata: { source: 'mcp-auto' },
|
|
133
|
+
}).catch(() => { });
|
|
134
|
+
}
|
|
135
|
+
// ─── MCP Tools Definition ───────────────────────────────────
|
|
136
|
+
exports.TOOLS = [
|
|
137
|
+
{
|
|
138
|
+
name: 'rovn_register',
|
|
139
|
+
description: 'Register this agent with Rovn governance platform. Returns an API key and agent ID. Call this once at the start.',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
name: { type: 'string', description: 'Agent name (e.g., "Claude Code Assistant")' },
|
|
144
|
+
description: { type: 'string', description: 'What this agent does' },
|
|
145
|
+
type: { type: 'string', description: 'Agent type (e.g., assistant, coder, researcher)' },
|
|
146
|
+
capabilities: {
|
|
147
|
+
type: 'array',
|
|
148
|
+
items: { type: 'string' },
|
|
149
|
+
description: 'List of capabilities (e.g., ["code_generation", "file_editing"])',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
required: ['name'],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: 'rovn_log_activity',
|
|
157
|
+
description: 'Log an activity to Rovn. Use this to report what the agent has done.',
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: 'object',
|
|
160
|
+
properties: {
|
|
161
|
+
title: { type: 'string', description: 'Activity title (e.g., "Refactored auth module")' },
|
|
162
|
+
type: { type: 'string', description: 'Activity type (e.g., code_generation, testing, deployment, review)' },
|
|
163
|
+
description: { type: 'string', description: 'Detailed description of what was done' },
|
|
164
|
+
metadata: { type: 'object', description: 'Additional structured data (e.g., { files_changed: 3 })' },
|
|
165
|
+
},
|
|
166
|
+
required: ['title'],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'rovn_check_action',
|
|
171
|
+
description: 'Pre-flight check: ask Rovn if an action is allowed before executing it. Returns allowed/denied/needs_approval.',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
action: { type: 'string', description: 'The action to check (e.g., send_email, delete_file, deploy)' },
|
|
176
|
+
context: { type: 'string', description: 'Context about the action' },
|
|
177
|
+
urgency: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'How urgent is this action' },
|
|
178
|
+
cost: { type: 'number', description: 'Estimated cost in USD (if applicable)' },
|
|
179
|
+
},
|
|
180
|
+
required: ['action'],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'rovn_request_approval',
|
|
185
|
+
description: 'Request approval from the owner before performing a risky or important action. Owner will see this in their dashboard.',
|
|
186
|
+
inputSchema: {
|
|
187
|
+
type: 'object',
|
|
188
|
+
properties: {
|
|
189
|
+
title: { type: 'string', description: 'What needs approval (e.g., "Deploy to production")' },
|
|
190
|
+
type: { type: 'string', description: 'Category (e.g., deployment, payment, data_access, action)' },
|
|
191
|
+
description: { type: 'string', description: 'Detailed description of what will happen' },
|
|
192
|
+
urgency: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'How urgent' },
|
|
193
|
+
},
|
|
194
|
+
required: ['title'],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'rovn_get_tasks',
|
|
199
|
+
description: 'Get tasks assigned to this agent by the owner.',
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: 'object',
|
|
202
|
+
properties: {
|
|
203
|
+
status: { type: 'string', enum: ['pending', 'in_progress', 'completed', 'cancelled'], description: 'Filter by status' },
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'rovn_update_task',
|
|
209
|
+
description: 'Update a task status (e.g., mark as in_progress or completed).',
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
task_id: { type: 'string', description: 'The task ID to update' },
|
|
214
|
+
status: { type: 'string', enum: ['in_progress', 'completed', 'cancelled', 'failed'], description: 'New status' },
|
|
215
|
+
},
|
|
216
|
+
required: ['task_id', 'status'],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'rovn_get_report_card',
|
|
221
|
+
description: 'Get this agent\'s performance report card — trust score, grades, and recommendations.',
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
days: { type: 'number', description: 'Report period in days (default: 7)' },
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'rovn_get_trust_score',
|
|
231
|
+
description: 'Get this agent\'s Trust Score (0-100). Higher trust unlocks more autonomy.',
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: 'object',
|
|
234
|
+
properties: {},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
];
|
|
238
|
+
// ─── MCP Protocol Handler ───────────────────────────────────
|
|
239
|
+
async function handleRequest(request) {
|
|
240
|
+
switch (request.method) {
|
|
241
|
+
case 'initialize':
|
|
242
|
+
return {
|
|
243
|
+
protocolVersion: '2024-11-05',
|
|
244
|
+
capabilities: { tools: {} },
|
|
245
|
+
serverInfo: { name: 'rovn-governance', version: '0.1.0' },
|
|
246
|
+
};
|
|
247
|
+
case 'tools/list':
|
|
248
|
+
return { tools: exports.TOOLS };
|
|
249
|
+
case 'tools/call':
|
|
250
|
+
return handleToolCall(request.params);
|
|
251
|
+
case 'notifications/initialized':
|
|
252
|
+
return null; // Notifications don't need a response
|
|
253
|
+
default:
|
|
254
|
+
return { error: { code: -32601, message: `Unknown method: ${request.method}` } };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function handleToolCall(params) {
|
|
258
|
+
const { name, arguments: toolArgs } = params;
|
|
259
|
+
try {
|
|
260
|
+
switch (name) {
|
|
261
|
+
case 'rovn_register': {
|
|
262
|
+
// Reuse existing agent if already registered (api-key + agent-id set)
|
|
263
|
+
if (config.apiKey && config.agentId) {
|
|
264
|
+
// Validate existing credentials by fetching trust score
|
|
265
|
+
const check = await rovnGet(`/api/agents/${config.agentId}/trust-score`);
|
|
266
|
+
if (check.success) {
|
|
267
|
+
return toolResult({
|
|
268
|
+
success: true,
|
|
269
|
+
data: {
|
|
270
|
+
id: config.agentId,
|
|
271
|
+
message: 'Already registered. Using existing agent credentials.',
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
// If validation fails, fall through to re-register
|
|
276
|
+
config.apiKey = '';
|
|
277
|
+
config.agentId = '';
|
|
278
|
+
}
|
|
279
|
+
const body = {
|
|
280
|
+
name: toolArgs.name,
|
|
281
|
+
description: toolArgs.description,
|
|
282
|
+
type: toolArgs.type ?? 'mcp-agent',
|
|
283
|
+
capabilities: toolArgs.capabilities,
|
|
284
|
+
owner_email: config.ownerEmail || undefined,
|
|
285
|
+
metadata: { platform: 'mcp', registered_at: new Date().toISOString() },
|
|
286
|
+
};
|
|
287
|
+
const res = await rovnPost('/api/agents/register', body);
|
|
288
|
+
const data = res.data;
|
|
289
|
+
if (res.success && data) {
|
|
290
|
+
config.apiKey = data.api_key;
|
|
291
|
+
config.agentId = data.id;
|
|
292
|
+
autoLog(`Registered as ${data.name}`, 'registration');
|
|
293
|
+
return toolResult({
|
|
294
|
+
success: true,
|
|
295
|
+
data: {
|
|
296
|
+
id: data.id,
|
|
297
|
+
name: data.name,
|
|
298
|
+
claim_url: data.claim_url,
|
|
299
|
+
message: 'Agent registered! Share the claim_url with the owner. API key saved for this session.',
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return toolResult(res);
|
|
304
|
+
}
|
|
305
|
+
case 'rovn_log_activity': {
|
|
306
|
+
const err = requireAgent(config);
|
|
307
|
+
if (err)
|
|
308
|
+
return toolResult({ success: false, error: err });
|
|
309
|
+
return toolResult(await rovnPost(`/api/agents/${config.agentId}/activities`, {
|
|
310
|
+
type: toolArgs.type ?? 'action',
|
|
311
|
+
title: toolArgs.title,
|
|
312
|
+
description: toolArgs.description,
|
|
313
|
+
metadata: toolArgs.metadata,
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
case 'rovn_check_action': {
|
|
317
|
+
const err = requireAgent(config);
|
|
318
|
+
if (err)
|
|
319
|
+
return toolResult({ success: false, error: err });
|
|
320
|
+
// Use GET with query params (matches the API endpoint)
|
|
321
|
+
const params = new URLSearchParams();
|
|
322
|
+
params.set('action', toolArgs.action);
|
|
323
|
+
if (toolArgs.urgency)
|
|
324
|
+
params.set('urgency', toolArgs.urgency);
|
|
325
|
+
if (toolArgs.cost !== undefined)
|
|
326
|
+
params.set('cost', String(toolArgs.cost));
|
|
327
|
+
if (toolArgs.context)
|
|
328
|
+
params.set('context', toolArgs.context);
|
|
329
|
+
const checkRes = await rovnGet(`/api/agents/${config.agentId}/check?${params}`);
|
|
330
|
+
const decision = (checkRes.data?.decision ?? '');
|
|
331
|
+
autoLog(`Checked: ${toolArgs.action} → ${decision}`, 'governance');
|
|
332
|
+
return toolResult(checkRes);
|
|
333
|
+
}
|
|
334
|
+
case 'rovn_request_approval': {
|
|
335
|
+
const err = requireAgent(config);
|
|
336
|
+
if (err)
|
|
337
|
+
return toolResult({ success: false, error: err });
|
|
338
|
+
const approvalRes = await rovnPost(`/api/agents/${config.agentId}/approvals`, {
|
|
339
|
+
type: toolArgs.type ?? 'action',
|
|
340
|
+
title: toolArgs.title,
|
|
341
|
+
description: toolArgs.description,
|
|
342
|
+
urgency: toolArgs.urgency ?? 'medium',
|
|
343
|
+
});
|
|
344
|
+
if (approvalRes.success)
|
|
345
|
+
autoLog(`Requested approval: ${toolArgs.title}`, 'governance');
|
|
346
|
+
return toolResult(approvalRes);
|
|
347
|
+
}
|
|
348
|
+
case 'rovn_get_tasks': {
|
|
349
|
+
const err = requireAgent(config);
|
|
350
|
+
if (err)
|
|
351
|
+
return toolResult({ success: false, error: err });
|
|
352
|
+
const query = toolArgs.status ? `?status=${toolArgs.status}` : '';
|
|
353
|
+
return toolResult(await rovnGet(`/api/agents/${config.agentId}/tasks${query}`));
|
|
354
|
+
}
|
|
355
|
+
case 'rovn_update_task': {
|
|
356
|
+
const err = requireAgent(config);
|
|
357
|
+
if (err)
|
|
358
|
+
return toolResult({ success: false, error: err });
|
|
359
|
+
const taskRes = await rovnPatch(`/api/tasks/${toolArgs.task_id}`, {
|
|
360
|
+
status: toolArgs.status,
|
|
361
|
+
});
|
|
362
|
+
if (taskRes.success)
|
|
363
|
+
autoLog(`Task ${toolArgs.task_id}: → ${toolArgs.status}`, 'task_management');
|
|
364
|
+
return toolResult(taskRes);
|
|
365
|
+
}
|
|
366
|
+
case 'rovn_get_report_card': {
|
|
367
|
+
const err = requireAgent(config);
|
|
368
|
+
if (err)
|
|
369
|
+
return toolResult({ success: false, error: err });
|
|
370
|
+
const days = toolArgs.days ? `?days=${toolArgs.days}` : '';
|
|
371
|
+
return toolResult(await rovnGet(`/api/agents/${config.agentId}/report-card${days}`));
|
|
372
|
+
}
|
|
373
|
+
case 'rovn_get_trust_score': {
|
|
374
|
+
const err = requireAgent(config);
|
|
375
|
+
if (err)
|
|
376
|
+
return toolResult({ success: false, error: err });
|
|
377
|
+
return toolResult(await rovnGet(`/api/agents/${config.agentId}/trust-score`));
|
|
378
|
+
}
|
|
379
|
+
default:
|
|
380
|
+
return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
return {
|
|
385
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
386
|
+
isError: true,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function toolResult(res) {
|
|
391
|
+
return {
|
|
392
|
+
content: [{
|
|
393
|
+
type: 'text',
|
|
394
|
+
text: JSON.stringify(res, null, 2),
|
|
395
|
+
}],
|
|
396
|
+
isError: !res.success,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
// ─── STDIO Transport ────────────────────────────────────────
|
|
400
|
+
// Only start STDIO transport when run directly (not imported for testing)
|
|
401
|
+
const isDirectRun = require.main === module;
|
|
402
|
+
if (isDirectRun) {
|
|
403
|
+
const rl = (0, readline_1.createInterface)({ input: process.stdin });
|
|
404
|
+
let buffer = '';
|
|
405
|
+
rl.on('line', async (line) => {
|
|
406
|
+
buffer += line;
|
|
407
|
+
let request;
|
|
408
|
+
try {
|
|
409
|
+
request = JSON.parse(buffer);
|
|
410
|
+
buffer = '';
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
// Incomplete JSON — keep buffering
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const result = await handleRequest(request);
|
|
418
|
+
// Notifications (null result) don't get a response
|
|
419
|
+
if (result === null)
|
|
420
|
+
return;
|
|
421
|
+
process.stdout.write(JSON.stringify({
|
|
422
|
+
jsonrpc: '2.0',
|
|
423
|
+
id: request.id,
|
|
424
|
+
result,
|
|
425
|
+
}) + '\n');
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
process.stdout.write(JSON.stringify({
|
|
429
|
+
jsonrpc: '2.0',
|
|
430
|
+
id: request.id,
|
|
431
|
+
error: { code: -32603, message: `Internal error: ${error instanceof Error ? error.message : String(error)}` },
|
|
432
|
+
}) + '\n');
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
process.stderr.write('Rovn MCP Server started\n');
|
|
436
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rovn-ai/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Rovn MCP Server — governance tools for Claude, GPT, and any MCP-compatible agent",
|
|
5
|
+
"main": "dist/server.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rovn-mcp-server": "./dist/server.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"!dist/**/*.test.*"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"start": "node dist/server.js",
|
|
17
|
+
"test": "tsc && node --test dist/server.test.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"rovn",
|
|
21
|
+
"mcp",
|
|
22
|
+
"governance",
|
|
23
|
+
"agent",
|
|
24
|
+
"claude"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.3.0",
|
|
29
|
+
"typescript": "^5.4.0"
|
|
30
|
+
}
|
|
31
|
+
}
|