@2kw/ai-mcp-server 6.4.0-dev.7 → 6.4.0-dev.8
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/lib/agent-run.js +42 -14
- package/dist/tools/conversion.js +7 -21
- package/dist/tools/skills.js +5 -16
- package/package.json +1 -1
package/dist/lib/agent-run.js
CHANGED
|
@@ -81,9 +81,25 @@ function parseArguments(raw) {
|
|
|
81
81
|
return raw;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* A connector tool's open approval, decoded from the standard `mcp_approval_request` item (#949). The item
|
|
86
|
+
* is the MCP twin of `backbone:approval_request` (#805): it names the server and the tool, carries no call
|
|
87
|
+
* id, policy class or status, and exists only while the decision is open, so its id doubles as the call id
|
|
88
|
+
* and the tool is named as the approval row stores it, `mcp__<server_label>__<tool>`.
|
|
89
|
+
*/
|
|
90
|
+
function connectorApproval(i) {
|
|
91
|
+
return {
|
|
92
|
+
approvalId: String(i.id),
|
|
93
|
+
callId: String(i.id),
|
|
94
|
+
tool: `mcp__${String(i.server_label)}__${String(i.name)}`,
|
|
95
|
+
arguments: parseArguments(i.arguments),
|
|
96
|
+
policyClass: "unknown",
|
|
97
|
+
reason: null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
84
100
|
/**
|
|
85
101
|
* Output item types the envelope decodes, or that never hold a run: text, reasoning and finished
|
|
86
|
-
* connector calls. A pause on anything else
|
|
102
|
+
* connector calls. A pause on anything else is named.
|
|
87
103
|
* `backbone:tool_image` is an image a finished `ViewImage` call attached (#1244): it never holds a run.
|
|
88
104
|
*/
|
|
89
105
|
const DECODED_ITEM_TYPES = new Set([
|
|
@@ -94,6 +110,7 @@ const DECODED_ITEM_TYPES = new Set([
|
|
|
94
110
|
"backbone:approval_request",
|
|
95
111
|
"backbone:connector_auth_request",
|
|
96
112
|
"backbone:tool_image",
|
|
113
|
+
"mcp_approval_request",
|
|
97
114
|
"mcp_call",
|
|
98
115
|
"mcp_list_tools",
|
|
99
116
|
]);
|
|
@@ -135,17 +152,20 @@ export function buildRunEnvelope(result, agentRef, chatUrl = DEFAULT_CHAT_URL) {
|
|
|
135
152
|
String(i.call_id),
|
|
136
153
|
i.status === "incomplete" ? "incomplete" : "completed",
|
|
137
154
|
]));
|
|
138
|
-
const pendingApprovals =
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
const pendingApprovals = [
|
|
156
|
+
...output
|
|
157
|
+
// Only an open request is pending; judge- or grant-decided requests (#634, #629) carry another status.
|
|
158
|
+
.filter((i) => i.type === "backbone:approval_request" && (i.status === undefined || i.status === "in_progress"))
|
|
159
|
+
.map((i) => ({
|
|
160
|
+
approvalId: String(i.id),
|
|
161
|
+
callId: String(i.call_id),
|
|
162
|
+
tool: String(i.tool),
|
|
163
|
+
arguments: parseArguments(i.arguments),
|
|
164
|
+
policyClass: String(i.policy_class),
|
|
165
|
+
reason: typeof i.reason === "string" && i.reason ? i.reason : null,
|
|
166
|
+
})),
|
|
167
|
+
...output.filter((i) => i.type === "mcp_approval_request").map(connectorApproval),
|
|
168
|
+
];
|
|
149
169
|
// The one decoding rule (#1086): only an open request with its id, call id, label and host.
|
|
150
170
|
const connectRequests = pendingConnectionsOf(output);
|
|
151
171
|
const pendingConnections = connectRequests.map(({ serverLabel, host, reason, destinations }) => ({
|
|
@@ -209,8 +229,8 @@ export function buildRunEnvelope(result, agentRef, chatUrl = DEFAULT_CHAT_URL) {
|
|
|
209
229
|
const approvalsSuffix = pendingApprovals.length > 0
|
|
210
230
|
? " Show the pending approvals to the user and pass their decisions in the same call, within the same window."
|
|
211
231
|
: "";
|
|
212
|
-
//
|
|
213
|
-
// envelope
|
|
232
|
+
// An item type this server does not decode (a connector approval is decoded since #949) can leave
|
|
233
|
+
// the envelope under-reporting what is actually pending; say so rather than sound falsely complete
|
|
214
234
|
// (#1254 review). The continuation itself still refuses an incomplete answer (400
|
|
215
235
|
// incomplete_tool_outputs, decideErrorText's hint), this only tells the assistant to expect that.
|
|
216
236
|
const undecodedTypes = extraUndecodedTypes(output);
|
|
@@ -221,6 +241,14 @@ export function buildRunEnvelope(result, agentRef, chatUrl = DEFAULT_CHAT_URL) {
|
|
|
221
241
|
: "";
|
|
222
242
|
next = `${connectPrefix}${relay}${approvalsSuffix}${undecodedSuffix}`;
|
|
223
243
|
}
|
|
244
|
+
else if (status === "requires_tool_output" && pendingConnections.length > 0 && pendingApprovals.length > 0 && pendingToolCalls.length === 0 && ref && responseId) {
|
|
245
|
+
// A continuation must decide every pending approval (400 incomplete_tool_outputs otherwise), so a
|
|
246
|
+
// fresh request is no way on; decide answers them and the engine re-checks access itself (#949 review).
|
|
247
|
+
next =
|
|
248
|
+
`Tell the user to ${connectionsPhrase(pendingConnections)} in ${chatUrl}/connectors. ` +
|
|
249
|
+
"Show the pending approvals to the user; after they decide each one, call 2kw_decide_agent_approvals with agent " +
|
|
250
|
+
`${JSON.stringify(ref)} and responseId ${JSON.stringify(responseId)}.`;
|
|
251
|
+
}
|
|
224
252
|
else if (status === "requires_tool_output" && pendingConnections.length > 0 && pendingToolCalls.length === 0 && responseId) {
|
|
225
253
|
// A connector-only pause (no relayed call, so 2kw_decide_agent_approvals has nothing to decide,
|
|
226
254
|
// spec M11) has no tool here to continue it by id, and a connect pause cannot be continued by
|
package/dist/tools/conversion.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { formatErrorForMcp } from "../errors.js";
|
|
5
5
|
import { getMimeType } from "../mime.js";
|
|
6
6
|
/**
|
|
7
7
|
* Map user-friendly format names to backend OutputFormat enum values.
|
|
@@ -167,27 +167,13 @@ export function register(server, client) {
|
|
|
167
167
|
if (Object.keys(nestedOpts).length > 0) {
|
|
168
168
|
formData.append("options", new Blob([JSON.stringify(nestedOpts)], { type: "application/json" }));
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
:
|
|
175
|
-
const res = await fetch(url, {
|
|
176
|
-
method: "POST",
|
|
177
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
178
|
-
body: formData,
|
|
170
|
+
// Placeholder body for the generated type; bodySerializer sends the real parts.
|
|
171
|
+
const result = await client.POST(isAsync ? "/v1/convert/file/async" : "/v1/convert/file", {
|
|
172
|
+
params: { query: { pipeline } },
|
|
173
|
+
body: { files: [] },
|
|
174
|
+
bodySerializer: () => formData,
|
|
179
175
|
});
|
|
180
|
-
|
|
181
|
-
let body;
|
|
182
|
-
try {
|
|
183
|
-
body = await res.json();
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
body = { error: res.statusText, message: `HTTP ${res.status}: ${res.statusText}`, status: res.status, timestamp: new Date().toISOString() };
|
|
187
|
-
}
|
|
188
|
-
throw new BackboneApiError(body);
|
|
189
|
-
}
|
|
190
|
-
const data = await res.json();
|
|
176
|
+
const data = result.data;
|
|
191
177
|
if (isAsync) {
|
|
192
178
|
const taskId = data?.taskId;
|
|
193
179
|
if (waitForCompletion && taskId) {
|
package/dist/tools/skills.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
3
|
import { basename, extname } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { formatErrorForMcp } from "../errors.js";
|
|
5
5
|
// Spring accepts flat pagination parameters despite the generated pageable wrapper.
|
|
6
6
|
function paginationParams(params) {
|
|
7
7
|
return {
|
|
@@ -160,22 +160,11 @@ export function register(server, client) {
|
|
|
160
160
|
formData.append("file", new Blob([buffer], {
|
|
161
161
|
type: isZip ? "application/zip" : "text/markdown",
|
|
162
162
|
}), filename);
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
body: formData,
|
|
163
|
+
// Placeholder body for the generated type; bodySerializer sends the real part.
|
|
164
|
+
const { data } = await client.POST("/v1/skills/import", {
|
|
165
|
+
body: { file: "" },
|
|
166
|
+
bodySerializer: () => formData,
|
|
168
167
|
});
|
|
169
|
-
if (!res.ok) {
|
|
170
|
-
const body = await res.json().catch(() => ({}));
|
|
171
|
-
throw new BackboneApiError({
|
|
172
|
-
status: body.status ?? res.status,
|
|
173
|
-
error: body.title ?? body.error ?? res.statusText,
|
|
174
|
-
message: body.detail ?? body.message ?? `HTTP ${res.status}: ${res.statusText}`,
|
|
175
|
-
timestamp: body.timestamp ?? new Date().toISOString(),
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
const data = await res.json();
|
|
179
168
|
return {
|
|
180
169
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
181
170
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@2kw/ai-mcp-server",
|
|
3
|
-
"version": "6.4.0-dev.
|
|
3
|
+
"version": "6.4.0-dev.8",
|
|
4
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": [
|