@error-bar/mcp 0.3.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 +202 -0
- package/README.md +155 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +58 -0
- package/dist/client.d.ts +38 -0
- package/dist/client.js +62 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/manifest-types.d.ts +32 -0
- package/dist/manifest-types.js +1 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +2042 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.js +135 -0
- package/package.json +47 -0
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type ZodTypeAny } from "zod";
|
|
3
|
+
import type { Operation } from "./manifest-types.js";
|
|
4
|
+
import { OmniaClient } from "./client.js";
|
|
5
|
+
export interface ServerOptions {
|
|
6
|
+
client: OmniaClient;
|
|
7
|
+
/** Expose only GET operations. */
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
/** Hide operations that spend money (eval runs, training, dedicated capacity). */
|
|
10
|
+
noSpend?: boolean;
|
|
11
|
+
/** Restrict to these tool names (after the filters above). */
|
|
12
|
+
only?: string[];
|
|
13
|
+
/** Max characters of a response body returned to the model (default 60k). */
|
|
14
|
+
maxChars?: number;
|
|
15
|
+
version?: string;
|
|
16
|
+
}
|
|
17
|
+
/** The MCP input schema for one operation: path + query + body fields, flat. */
|
|
18
|
+
export declare function inputShapeFor(op: Operation): Record<string, ZodTypeAny>;
|
|
19
|
+
export declare function descriptionFor(op: Operation): string;
|
|
20
|
+
export declare function selectOperations(opts: Pick<ServerOptions, "readOnly" | "noSpend" | "only">): readonly Operation[];
|
|
21
|
+
export declare function createServer(opts: ServerOptions): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { OPERATIONS } from "./manifest.js";
|
|
4
|
+
function zodFor(p) {
|
|
5
|
+
let t;
|
|
6
|
+
switch (p.type) {
|
|
7
|
+
case "string":
|
|
8
|
+
t = p.enum ? z.enum(p.enum) : z.string();
|
|
9
|
+
break;
|
|
10
|
+
case "integer":
|
|
11
|
+
t = z.number().int();
|
|
12
|
+
break;
|
|
13
|
+
case "number":
|
|
14
|
+
t = z.number();
|
|
15
|
+
break;
|
|
16
|
+
case "boolean":
|
|
17
|
+
t = z.boolean();
|
|
18
|
+
break;
|
|
19
|
+
case "object":
|
|
20
|
+
t = z.record(z.string(), z.unknown());
|
|
21
|
+
break;
|
|
22
|
+
case "array": {
|
|
23
|
+
const item = p.items === "integer" ? z.number().int()
|
|
24
|
+
: p.items === "number" ? z.number()
|
|
25
|
+
: p.items === "boolean" ? z.boolean()
|
|
26
|
+
: p.items === "object" ? z.record(z.string(), z.unknown())
|
|
27
|
+
: z.string();
|
|
28
|
+
t = z.array(item);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
t = t.describe(p.description + (p.default !== undefined ? ` Default: ${JSON.stringify(p.default)}.` : ""));
|
|
33
|
+
return p.required ? t : t.optional();
|
|
34
|
+
}
|
|
35
|
+
/** The MCP input schema for one operation: path + query + body fields, flat. */
|
|
36
|
+
export function inputShapeFor(op) {
|
|
37
|
+
const shape = {};
|
|
38
|
+
const add = (p, kind) => {
|
|
39
|
+
if (shape[p.name])
|
|
40
|
+
throw new Error(`${op.name}: duplicate parameter name ${p.name} (${kind})`);
|
|
41
|
+
shape[p.name] = zodFor(p);
|
|
42
|
+
};
|
|
43
|
+
for (const p of op.pathParams ?? [])
|
|
44
|
+
add({ ...p, required: true }, "path");
|
|
45
|
+
for (const p of op.query ?? [])
|
|
46
|
+
add(p, "query");
|
|
47
|
+
for (const p of op.body ?? [])
|
|
48
|
+
add(p, "body");
|
|
49
|
+
return shape;
|
|
50
|
+
}
|
|
51
|
+
export function descriptionFor(op) {
|
|
52
|
+
const parts = [op.summary];
|
|
53
|
+
parts.push(`${op.method} ${op.path} (API-key scope: ${op.scope}).`);
|
|
54
|
+
if (op.spends)
|
|
55
|
+
parts.push("SPENDS MONEY: this starts billable work on the workspace wallet.");
|
|
56
|
+
parts.push(`Returns: ${op.responseSummary}`);
|
|
57
|
+
if (op.notes)
|
|
58
|
+
parts.push(`Notes: ${op.notes}`);
|
|
59
|
+
return parts.join(" ");
|
|
60
|
+
}
|
|
61
|
+
export function selectOperations(opts) {
|
|
62
|
+
let ops = OPERATIONS;
|
|
63
|
+
if (opts.readOnly)
|
|
64
|
+
ops = ops.filter((o) => o.method === "GET");
|
|
65
|
+
if (opts.noSpend)
|
|
66
|
+
ops = ops.filter((o) => !o.spends);
|
|
67
|
+
if (opts.only?.length) {
|
|
68
|
+
const want = new Set(opts.only);
|
|
69
|
+
ops = ops.filter((o) => want.has(o.name));
|
|
70
|
+
}
|
|
71
|
+
return ops;
|
|
72
|
+
}
|
|
73
|
+
function truncate(s, max) {
|
|
74
|
+
return s.length <= max ? s : s.slice(0, max) + `\n… [truncated ${s.length - max} characters; narrow the query or use a cursor]`;
|
|
75
|
+
}
|
|
76
|
+
export function createServer(opts) {
|
|
77
|
+
const server = new McpServer({ name: "errorbar", version: opts.version ?? "0.0.0" });
|
|
78
|
+
const maxChars = opts.maxChars ?? 60_000;
|
|
79
|
+
for (const op of selectOperations(opts)) {
|
|
80
|
+
const pathNames = new Set((op.pathParams ?? []).map((p) => p.name));
|
|
81
|
+
const queryNames = new Set((op.query ?? []).map((p) => p.name));
|
|
82
|
+
const bodyNames = new Set((op.body ?? []).map((p) => p.name));
|
|
83
|
+
server.registerTool(op.name, {
|
|
84
|
+
title: op.name.replace(/_/g, " "),
|
|
85
|
+
description: descriptionFor(op),
|
|
86
|
+
inputSchema: inputShapeFor(op),
|
|
87
|
+
annotations: {
|
|
88
|
+
readOnlyHint: op.method === "GET",
|
|
89
|
+
destructiveHint: op.method === "DELETE",
|
|
90
|
+
idempotentHint: op.method === "GET" || op.method === "PUT" || op.method === "DELETE",
|
|
91
|
+
openWorldHint: true,
|
|
92
|
+
},
|
|
93
|
+
}, async (args) => {
|
|
94
|
+
const pathParams = {};
|
|
95
|
+
const query = {};
|
|
96
|
+
const body = {};
|
|
97
|
+
for (const [k, v] of Object.entries(args ?? {})) {
|
|
98
|
+
if (v === undefined)
|
|
99
|
+
continue;
|
|
100
|
+
if (pathNames.has(k))
|
|
101
|
+
pathParams[k] = v;
|
|
102
|
+
else if (queryNames.has(k))
|
|
103
|
+
query[k] = v;
|
|
104
|
+
else if (bodyNames.has(k))
|
|
105
|
+
body[k] = v;
|
|
106
|
+
}
|
|
107
|
+
let res;
|
|
108
|
+
try {
|
|
109
|
+
res = await opts.client.request({
|
|
110
|
+
method: op.method,
|
|
111
|
+
path: op.path,
|
|
112
|
+
pathParams,
|
|
113
|
+
query,
|
|
114
|
+
body: bodyNames.size > 0 ? body : undefined,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
return { isError: true, content: [{ type: "text", text: `request failed: ${e.message}` }] };
|
|
119
|
+
}
|
|
120
|
+
let text = res.json !== undefined ? JSON.stringify(res.json, null, 2) : (res.text ?? "");
|
|
121
|
+
if (res.json === undefined && res.contentType.includes("text/html")) {
|
|
122
|
+
// An HTML body is never an API answer — it is the platform's 404/500 page
|
|
123
|
+
// (route not deployed, wrong base URL). Say that instead of dumping markup.
|
|
124
|
+
const title = /<title>([^<]*)<\/title>/i.exec(text)?.[1]?.trim();
|
|
125
|
+
text = `HTML page instead of an API response${title ? ` ("${title}")` : ""} — the route is not available at this base URL (check ERRORBAR_BASE_URL or whether this API version is deployed).`;
|
|
126
|
+
}
|
|
127
|
+
const headline = res.ok ? "" : `HTTP ${res.status} from ${op.method} ${op.path}\n`;
|
|
128
|
+
return {
|
|
129
|
+
isError: !res.ok,
|
|
130
|
+
content: [{ type: "text", text: headline + truncate(text, maxChars) }],
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return server;
|
|
135
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@error-bar/mcp",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "errorbar MCP server \u2014 every platform API (evals, criteria, gates, logs, datasets, aliases, audit, proving) as tools for Claude, Cursor, and any MCP client.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/omnia-v/omnia-mcp.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"errorbar-mcp": "dist/cli.js",
|
|
13
|
+
"omnia-mcp": "dist/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/cli.js",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
+
"start": "node dist/cli.js"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
32
|
+
"zod": "^3.25.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.0.0",
|
|
36
|
+
"typescript": "^5.6.0",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
".": {
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"default": "./dist/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./cli": "./dist/cli.js"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://docs.errorbar.ai"
|
|
47
|
+
}
|