@rovn-ai/mcp-server 0.1.0 → 0.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/dist/server.d.ts CHANGED
@@ -30,6 +30,9 @@ export interface ServerConfig {
30
30
  }
31
31
  export declare function getArg(args: string[], flag: string): string | undefined;
32
32
  export declare function createConfig(args: string[]): ServerConfig;
33
+ export declare const config: ServerConfig;
34
+ /** Reset config for testing. */
35
+ export declare function resetConfig(overrides?: Partial<ServerConfig>): void;
33
36
  export declare function requireAgent(cfg: ServerConfig): string | null;
34
37
  export declare function rovnPost(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
35
38
  export declare function rovnGet(path: string): Promise<Record<string, unknown>>;
package/dist/server.js CHANGED
@@ -24,9 +24,10 @@
24
24
  * }
25
25
  */
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.TOOLS = void 0;
27
+ exports.TOOLS = exports.config = void 0;
28
28
  exports.getArg = getArg;
29
29
  exports.createConfig = createConfig;
30
+ exports.resetConfig = resetConfig;
30
31
  exports.requireAgent = requireAgent;
31
32
  exports.rovnPost = rovnPost;
32
33
  exports.rovnGet = rovnGet;
@@ -47,7 +48,14 @@ function createConfig(args) {
47
48
  agentId: getArg(args, '--agent-id') ?? process.env.ROVN_AGENT_ID ?? '',
48
49
  };
49
50
  }
50
- const config = createConfig(process.argv.slice(2));
51
+ exports.config = createConfig(process.argv.slice(2));
52
+ /** Reset config for testing. */
53
+ function resetConfig(overrides = {}) {
54
+ exports.config.rovnUrl = overrides.rovnUrl ?? 'https://rovn.io';
55
+ exports.config.ownerEmail = overrides.ownerEmail ?? '';
56
+ exports.config.apiKey = overrides.apiKey ?? '';
57
+ exports.config.agentId = overrides.agentId ?? '';
58
+ }
51
59
  function requireAgent(cfg) {
52
60
  if (!cfg.agentId || !cfg.apiKey) {
53
61
  return 'Not registered. Call rovn_register first.';
@@ -97,9 +105,9 @@ async function safeFetch(url, init) {
97
105
  }
98
106
  async function rovnPost(path, body) {
99
107
  const headers = { 'Content-Type': 'application/json' };
100
- if (config.apiKey)
101
- headers['Authorization'] = `Bearer ${config.apiKey}`;
102
- return safeFetch(`${config.rovnUrl}${path}`, {
108
+ if (exports.config.apiKey)
109
+ headers['Authorization'] = `Bearer ${exports.config.apiKey}`;
110
+ return safeFetch(`${exports.config.rovnUrl}${path}`, {
103
111
  method: 'POST',
104
112
  headers,
105
113
  body: JSON.stringify(body),
@@ -107,15 +115,15 @@ async function rovnPost(path, body) {
107
115
  }
108
116
  async function rovnGet(path) {
109
117
  const headers = {};
110
- if (config.apiKey)
111
- headers['Authorization'] = `Bearer ${config.apiKey}`;
112
- return safeFetch(`${config.rovnUrl}${path}`, { headers });
118
+ if (exports.config.apiKey)
119
+ headers['Authorization'] = `Bearer ${exports.config.apiKey}`;
120
+ return safeFetch(`${exports.config.rovnUrl}${path}`, { headers });
113
121
  }
114
122
  async function rovnPatch(path, body) {
115
123
  const headers = { 'Content-Type': 'application/json' };
116
- if (config.apiKey)
117
- headers['Authorization'] = `Bearer ${config.apiKey}`;
118
- return safeFetch(`${config.rovnUrl}${path}`, {
124
+ if (exports.config.apiKey)
125
+ headers['Authorization'] = `Bearer ${exports.config.apiKey}`;
126
+ return safeFetch(`${exports.config.rovnUrl}${path}`, {
119
127
  method: 'PATCH',
120
128
  headers,
121
129
  body: JSON.stringify(body),
@@ -123,10 +131,10 @@ async function rovnPatch(path, body) {
123
131
  }
124
132
  // ─── Auto-Logging (fire-and-forget) ─────────────────────────
125
133
  function autoLog(title, type = 'governance') {
126
- if (!config.agentId || !config.apiKey)
134
+ if (!exports.config.agentId || !exports.config.apiKey)
127
135
  return;
128
136
  // Fire-and-forget — don't await, don't block the tool response
129
- rovnPost(`/api/agents/${config.agentId}/activities`, {
137
+ rovnPost(`/api/agents/${exports.config.agentId}/activities`, {
130
138
  type,
131
139
  title,
132
140
  metadata: { source: 'mcp-auto' },
@@ -260,35 +268,48 @@ async function handleToolCall(params) {
260
268
  switch (name) {
261
269
  case 'rovn_register': {
262
270
  // Reuse existing agent if already registered (api-key + agent-id set)
263
- if (config.apiKey && config.agentId) {
271
+ if (exports.config.apiKey && exports.config.agentId) {
264
272
  // Validate existing credentials by fetching trust score
265
- const check = await rovnGet(`/api/agents/${config.agentId}/trust-score`);
273
+ const check = await rovnGet(`/api/agents/${exports.config.agentId}/trust-score`);
266
274
  if (check.success) {
275
+ const data = (check.data ?? check);
267
276
  return toolResult({
268
277
  success: true,
269
278
  data: {
270
- id: config.agentId,
279
+ id: exports.config.agentId,
280
+ name: data.agent_name ?? toolArgs.name,
271
281
  message: 'Already registered. Using existing agent credentials.',
272
282
  },
273
283
  });
274
284
  }
275
- // If validation fails, fall through to re-register
276
- config.apiKey = '';
277
- config.agentId = '';
285
+ // Pre-configured credentials (from CLI args) keep using them even if validation fails
286
+ // This prevents creating duplicate agents when the server is temporarily unavailable
287
+ if (getArg(process.argv.slice(2), '--api-key') || process.env.ROVN_API_KEY) {
288
+ return toolResult({
289
+ success: true,
290
+ data: {
291
+ id: exports.config.agentId,
292
+ message: 'Using pre-configured credentials (server validation skipped).',
293
+ },
294
+ });
295
+ }
296
+ // Only clear credentials if they were from a previous dynamic registration
297
+ exports.config.apiKey = '';
298
+ exports.config.agentId = '';
278
299
  }
279
300
  const body = {
280
301
  name: toolArgs.name,
281
302
  description: toolArgs.description,
282
303
  type: toolArgs.type ?? 'mcp-agent',
283
304
  capabilities: toolArgs.capabilities,
284
- owner_email: config.ownerEmail || undefined,
305
+ owner_email: exports.config.ownerEmail || undefined,
285
306
  metadata: { platform: 'mcp', registered_at: new Date().toISOString() },
286
307
  };
287
308
  const res = await rovnPost('/api/agents/register', body);
288
309
  const data = res.data;
289
310
  if (res.success && data) {
290
- config.apiKey = data.api_key;
291
- config.agentId = data.id;
311
+ exports.config.apiKey = data.api_key;
312
+ exports.config.agentId = data.id;
292
313
  autoLog(`Registered as ${data.name}`, 'registration');
293
314
  return toolResult({
294
315
  success: true,
@@ -303,10 +324,10 @@ async function handleToolCall(params) {
303
324
  return toolResult(res);
304
325
  }
305
326
  case 'rovn_log_activity': {
306
- const err = requireAgent(config);
327
+ const err = requireAgent(exports.config);
307
328
  if (err)
308
329
  return toolResult({ success: false, error: err });
309
- return toolResult(await rovnPost(`/api/agents/${config.agentId}/activities`, {
330
+ return toolResult(await rovnPost(`/api/agents/${exports.config.agentId}/activities`, {
310
331
  type: toolArgs.type ?? 'action',
311
332
  title: toolArgs.title,
312
333
  description: toolArgs.description,
@@ -314,7 +335,7 @@ async function handleToolCall(params) {
314
335
  }));
315
336
  }
316
337
  case 'rovn_check_action': {
317
- const err = requireAgent(config);
338
+ const err = requireAgent(exports.config);
318
339
  if (err)
319
340
  return toolResult({ success: false, error: err });
320
341
  // Use GET with query params (matches the API endpoint)
@@ -326,16 +347,16 @@ async function handleToolCall(params) {
326
347
  params.set('cost', String(toolArgs.cost));
327
348
  if (toolArgs.context)
328
349
  params.set('context', toolArgs.context);
329
- const checkRes = await rovnGet(`/api/agents/${config.agentId}/check?${params}`);
350
+ const checkRes = await rovnGet(`/api/agents/${exports.config.agentId}/check?${params}`);
330
351
  const decision = (checkRes.data?.decision ?? '');
331
352
  autoLog(`Checked: ${toolArgs.action} → ${decision}`, 'governance');
332
353
  return toolResult(checkRes);
333
354
  }
334
355
  case 'rovn_request_approval': {
335
- const err = requireAgent(config);
356
+ const err = requireAgent(exports.config);
336
357
  if (err)
337
358
  return toolResult({ success: false, error: err });
338
- const approvalRes = await rovnPost(`/api/agents/${config.agentId}/approvals`, {
359
+ const approvalRes = await rovnPost(`/api/agents/${exports.config.agentId}/approvals`, {
339
360
  type: toolArgs.type ?? 'action',
340
361
  title: toolArgs.title,
341
362
  description: toolArgs.description,
@@ -346,14 +367,14 @@ async function handleToolCall(params) {
346
367
  return toolResult(approvalRes);
347
368
  }
348
369
  case 'rovn_get_tasks': {
349
- const err = requireAgent(config);
370
+ const err = requireAgent(exports.config);
350
371
  if (err)
351
372
  return toolResult({ success: false, error: err });
352
373
  const query = toolArgs.status ? `?status=${toolArgs.status}` : '';
353
- return toolResult(await rovnGet(`/api/agents/${config.agentId}/tasks${query}`));
374
+ return toolResult(await rovnGet(`/api/agents/${exports.config.agentId}/tasks${query}`));
354
375
  }
355
376
  case 'rovn_update_task': {
356
- const err = requireAgent(config);
377
+ const err = requireAgent(exports.config);
357
378
  if (err)
358
379
  return toolResult({ success: false, error: err });
359
380
  const taskRes = await rovnPatch(`/api/tasks/${toolArgs.task_id}`, {
@@ -364,17 +385,17 @@ async function handleToolCall(params) {
364
385
  return toolResult(taskRes);
365
386
  }
366
387
  case 'rovn_get_report_card': {
367
- const err = requireAgent(config);
388
+ const err = requireAgent(exports.config);
368
389
  if (err)
369
390
  return toolResult({ success: false, error: err });
370
391
  const days = toolArgs.days ? `?days=${toolArgs.days}` : '';
371
- return toolResult(await rovnGet(`/api/agents/${config.agentId}/report-card${days}`));
392
+ return toolResult(await rovnGet(`/api/agents/${exports.config.agentId}/report-card${days}`));
372
393
  }
373
394
  case 'rovn_get_trust_score': {
374
- const err = requireAgent(config);
395
+ const err = requireAgent(exports.config);
375
396
  if (err)
376
397
  return toolResult({ success: false, error: err });
377
- return toolResult(await rovnGet(`/api/agents/${config.agentId}/trust-score`));
398
+ return toolResult(await rovnGet(`/api/agents/${exports.config.agentId}/trust-score`));
378
399
  }
379
400
  default:
380
401
  return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovn-ai/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Rovn MCP Server — governance tools for Claude, GPT, and any MCP-compatible agent",
5
5
  "main": "dist/server.js",
6
6
  "bin": {