@2kw/ai-mcp-server 4.0.0-dev.2
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 +19 -0
- package/README.md +123 -0
- package/dist/client.d.ts +14 -0
- package/dist/client.js +46 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +22 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +116 -0
- package/dist/mime.d.ts +2 -0
- package/dist/mime.js +56 -0
- package/dist/schema-compat.d.ts +11 -0
- package/dist/schema-compat.js +51 -0
- package/dist/tools/ai-gateway.d.ts +4 -0
- package/dist/tools/ai-gateway.js +107 -0
- package/dist/tools/analytics.d.ts +4 -0
- package/dist/tools/analytics.js +163 -0
- package/dist/tools/billing.d.ts +4 -0
- package/dist/tools/billing.js +76 -0
- package/dist/tools/conversion.d.ts +4 -0
- package/dist/tools/conversion.js +281 -0
- package/dist/tools/datasets.d.ts +4 -0
- package/dist/tools/datasets.js +200 -0
- package/dist/tools/docs.d.ts +4 -0
- package/dist/tools/docs.js +171 -0
- package/dist/tools/evaluators.d.ts +4 -0
- package/dist/tools/evaluators.js +140 -0
- package/dist/tools/experiments.d.ts +4 -0
- package/dist/tools/experiments.js +231 -0
- package/dist/tools/extraction.d.ts +4 -0
- package/dist/tools/extraction.js +245 -0
- package/dist/tools/prompts.d.ts +4 -0
- package/dist/tools/prompts.js +373 -0
- package/dist/tools/providers.d.ts +4 -0
- package/dist/tools/providers.js +148 -0
- package/dist/tools/schema-labels.d.ts +4 -0
- package/dist/tools/schema-labels.js +88 -0
- package/dist/tools/schema-testing.d.ts +4 -0
- package/dist/tools/schema-testing.js +96 -0
- package/dist/tools/schema-versions.d.ts +4 -0
- package/dist/tools/schema-versions.js +127 -0
- package/dist/tools/schemas.d.ts +4 -0
- package/dist/tools/schemas.js +136 -0
- package/dist/tools/scores.d.ts +4 -0
- package/dist/tools/scores.js +43 -0
- package/dist/tools/tracing.d.ts +4 -0
- package/dist/tools/tracing.js +124 -0
- package/dist/tools/transcription.d.ts +4 -0
- package/dist/tools/transcription.js +76 -0
- package/package.json +45 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatErrorForMcp } from "../errors.js";
|
|
3
|
+
async function resolveLatestVersionId(client, datasetId) {
|
|
4
|
+
const { data } = await client.GET("/v1/datasets/{id}/versions/latest", { params: { path: { id: datasetId } } });
|
|
5
|
+
const versionId = data?.id;
|
|
6
|
+
if (!versionId) {
|
|
7
|
+
throw new Error(`Could not resolve latest version for dataset ${datasetId}. Create a version first.`);
|
|
8
|
+
}
|
|
9
|
+
return versionId;
|
|
10
|
+
}
|
|
11
|
+
export function register(server, client) {
|
|
12
|
+
// ── list_datasets ──────────────────────────────────────────────
|
|
13
|
+
server.tool("2kw_list_datasets", "List datasets in the organization with optional search, type filter, and pagination.", {
|
|
14
|
+
search: z.string().optional().describe("Filter datasets by name"),
|
|
15
|
+
type: z.string().optional().describe("Filter by dataset type"),
|
|
16
|
+
page: z.number().optional().default(0).describe("Page number (0-based)"),
|
|
17
|
+
size: z.number().optional().default(20).describe("Page size"),
|
|
18
|
+
sort: z.string().optional().describe("Sort field and direction"),
|
|
19
|
+
}, async ({ search, type, page, size, sort }) => {
|
|
20
|
+
try {
|
|
21
|
+
const { data } = await client.GET("/v1/datasets", {
|
|
22
|
+
params: {
|
|
23
|
+
query: {
|
|
24
|
+
search,
|
|
25
|
+
type,
|
|
26
|
+
pageable: {
|
|
27
|
+
page,
|
|
28
|
+
size,
|
|
29
|
+
sort: sort ? [sort] : undefined,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
const result = data;
|
|
35
|
+
const lines = (result.content ?? []).map((d) => `- ${d.name} (id: ${d.id}, type: ${d.type ?? "—"})${d.description ? ` — ${d.description}` : ""}`);
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `Datasets (${result.totalElements} total, page ${(result.number ?? 0) + 1}/${result.totalPages}):\n${lines.join("\n") || "(none)"}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// ── get_dataset ────────────────────────────────────────────────
|
|
53
|
+
server.tool("2kw_get_dataset", "Get a dataset by its ID.", {
|
|
54
|
+
datasetId: z.string().describe("The dataset ID"),
|
|
55
|
+
}, async ({ datasetId }) => {
|
|
56
|
+
try {
|
|
57
|
+
const { data } = await client.GET("/v1/datasets/{id}", {
|
|
58
|
+
params: { path: { id: datasetId } },
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// ── create_dataset ─────────────────────────────────────────────
|
|
72
|
+
server.tool("2kw_create_dataset", "Create a new dataset in the organization.", {
|
|
73
|
+
name: z.string().min(1).describe("Dataset name"),
|
|
74
|
+
description: z.string().optional().describe("Dataset description"),
|
|
75
|
+
type: z.string().optional().describe("Dataset type"),
|
|
76
|
+
inputSchema: z.unknown().optional().describe("Input JSON Schema definition"),
|
|
77
|
+
expectedOutputSchema: z.unknown().optional().describe("Expected output JSON Schema definition"),
|
|
78
|
+
metadata: z.unknown().optional().describe("Arbitrary metadata (JSON object)"),
|
|
79
|
+
}, async ({ name, description, type, inputSchema, expectedOutputSchema, metadata }) => {
|
|
80
|
+
try {
|
|
81
|
+
const body = { name };
|
|
82
|
+
if (description !== undefined)
|
|
83
|
+
body.description = description;
|
|
84
|
+
if (type !== undefined)
|
|
85
|
+
body.type = type;
|
|
86
|
+
if (inputSchema !== undefined)
|
|
87
|
+
body.inputSchema = inputSchema;
|
|
88
|
+
if (expectedOutputSchema !== undefined)
|
|
89
|
+
body.expectedOutputSchema = expectedOutputSchema;
|
|
90
|
+
if (metadata !== undefined)
|
|
91
|
+
body.metadata = metadata;
|
|
92
|
+
const { data } = await client.POST("/v1/datasets", {
|
|
93
|
+
body: body,
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// ── create_dataset_version ─────────────────────────────────────
|
|
107
|
+
server.tool("2kw_create_dataset_version", "Create a new version of a dataset.", {
|
|
108
|
+
datasetId: z.string().describe("The dataset ID"),
|
|
109
|
+
changeDescription: z.string().optional().describe("Description of what changed in this version"),
|
|
110
|
+
}, async ({ datasetId, changeDescription }) => {
|
|
111
|
+
try {
|
|
112
|
+
const { data } = await client.POST("/v1/datasets/{id}/versions", {
|
|
113
|
+
params: { path: { id: datasetId } },
|
|
114
|
+
body: { changeDescription },
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
123
|
+
isError: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// ── add_dataset_item ───────────────────────────────────────────
|
|
128
|
+
server.tool("2kw_add_dataset_item", "Add an item to a dataset. Uses the latest version unless versionId is specified.", {
|
|
129
|
+
datasetId: z.string().describe("The dataset ID"),
|
|
130
|
+
versionId: z.string().optional().describe("The dataset version ID (defaults to latest)"),
|
|
131
|
+
input: z.unknown().describe("Item input data (JSON object)"),
|
|
132
|
+
expectedOutput: z.unknown().optional().describe("Expected output (JSON object)"),
|
|
133
|
+
tags: z.array(z.string()).optional().describe("Tags for the item"),
|
|
134
|
+
metadata: z.unknown().optional().describe("Arbitrary metadata (JSON object)"),
|
|
135
|
+
}, async ({ datasetId, versionId, input, expectedOutput, tags, metadata }) => {
|
|
136
|
+
try {
|
|
137
|
+
const resolvedVersionId = versionId ?? (await resolveLatestVersionId(client, datasetId));
|
|
138
|
+
const body = { input };
|
|
139
|
+
if (expectedOutput !== undefined)
|
|
140
|
+
body.expectedOutput = expectedOutput;
|
|
141
|
+
if (tags !== undefined)
|
|
142
|
+
body.tags = tags;
|
|
143
|
+
if (metadata !== undefined)
|
|
144
|
+
body.metadata = metadata;
|
|
145
|
+
const { data } = await client.POST("/v1/datasets/{id}/versions/{versionId}/items", {
|
|
146
|
+
params: {
|
|
147
|
+
// OpenAPI spec omits `id` in declared path params though `{id}` is in the URL template.
|
|
148
|
+
path: { id: datasetId, versionId: resolvedVersionId },
|
|
149
|
+
},
|
|
150
|
+
body: body,
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
159
|
+
isError: true,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
// ── get_dataset_items ──────────────────────────────────────────
|
|
164
|
+
server.tool("2kw_get_dataset_items", "List items in a dataset with pagination. Uses the latest version unless versionId is specified.", {
|
|
165
|
+
datasetId: z.string().describe("The dataset ID"),
|
|
166
|
+
versionId: z.string().optional().describe("The dataset version ID (defaults to latest)"),
|
|
167
|
+
page: z.number().optional().default(0).describe("Page number (0-based)"),
|
|
168
|
+
size: z.number().optional().default(20).describe("Page size"),
|
|
169
|
+
}, async ({ datasetId, versionId, page, size }) => {
|
|
170
|
+
try {
|
|
171
|
+
const resolvedVersionId = versionId ?? (await resolveLatestVersionId(client, datasetId));
|
|
172
|
+
const { data } = await client.GET("/v1/datasets/{id}/versions/{versionId}/items", {
|
|
173
|
+
params: {
|
|
174
|
+
// OpenAPI spec omits `id` in declared path params though `{id}` is in the URL template.
|
|
175
|
+
path: { id: datasetId, versionId: resolvedVersionId },
|
|
176
|
+
query: { pageable: { page, size } },
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
const result = data;
|
|
180
|
+
const lines = (result.content ?? []).map(
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
(item) => `- Item ${item.id}: input=${JSON.stringify(item.input)}${item.expectedOutput ? `, expected=${JSON.stringify(item.expectedOutput)}` : ""}${item.tags?.length ? `, tags=[${item.tags.join(", ")}]` : ""}`);
|
|
183
|
+
return {
|
|
184
|
+
content: [
|
|
185
|
+
{
|
|
186
|
+
type: "text",
|
|
187
|
+
text: `Items (${result.totalElements} total, page ${(result.number ?? 0) + 1}/${result.totalPages}):\n${lines.join("\n") || "(none)"}`,
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
return {
|
|
194
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
195
|
+
isError: true,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=datasets.js.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatErrorForMcp } from "../errors.js";
|
|
3
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
4
|
+
let specCache = null;
|
|
5
|
+
async function fetchSpec(baseUrl, apiKey) {
|
|
6
|
+
if (specCache)
|
|
7
|
+
return specCache;
|
|
8
|
+
const specUrl = `${baseUrl.replace(/\/+$/, "")}/v3/api-docs`;
|
|
9
|
+
const res = await fetch(specUrl, {
|
|
10
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
11
|
+
});
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
if (res.status === 404 || res.status === 403) {
|
|
14
|
+
throw new Error("API documentation is not available. Enable it by setting SPRINGDOC_ENABLED=true on the backend.");
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`Failed to fetch API docs: ${res.status} ${res.statusText}`);
|
|
17
|
+
}
|
|
18
|
+
specCache = await res.json();
|
|
19
|
+
return specCache;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Collect all $ref strings from an object tree.
|
|
23
|
+
*/
|
|
24
|
+
function collectRefs(obj, refs) {
|
|
25
|
+
if (obj === null || obj === undefined || typeof obj !== "object")
|
|
26
|
+
return;
|
|
27
|
+
if (Array.isArray(obj)) {
|
|
28
|
+
for (const item of obj)
|
|
29
|
+
collectRefs(item, refs);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const record = obj;
|
|
33
|
+
if (typeof record["$ref"] === "string") {
|
|
34
|
+
refs.add(record["$ref"]);
|
|
35
|
+
}
|
|
36
|
+
for (const value of Object.values(record)) {
|
|
37
|
+
collectRefs(value, refs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Recursively resolve schema refs — the initial set plus any schemas they reference.
|
|
42
|
+
*/
|
|
43
|
+
function resolveSchemas(refPaths, allSchemas) {
|
|
44
|
+
const resolved = {};
|
|
45
|
+
const queue = [...refPaths];
|
|
46
|
+
const visited = new Set();
|
|
47
|
+
while (queue.length > 0) {
|
|
48
|
+
const ref = queue.pop();
|
|
49
|
+
if (visited.has(ref))
|
|
50
|
+
continue;
|
|
51
|
+
visited.add(ref);
|
|
52
|
+
const prefix = "#/components/schemas/";
|
|
53
|
+
if (!ref.startsWith(prefix))
|
|
54
|
+
continue;
|
|
55
|
+
const name = ref.slice(prefix.length);
|
|
56
|
+
const schema = allSchemas[name];
|
|
57
|
+
if (!schema)
|
|
58
|
+
continue;
|
|
59
|
+
resolved[name] = schema;
|
|
60
|
+
// Find nested refs in this schema
|
|
61
|
+
const nested = new Set();
|
|
62
|
+
collectRefs(schema, nested);
|
|
63
|
+
for (const n of nested) {
|
|
64
|
+
if (!visited.has(n))
|
|
65
|
+
queue.push(n);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return resolved;
|
|
69
|
+
}
|
|
70
|
+
export function register(server, _client, baseUrl, apiKey) {
|
|
71
|
+
// ── list_api_doc_sections ───────────────────────────────────────────────
|
|
72
|
+
server.tool("2kw_list_api_doc_sections", "List available API documentation sections (tags) from the OpenAPI spec. Use this to discover which sections you can fetch detailed docs for.", {}, async () => {
|
|
73
|
+
try {
|
|
74
|
+
const spec = await fetchSpec(baseUrl, apiKey);
|
|
75
|
+
const tags = spec.tags ?? [];
|
|
76
|
+
const paths = spec.paths ?? {};
|
|
77
|
+
// Count endpoints per tag
|
|
78
|
+
const tagCounts = new Map();
|
|
79
|
+
for (const methods of Object.values(paths)) {
|
|
80
|
+
for (const operation of Object.values(methods)) {
|
|
81
|
+
if (operation?.tags) {
|
|
82
|
+
for (const tag of operation.tags) {
|
|
83
|
+
tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const lines = tags.map((t) => {
|
|
89
|
+
const count = tagCounts.get(t.name) ?? 0;
|
|
90
|
+
const desc = t.description ? ` — ${t.description}` : "";
|
|
91
|
+
return `- ${t.name} (${count} endpoint${count !== 1 ? "s" : ""})${desc}`;
|
|
92
|
+
});
|
|
93
|
+
const info = spec.info ?? {};
|
|
94
|
+
const header = `${info.title ?? "API"} v${info.version ?? "?"}`;
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: `${header}\n\nAvailable sections:\n${lines.join("\n") || "(none)"}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// ── get_api_docs ────────────────────────────────────────────────────────
|
|
112
|
+
server.tool("2kw_get_api_docs", "Fetch API documentation for a specific section (tag). Returns the filtered endpoints and their referenced schemas. Use 2kw_list_api_doc_sections first to see available tags.", {
|
|
113
|
+
tag: z.string().describe("The tag/section name to filter by (e.g. 'Projects', 'Extractions')"),
|
|
114
|
+
}, async ({ tag }) => {
|
|
115
|
+
try {
|
|
116
|
+
const spec = await fetchSpec(baseUrl, apiKey);
|
|
117
|
+
const allTags = spec.tags ?? [];
|
|
118
|
+
const tagNames = allTags.map((t) => t.name);
|
|
119
|
+
if (!tagNames.includes(tag)) {
|
|
120
|
+
return {
|
|
121
|
+
content: [
|
|
122
|
+
{
|
|
123
|
+
type: "text",
|
|
124
|
+
text: `Tag "${tag}" not found. Available tags: ${tagNames.join(", ")}`,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
isError: true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const allPaths = spec.paths ?? {};
|
|
131
|
+
const allSchemas = spec.components?.schemas ?? {};
|
|
132
|
+
// Filter paths to only operations matching the requested tag
|
|
133
|
+
const filteredPaths = {};
|
|
134
|
+
const refs = new Set();
|
|
135
|
+
for (const [path, methods] of Object.entries(allPaths)) {
|
|
136
|
+
const filteredMethods = {};
|
|
137
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
138
|
+
const op = operation;
|
|
139
|
+
if (op?.tags?.includes(tag)) {
|
|
140
|
+
filteredMethods[method] = operation;
|
|
141
|
+
collectRefs(operation, refs);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (Object.keys(filteredMethods).length > 0) {
|
|
145
|
+
filteredPaths[path] = filteredMethods;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Resolve referenced schemas (including transitive refs)
|
|
149
|
+
const referencedSchemas = resolveSchemas(refs, allSchemas);
|
|
150
|
+
const result = {
|
|
151
|
+
paths: filteredPaths,
|
|
152
|
+
schemas: referencedSchemas,
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: "text",
|
|
158
|
+
text: JSON.stringify(result, null, 2),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
166
|
+
isError: true,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=docs.js.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatErrorForMcp } from "../errors.js";
|
|
3
|
+
export function register(server, client) {
|
|
4
|
+
// ── built-in types ──────────────────────────────────────────────────────
|
|
5
|
+
server.tool("2kw_list_evaluator_types", "List the built-in evaluator types that experiments can score against (e.g. exact_match, grounding, llm_judge). These are the primitive kinds — use evaluator templates to reuse a configured judge across experiments.", {}, async () => {
|
|
6
|
+
try {
|
|
7
|
+
const { data } = await client.GET("/v1/evaluators");
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
15
|
+
isError: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
// ── templates ───────────────────────────────────────────────────────────
|
|
20
|
+
server.tool("2kw_list_evaluator_templates", "List org-scoped evaluator templates. Templates bundle a type + name + description + config and are referenced by id when attached to experiments.", {}, async () => {
|
|
21
|
+
try {
|
|
22
|
+
const { data } = await client.GET("/v1/evaluator-templates");
|
|
23
|
+
return {
|
|
24
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
server.tool("2kw_get_evaluator_template", "Show a single evaluator template by id, including its config.", { id: z.string().describe("Evaluator template id") }, async (params) => {
|
|
35
|
+
try {
|
|
36
|
+
const { data } = await client.GET("/v1/evaluator-templates/{id}", {
|
|
37
|
+
params: { path: { id: params.id } },
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
server.tool("2kw_create_evaluator_template", "Create a reusable evaluator template. LLM-judge templates require a config object with rubricPrompt (string) and model (provider/model). CODE and HUMAN templates may omit config.", {
|
|
51
|
+
name: z.string().describe("Template name"),
|
|
52
|
+
type: z.enum(["CODE", "LLM_JUDGE", "HUMAN"]).describe("Evaluator type"),
|
|
53
|
+
description: z.string().optional().describe("Description"),
|
|
54
|
+
config: z
|
|
55
|
+
.record(z.string(), z.unknown())
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Type-specific config JSON (LLM_JUDGE requires rubricPrompt + model)"),
|
|
58
|
+
}, async (params) => {
|
|
59
|
+
try {
|
|
60
|
+
const { data } = await client.POST("/v1/evaluator-templates", {
|
|
61
|
+
body: {
|
|
62
|
+
name: params.name,
|
|
63
|
+
type: params.type,
|
|
64
|
+
description: params.description,
|
|
65
|
+
config: params.config,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: `Evaluator template created.\n\n${JSON.stringify(data, null, 2)}`,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
server.tool("2kw_update_evaluator_template", "Replace an evaluator template. PUT semantics: omitted fields fall back to the current values (the tool reads current state first and merges).", {
|
|
85
|
+
id: z.string().describe("Evaluator template id"),
|
|
86
|
+
name: z.string().optional(),
|
|
87
|
+
type: z.enum(["CODE", "LLM_JUDGE", "HUMAN"]).optional(),
|
|
88
|
+
description: z.string().optional(),
|
|
89
|
+
config: z.record(z.string(), z.unknown()).optional(),
|
|
90
|
+
}, async (params) => {
|
|
91
|
+
try {
|
|
92
|
+
const { data: current } = await client.GET("/v1/evaluator-templates/{id}", {
|
|
93
|
+
params: { path: { id: params.id } },
|
|
94
|
+
});
|
|
95
|
+
const cur = current;
|
|
96
|
+
const { data } = await client.PUT("/v1/evaluator-templates/{id}", {
|
|
97
|
+
params: { path: { id: params.id } },
|
|
98
|
+
body: {
|
|
99
|
+
name: params.name ?? cur?.name,
|
|
100
|
+
type: params.type ?? cur?.type,
|
|
101
|
+
description: params.description ?? cur?.description,
|
|
102
|
+
config: params.config ?? cur?.config,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: `Evaluator template updated.\n\n${JSON.stringify(data, null, 2)}`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
117
|
+
isError: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
server.tool("2kw_delete_evaluator_template", "Delete an evaluator template. Experiments that already scored against it keep their past scores.", { id: z.string().describe("Evaluator template id") }, async (params) => {
|
|
122
|
+
try {
|
|
123
|
+
await client.DELETE("/v1/evaluator-templates/{id}", {
|
|
124
|
+
params: { path: { id: params.id } },
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
content: [
|
|
128
|
+
{ type: "text", text: `Deleted evaluator template ${params.id}` },
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
135
|
+
isError: true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=evaluators.js.map
|