@vorim/mcp-server 1.1.4 → 1.1.5
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/build/index.js +35 -5
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
22
22
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
23
23
|
import { z } from "zod";
|
|
24
|
+
// SECURITY: The MCP server uses a single process-wide Vorim API key
|
|
25
|
+
// taken from VORIM_API_KEY at startup. The stdio transport between
|
|
26
|
+
// the MCP host (e.g. Claude Desktop) and this process carries NO
|
|
27
|
+
// per-call auth — every tool call is attributed to the configured
|
|
28
|
+
// key. Two consequences:
|
|
29
|
+
// 1. Scope the key tightly. The key's scopes (audit:read,
|
|
30
|
+
// audit:write, agent:write, etc.) determine which MCP tools
|
|
31
|
+
// will actually work; a least-privilege scoped key reduces
|
|
32
|
+
// blast radius if the host environment is compromised.
|
|
33
|
+
// 2. Do not share a key across MCP installations. Each user /
|
|
34
|
+
// machine should mint its own key so revocation surgically
|
|
35
|
+
// kills exactly one installation.
|
|
24
36
|
const API_KEY = process.env.VORIM_API_KEY || "";
|
|
25
37
|
const BASE_URL = (process.env.VORIM_BASE_URL || "https://api.vorim.ai").replace(/\/$/, "");
|
|
26
38
|
if (!API_KEY) {
|
|
@@ -32,7 +44,7 @@ if (!API_KEY) {
|
|
|
32
44
|
// server's advertised version stay in sync with package.json.
|
|
33
45
|
// require() works in the CommonJS build path; for the ESM-only build
|
|
34
46
|
// we fall back to a constant that must match package.json.
|
|
35
|
-
const MCP_VERSION = "1.1.
|
|
47
|
+
const MCP_VERSION = "1.1.5";
|
|
36
48
|
/**
|
|
37
49
|
* URL-encode a user-supplied path segment. Agent ids, scopes, and
|
|
38
50
|
* chain ids all reach the API via path interpolation; raw slashes or
|
|
@@ -52,6 +64,22 @@ async function vorimRequest(method, path, body) {
|
|
|
52
64
|
},
|
|
53
65
|
body: body ? JSON.stringify(body) : undefined,
|
|
54
66
|
});
|
|
67
|
+
// Hand out clearer error messages for the common cases an MCP user
|
|
68
|
+
// will see. Auth: the API key is wrong or revoked. Scope: the key
|
|
69
|
+
// is missing the scope this route requires (e.g. audit:write).
|
|
70
|
+
if (response.status === 401) {
|
|
71
|
+
throw new Error("Vorim API key is invalid, revoked, or expired. Check VORIM_API_KEY.");
|
|
72
|
+
}
|
|
73
|
+
if (response.status === 403) {
|
|
74
|
+
const j = await response.json().catch(() => ({}));
|
|
75
|
+
const err = j.error;
|
|
76
|
+
const code = err?.code;
|
|
77
|
+
if (code === "INSUFFICIENT_SCOPE") {
|
|
78
|
+
throw new Error(err?.message ||
|
|
79
|
+
"Vorim API key is missing the scope required for this operation. Mint a new key with the required scope and update VORIM_API_KEY.");
|
|
80
|
+
}
|
|
81
|
+
throw new Error(err?.message || "Vorim API rejected with 403");
|
|
82
|
+
}
|
|
55
83
|
const json = await response.json();
|
|
56
84
|
if (!response.ok) {
|
|
57
85
|
const err = json.error;
|
|
@@ -84,9 +112,10 @@ const server = new McpServer({
|
|
|
84
112
|
server.registerTool("vorim_ping", {
|
|
85
113
|
description: "Check Vorim AI API health and connectivity. Returns status, version, and service health.",
|
|
86
114
|
inputSchema: {},
|
|
115
|
+
annotations: { readOnlyHint: true },
|
|
87
116
|
}, async () => {
|
|
88
117
|
const response = await fetch(`${BASE_URL}/health`, {
|
|
89
|
-
headers: { "User-Agent":
|
|
118
|
+
headers: { "User-Agent": `vorim-mcp-server/${MCP_VERSION}` },
|
|
90
119
|
});
|
|
91
120
|
const data = await response.json();
|
|
92
121
|
return text(data);
|
|
@@ -235,11 +264,12 @@ server.registerTool("vorim_emit_event", {
|
|
|
235
264
|
return text(data);
|
|
236
265
|
});
|
|
237
266
|
server.registerTool("vorim_export_audit", {
|
|
238
|
-
description: "Export a signed audit bundle for a date range. Returns events with a SHA-256 manifest for tamper-proof verification.",
|
|
267
|
+
description: "Export a signed audit bundle for a date range. Returns events with a SHA-256 manifest for tamper-proof verification. Window must be <= 90 days; the server returns 400 if from > to or the range exceeds the cap. The returned bundle has up to 1,000,000 events; if truncated, the response carries `truncated: true` and the caller should re-export a narrower window.",
|
|
239
268
|
inputSchema: {
|
|
240
|
-
from: z.string().describe("Start date
|
|
241
|
-
to: z.string().describe("End date
|
|
269
|
+
from: z.string().describe("Start date in ISO 8601 (e.g. 2026-06-01T00:00:00Z)"),
|
|
270
|
+
to: z.string().describe("End date in ISO 8601 (must be on or after `from`; window <= 90 days)"),
|
|
242
271
|
},
|
|
272
|
+
annotations: { readOnlyHint: true },
|
|
243
273
|
}, async ({ from, to }) => {
|
|
244
274
|
const result = await vorimPost("/audit/export", { from, to });
|
|
245
275
|
return text(result);
|
package/package.json
CHANGED