@2kw/ai-mcp-server 6.1.0-dev.8 → 6.2.0-dev.13
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 +5 -1
- package/dist/index.js +14 -0
- package/dist/tools/agents.d.ts +4 -0
- package/dist/tools/agents.js +434 -0
- package/dist/tools/annotation-queues.d.ts +4 -0
- package/dist/tools/annotation-queues.js +322 -0
- package/dist/tools/conversations.d.ts +4 -0
- package/dist/tools/conversations.js +123 -0
- package/dist/tools/files.d.ts +4 -0
- package/dist/tools/files.js +143 -0
- package/dist/tools/knowledge.d.ts +4 -0
- package/dist/tools/knowledge.js +382 -0
- package/dist/tools/plugins.d.ts +5 -0
- package/dist/tools/plugins.js +98 -0
- package/dist/tools/scores.js +53 -3
- package/dist/tools/skills.d.ts +5 -0
- package/dist/tools/skills.js +177 -0
- package/package.json +3 -3
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { basename, extname } from "node:path";
|
|
4
|
+
import { BackboneApiError, formatErrorForMcp } from "../errors.js";
|
|
5
|
+
// Spring accepts flat pagination parameters despite the generated pageable wrapper.
|
|
6
|
+
function paginationParams(params) {
|
|
7
|
+
return {
|
|
8
|
+
page: params.page ?? 0,
|
|
9
|
+
size: params.size ?? 20,
|
|
10
|
+
sort: params.sort ? [params.sort] : undefined,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Register skill read and import tools (#642). */
|
|
14
|
+
export function register(server, client) {
|
|
15
|
+
server.tool("2kw_list_skills", "List org skills with optional name/status filter and pagination.", {
|
|
16
|
+
search: z.string().optional().describe("Filter by name"),
|
|
17
|
+
status: z.enum(["ACTIVE", "ARCHIVED"]).optional(),
|
|
18
|
+
page: z.number().int().min(0).optional(),
|
|
19
|
+
size: z.number().int().min(1).max(100).optional(),
|
|
20
|
+
sort: z.string().optional().describe("Sort field and direction"),
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
try {
|
|
23
|
+
const { data } = await client.GET("/v1/skills", {
|
|
24
|
+
params: {
|
|
25
|
+
query: {
|
|
26
|
+
search: params.search,
|
|
27
|
+
status: params.status,
|
|
28
|
+
...paginationParams(params),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
server.tool("2kw_get_skill", "Get a skill by ID, including its latest version number.", { skillId: z.string() }, async (params) => {
|
|
44
|
+
try {
|
|
45
|
+
const { data } = await client.GET("/v1/skills/{id}", {
|
|
46
|
+
params: { path: { id: params.skillId } },
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.tool("2kw_list_skill_versions", "List versions of a skill with pagination.", {
|
|
60
|
+
skillId: z.string(),
|
|
61
|
+
page: z.number().int().min(0).optional(),
|
|
62
|
+
size: z.number().int().min(1).max(100).optional(),
|
|
63
|
+
sort: z.string().optional().describe("Sort field and direction"),
|
|
64
|
+
}, async (params) => {
|
|
65
|
+
try {
|
|
66
|
+
const { data } = await client.GET("/v1/skills/{id}/versions", {
|
|
67
|
+
params: {
|
|
68
|
+
path: { id: params.skillId },
|
|
69
|
+
query: paginationParams(params),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
server.tool("2kw_get_skill_version", "Get a skill version, including description, body, frontmatter and resources.", {
|
|
84
|
+
skillId: z.string(),
|
|
85
|
+
versionNumber: z.number().int().min(1),
|
|
86
|
+
}, async (params) => {
|
|
87
|
+
try {
|
|
88
|
+
const { data } = await client.GET("/v1/skills/{id}/versions/{versionNumber}", {
|
|
89
|
+
params: { path: { id: params.skillId, versionNumber: params.versionNumber } },
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
98
|
+
isError: true,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
server.tool("2kw_list_skill_labels", "List skill labels and the versions they point to.", { skillId: z.string() }, async (params) => {
|
|
103
|
+
try {
|
|
104
|
+
const { data } = await client.GET("/v1/skills/{id}/labels", {
|
|
105
|
+
params: { path: { id: params.skillId } },
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
114
|
+
isError: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
server.tool("2kw_resolve_skill", "Resolve a skill by name, name@label or name@version number.", { ref: z.string().min(1).describe("Skill reference: name, name@label or name@<n>") }, async (params) => {
|
|
119
|
+
try {
|
|
120
|
+
const { data } = await client.GET("/v1/skills/resolve", {
|
|
121
|
+
params: { query: { ref: params.ref } },
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
server.tool("2kw_import_skill", "Import a local SKILL.md or .zip file. Returns outcome, version, renamedFrom and skipped files. Zip directories before importing.", { filePath: z.string().min(1).describe("Local path to SKILL.md or a .zip archive") }, async (params) => {
|
|
135
|
+
try {
|
|
136
|
+
const info = await stat(params.filePath);
|
|
137
|
+
if (info.isDirectory())
|
|
138
|
+
throw new Error("Cannot import a directory; zip it first.");
|
|
139
|
+
const filename = basename(params.filePath);
|
|
140
|
+
const isZip = extname(filename).toLowerCase() === ".zip";
|
|
141
|
+
if (filename !== "SKILL.md" && !isZip) {
|
|
142
|
+
throw new Error("Import requires a SKILL.md or .zip file.");
|
|
143
|
+
}
|
|
144
|
+
const buffer = await readFile(params.filePath);
|
|
145
|
+
const formData = new FormData();
|
|
146
|
+
formData.append("file", new Blob([buffer], {
|
|
147
|
+
type: isZip ? "application/zip" : "text/markdown",
|
|
148
|
+
}), filename);
|
|
149
|
+
const { baseUrl, apiKey } = client._config;
|
|
150
|
+
const res = await fetch(`${baseUrl.replace(/\/+$/, "")}/v1/skills/import`, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
153
|
+
body: formData,
|
|
154
|
+
});
|
|
155
|
+
if (!res.ok) {
|
|
156
|
+
const body = await res.json().catch(() => ({}));
|
|
157
|
+
throw new BackboneApiError({
|
|
158
|
+
status: body.status ?? res.status,
|
|
159
|
+
error: body.title ?? body.error ?? res.statusText,
|
|
160
|
+
message: body.detail ?? body.message ?? `HTTP ${res.status}: ${res.statusText}`,
|
|
161
|
+
timestamp: body.timestamp ?? new Date().toISOString(),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const data = await res.json();
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
content: [{ type: "text", text: formatErrorForMcp(error) }],
|
|
172
|
+
isError: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=skills.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@2kw/ai-mcp-server",
|
|
3
|
-
"version": "6.
|
|
4
|
-
"description": "MCP server for 2kw.ai — EU-hosted AI platform: OpenAI-compatible LLM gateway, schema-driven document extraction, transcription, and cost observability.
|
|
3
|
+
"version": "6.2.0-dev.13",
|
|
4
|
+
"description": "MCP server for 2kw.ai — EU-hosted AI platform: OpenAI-compatible LLM gateway, schema-driven document extraction, transcription, agents with a knowledge base, and cost observability. 158 tools for Claude Code, Cursor, and Windsurf.",
|
|
5
5
|
"mcpName": "ai.2kw/mcp-server",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"openapi-fetch": "^0.13.5"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@types/node": "^22.
|
|
51
|
+
"@types/node": "^22.20.1",
|
|
52
52
|
"openapi-typescript": "^7.13.0",
|
|
53
53
|
"tsx": "^4.21.1",
|
|
54
54
|
"typescript": "^5.9.3"
|