@agentskit/mcp 0.2.17 → 0.2.20
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 +56 -2
- package/dist/bin.cjs +386 -120
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +176 -85
- package/dist/bin.js.map +1 -1
- package/dist/chunk-CKAUENP5.js +258 -0
- package/dist/chunk-CKAUENP5.js.map +1 -0
- package/dist/index.cjs +207 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +1 -1
- package/package.json +12 -8
- package/dist/chunk-F5SVUT7Z.js +0 -85
- package/dist/chunk-F5SVUT7Z.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -1,67 +1,198 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var tools = require('@agentskit/tools');
|
|
5
4
|
var adapters = require('@agentskit/adapters');
|
|
6
5
|
var catalog = require('@agentskit/adapters/catalog');
|
|
7
|
-
var
|
|
6
|
+
var tools = require('@agentskit/tools');
|
|
7
|
+
var core = require('@agentskit/core');
|
|
8
8
|
var runtime = require('@agentskit/runtime');
|
|
9
|
+
var mcp = require('@agentskit/tools/mcp');
|
|
10
|
+
|
|
11
|
+
var encoder = new TextEncoder();
|
|
12
|
+
var TOOL_NAME = /^[A-Za-z0-9_.-]+$/;
|
|
13
|
+
var invalid = (message) => new core.ConfigError({ code: core.ErrorCodes.AK_CONFIG_INVALID, message });
|
|
14
|
+
var assertNonEmptyString = (input, field, maxBytes) => {
|
|
15
|
+
if (typeof input !== "string" || input.trim().length === 0) {
|
|
16
|
+
throw invalid(`${field} must be a non-empty string`);
|
|
17
|
+
}
|
|
18
|
+
if (encoder.encode(input).byteLength > maxBytes) {
|
|
19
|
+
throw invalid(`${field} must not exceed ${maxBytes} bytes`);
|
|
20
|
+
}
|
|
21
|
+
return input.trim();
|
|
22
|
+
};
|
|
23
|
+
var assertToolName = (input, field = "tool name") => {
|
|
24
|
+
const value = assertNonEmptyString(input, field, 128);
|
|
25
|
+
if (!TOOL_NAME.test(value)) {
|
|
26
|
+
throw invalid(`${field} may contain only ASCII letters, digits, underscore, hyphen, and dot`);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
};
|
|
30
|
+
var assertPositiveInteger = (input, field, maximum) => {
|
|
31
|
+
if (!Number.isSafeInteger(input) || input < 1 || input > maximum) {
|
|
32
|
+
throw invalid(`${field} must be a safe integer between 1 and ${maximum}`);
|
|
33
|
+
}
|
|
34
|
+
return input;
|
|
35
|
+
};
|
|
36
|
+
var isRecord = (input) => {
|
|
37
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) return false;
|
|
38
|
+
try {
|
|
39
|
+
const prototype = Object.getPrototypeOf(input);
|
|
40
|
+
return prototype === Object.prototype || prototype === null;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
9
45
|
|
|
46
|
+
// src/agent-tool.ts
|
|
10
47
|
function createAgentTool(config) {
|
|
48
|
+
const id = assertToolName(config?.id, "agent tool id");
|
|
49
|
+
const description = assertNonEmptyString(config?.description, "agent tool description", 4096);
|
|
50
|
+
const systemPrompt = assertNonEmptyString(config?.systemPrompt, "agent tool systemPrompt", 65536);
|
|
51
|
+
if (!isRecord(config?.adapter) || typeof config.adapter.createSource !== "function") {
|
|
52
|
+
throw new core.ConfigError({
|
|
53
|
+
code: core.ErrorCodes.AK_CONFIG_INVALID,
|
|
54
|
+
message: "agent tool adapter must implement createSource"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const maxSteps = assertPositiveInteger(config.maxSteps ?? 8, "agent tool maxSteps", 100);
|
|
58
|
+
const maxTaskBytes = assertPositiveInteger(config.maxTaskBytes ?? 65536, "agent tool maxTaskBytes", 1048576);
|
|
11
59
|
const skill = {
|
|
12
|
-
name:
|
|
13
|
-
description
|
|
14
|
-
systemPrompt
|
|
60
|
+
name: id,
|
|
61
|
+
description,
|
|
62
|
+
systemPrompt
|
|
15
63
|
};
|
|
16
|
-
|
|
17
|
-
name:
|
|
18
|
-
description
|
|
64
|
+
const tool = {
|
|
65
|
+
name: id,
|
|
66
|
+
description,
|
|
19
67
|
schema: {
|
|
20
68
|
type: "object",
|
|
21
69
|
properties: { task: { type: "string", description: "The task or input for the agent." } },
|
|
22
|
-
required: ["task"]
|
|
70
|
+
required: ["task"],
|
|
71
|
+
additionalProperties: false
|
|
23
72
|
},
|
|
24
73
|
execute: async (args) => {
|
|
25
|
-
|
|
26
|
-
|
|
74
|
+
if (typeof args.task !== "string" || args.task.trim().length === 0) {
|
|
75
|
+
throw new core.ToolError({
|
|
76
|
+
code: core.ErrorCodes.AK_TOOL_INVALID_INPUT,
|
|
77
|
+
message: "agent tool task must be a non-empty string"
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (new TextEncoder().encode(args.task).byteLength > maxTaskBytes) {
|
|
81
|
+
throw new core.ToolError({
|
|
82
|
+
code: core.ErrorCodes.AK_TOOL_INVALID_INPUT,
|
|
83
|
+
message: `agent tool task must not exceed ${maxTaskBytes} bytes`
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const runtime$1 = runtime.createRuntime({ adapter: config.adapter, maxSteps });
|
|
87
|
+
const result = await runtime$1.run(args.task, { skill });
|
|
27
88
|
return { content: result.content, steps: result.steps };
|
|
28
89
|
}
|
|
29
90
|
};
|
|
91
|
+
return Object.freeze(tool);
|
|
30
92
|
}
|
|
31
93
|
|
|
32
94
|
// src/registry-fetch.ts
|
|
33
95
|
var HOSTED = "https://registry.agentskit.io/r";
|
|
34
96
|
var RAW = "https://raw.githubusercontent.com/AgentsKit-io/agentskit-registry/main";
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
97
|
+
var REGISTRY_ID = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
98
|
+
var isRecord2 = (input) => input !== null && typeof input === "object" && !Array.isArray(input);
|
|
99
|
+
var boundedString = (input, maximum) => {
|
|
100
|
+
if (typeof input !== "string" || input.trim().length === 0) return null;
|
|
101
|
+
return new TextEncoder().encode(input).byteLength <= maximum ? input.trim() : null;
|
|
102
|
+
};
|
|
103
|
+
var readBounded = async (response, maximum) => {
|
|
104
|
+
const declared = Number(response.headers.get("content-length"));
|
|
105
|
+
if (Number.isFinite(declared) && declared > maximum) return null;
|
|
106
|
+
if (!response.body) return "";
|
|
107
|
+
const reader = response.body.getReader();
|
|
108
|
+
const decoder = new TextDecoder();
|
|
109
|
+
let bytes = 0;
|
|
110
|
+
let text = "";
|
|
111
|
+
while (true) {
|
|
112
|
+
const chunk = await reader.read();
|
|
113
|
+
if (chunk.done) break;
|
|
114
|
+
bytes += chunk.value.byteLength;
|
|
115
|
+
if (bytes > maximum) {
|
|
116
|
+
await reader.cancel().catch(() => void 0);
|
|
41
117
|
return null;
|
|
42
118
|
}
|
|
119
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
120
|
+
}
|
|
121
|
+
return text + decoder.decode();
|
|
122
|
+
};
|
|
123
|
+
var requestText = async (url, fetchImpl, options) => {
|
|
124
|
+
if (options.signal?.aborted) return null;
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
let resolveAbort;
|
|
127
|
+
const aborted = new Promise((resolve) => {
|
|
128
|
+
resolveAbort = resolve;
|
|
129
|
+
});
|
|
130
|
+
const abort = () => {
|
|
131
|
+
controller.abort();
|
|
132
|
+
resolveAbort?.(null);
|
|
43
133
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
134
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
135
|
+
let timer;
|
|
136
|
+
try {
|
|
137
|
+
const request = (async () => {
|
|
138
|
+
const response = await fetchImpl(url, { signal: controller.signal });
|
|
139
|
+
if (!response.ok) return null;
|
|
140
|
+
return readBounded(response, options.maxResponseBytes);
|
|
141
|
+
})().catch(() => null);
|
|
142
|
+
const timeout = new Promise((resolve) => {
|
|
143
|
+
timer = setTimeout(() => {
|
|
144
|
+
controller.abort();
|
|
145
|
+
resolve(null);
|
|
146
|
+
}, options.timeoutMs);
|
|
147
|
+
});
|
|
148
|
+
return await Promise.race([request, timeout, aborted]);
|
|
149
|
+
} finally {
|
|
150
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
151
|
+
options.signal?.removeEventListener("abort", abort);
|
|
47
152
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
153
|
+
};
|
|
154
|
+
var requestJson = async (url, fetchImpl, options) => {
|
|
155
|
+
const text = await requestText(url, fetchImpl, options);
|
|
156
|
+
if (text === null) return null;
|
|
51
157
|
try {
|
|
52
|
-
|
|
53
|
-
src = res.ok ? await res.text() : null;
|
|
158
|
+
return JSON.parse(text);
|
|
54
159
|
} catch {
|
|
55
|
-
|
|
160
|
+
return null;
|
|
56
161
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (!
|
|
60
|
-
|
|
162
|
+
};
|
|
163
|
+
async function fetchAgentSkill(id, fetchImpl = globalThis.fetch, options = {}) {
|
|
164
|
+
if (!REGISTRY_ID.test(id) || typeof fetchImpl !== "function") return null;
|
|
165
|
+
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
166
|
+
const maxResponseBytes = options.maxResponseBytes ?? 131072;
|
|
167
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 12e4 || !Number.isSafeInteger(maxResponseBytes) || maxResponseBytes < 1 || maxResponseBytes > 1048576) return null;
|
|
168
|
+
const bounds = { maxResponseBytes, signal: options.signal, timeoutMs };
|
|
169
|
+
const hosted = await requestJson(`${HOSTED}/${id}.json`, fetchImpl, bounds);
|
|
170
|
+
if (isRecord2(hosted)) {
|
|
171
|
+
if (hosted.skill === null) return null;
|
|
172
|
+
if (isRecord2(hosted.skill)) {
|
|
173
|
+
const systemPrompt2 = boundedString(hosted.skill.systemPrompt, 65536);
|
|
174
|
+
if (systemPrompt2) {
|
|
175
|
+
const description = boundedString(hosted.description, 4096) ?? id;
|
|
176
|
+
return Object.freeze({ description, id, systemPrompt: systemPrompt2 });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const meta = await requestJson(`${RAW}/registry/${id}/meta.json`, fetchImpl, bounds);
|
|
181
|
+
if (!isRecord2(meta)) return null;
|
|
182
|
+
const source = await requestText(`${RAW}/registry/${id}/agent.ts`, fetchImpl, bounds);
|
|
183
|
+
if (!source) return null;
|
|
184
|
+
const match = source.match(/systemPrompt:\s*`((?:\\.|[^`\\])*)`/);
|
|
185
|
+
if (!match) return null;
|
|
186
|
+
const systemPrompt = boundedString(
|
|
187
|
+
match[1].replace(/\\`/g, "`").replace(/\\\$\{/g, "${"),
|
|
188
|
+
65536
|
|
189
|
+
);
|
|
190
|
+
if (!systemPrompt) return null;
|
|
191
|
+
return Object.freeze({
|
|
61
192
|
id,
|
|
62
|
-
description: meta.description ?? id,
|
|
63
|
-
systemPrompt
|
|
64
|
-
};
|
|
193
|
+
description: boundedString(meta.description, 4096) ?? id,
|
|
194
|
+
systemPrompt
|
|
195
|
+
});
|
|
65
196
|
}
|
|
66
197
|
|
|
67
198
|
// src/index.ts
|
|
@@ -76,131 +207,266 @@ function processStdio() {
|
|
|
76
207
|
};
|
|
77
208
|
}
|
|
78
209
|
function createAgentsKitMcpServer(options) {
|
|
210
|
+
if (!isRecord(options) || !Array.isArray(options.tools)) {
|
|
211
|
+
throw new core.ConfigError({
|
|
212
|
+
code: core.ErrorCodes.AK_CONFIG_INVALID,
|
|
213
|
+
message: "MCP server options must include a tools array"
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const names = /* @__PURE__ */ new Set();
|
|
217
|
+
const tools = options.tools.map((tool, index) => {
|
|
218
|
+
if (!isRecord(tool)) {
|
|
219
|
+
throw new core.ConfigError({
|
|
220
|
+
code: core.ErrorCodes.AK_CONFIG_INVALID,
|
|
221
|
+
message: `tools[${index}] must be a tool definition`
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
const name = assertToolName(tool.name, `tools[${index}].name`);
|
|
225
|
+
if (names.has(name)) {
|
|
226
|
+
throw new core.ConfigError({
|
|
227
|
+
code: core.ErrorCodes.AK_CONFIG_INVALID,
|
|
228
|
+
message: `tool names must be unique; duplicate "${name}"`
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
names.add(name);
|
|
232
|
+
return Object.freeze({ ...tool, name });
|
|
233
|
+
});
|
|
234
|
+
const serverInfo = options.serverInfo === void 0 ? { name: "agentskit-mcp", version: "1.0.0" } : {
|
|
235
|
+
name: assertNonEmptyString(options.serverInfo?.name, "serverInfo.name", 128),
|
|
236
|
+
version: assertNonEmptyString(options.serverInfo?.version, "serverInfo.version", 64)
|
|
237
|
+
};
|
|
238
|
+
if (options.transport !== void 0 && (!isRecord(options.transport) || typeof options.transport.send !== "function" || typeof options.transport.onMessage !== "function")) {
|
|
239
|
+
throw new core.ConfigError({
|
|
240
|
+
code: core.ErrorCodes.AK_CONFIG_INVALID,
|
|
241
|
+
message: "transport must implement send and onMessage"
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const onEvent = options.onEvent === void 0 ? void 0 : (event) => {
|
|
245
|
+
try {
|
|
246
|
+
const delivered = options.onEvent(Object.freeze({ ...event }));
|
|
247
|
+
if (delivered !== null && (typeof delivered === "object" || typeof delivered === "function")) {
|
|
248
|
+
const then = delivered.then;
|
|
249
|
+
if (typeof then === "function") void Promise.resolve(delivered).catch(() => void 0);
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
};
|
|
79
254
|
const transport = options.transport ?? mcp.createStdioTransport(processStdio());
|
|
80
255
|
return mcp.createMcpServer({
|
|
81
256
|
transport,
|
|
82
|
-
tools
|
|
83
|
-
serverInfo
|
|
84
|
-
onEvent
|
|
257
|
+
tools,
|
|
258
|
+
serverInfo,
|
|
259
|
+
onEvent
|
|
85
260
|
});
|
|
86
261
|
}
|
|
87
262
|
|
|
88
|
-
// src/
|
|
89
|
-
var
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (has(
|
|
114
|
-
|
|
263
|
+
// src/cli.ts
|
|
264
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
265
|
+
"--agents",
|
|
266
|
+
"--api-key",
|
|
267
|
+
"--base-url",
|
|
268
|
+
"--fs-root",
|
|
269
|
+
"--max-steps",
|
|
270
|
+
"--model",
|
|
271
|
+
"--provider",
|
|
272
|
+
"--sqlite",
|
|
273
|
+
"--tools"
|
|
274
|
+
]);
|
|
275
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["--allow-shell", "--help"]);
|
|
276
|
+
var TOOL_IDS = /* @__PURE__ */ new Set(["fetch", "filesystem", "search", "shell", "sqlite"]);
|
|
277
|
+
var csv = (input) => [...new Set(input.split(",").map((value) => value.trim()).filter(Boolean))];
|
|
278
|
+
var parseMcpCliArgs = (argv) => {
|
|
279
|
+
const values = /* @__PURE__ */ new Map();
|
|
280
|
+
const booleans = /* @__PURE__ */ new Set();
|
|
281
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
282
|
+
const argument = argv[index];
|
|
283
|
+
if (BOOLEAN_FLAGS.has(argument)) {
|
|
284
|
+
if (booleans.has(argument)) return { message: `duplicate flag: ${argument}`, status: "rejected" };
|
|
285
|
+
booleans.add(argument);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (!VALUE_FLAGS.has(argument)) return { message: `unknown argument: ${argument}`, status: "rejected" };
|
|
289
|
+
if (values.has(argument)) return { message: `duplicate flag: ${argument}`, status: "rejected" };
|
|
290
|
+
const value = argv[index + 1];
|
|
291
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
292
|
+
return { message: `missing value for ${argument}`, status: "rejected" };
|
|
293
|
+
}
|
|
294
|
+
values.set(argument, value);
|
|
295
|
+
index += 1;
|
|
115
296
|
}
|
|
116
|
-
|
|
117
|
-
|
|
297
|
+
const tools = values.has("--tools") ? csv(values.get("--tools")) : ["fetch", "search"];
|
|
298
|
+
const unknownTool = tools.find((tool) => !TOOL_IDS.has(tool));
|
|
299
|
+
if (unknownTool) return { message: `unknown tool: ${unknownTool}`, status: "rejected" };
|
|
300
|
+
const agents = values.has("--agents") ? csv(values.get("--agents")) : [];
|
|
301
|
+
const maxStepsText = values.get("--max-steps") ?? "8";
|
|
302
|
+
const maxSteps = Number(maxStepsText);
|
|
303
|
+
if (!Number.isSafeInteger(maxSteps) || maxSteps < 1 || maxSteps > 100) {
|
|
304
|
+
return { message: "--max-steps must be a safe integer between 1 and 100", status: "rejected" };
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
options: {
|
|
308
|
+
agents,
|
|
309
|
+
allowShell: booleans.has("--allow-shell"),
|
|
310
|
+
apiKey: values.get("--api-key"),
|
|
311
|
+
baseUrl: values.get("--base-url"),
|
|
312
|
+
fsRoot: values.get("--fs-root"),
|
|
313
|
+
help: booleans.has("--help"),
|
|
314
|
+
maxSteps,
|
|
315
|
+
model: values.get("--model"),
|
|
316
|
+
provider: (values.get("--provider") ?? "openai").toLowerCase(),
|
|
317
|
+
sqlite: values.get("--sqlite"),
|
|
318
|
+
tools
|
|
319
|
+
},
|
|
320
|
+
status: "parsed"
|
|
321
|
+
};
|
|
322
|
+
};
|
|
118
323
|
var KEYED = {
|
|
119
|
-
openai: adapters.openai,
|
|
120
324
|
anthropic: adapters.anthropic,
|
|
121
|
-
|
|
325
|
+
cerebras: adapters.cerebras,
|
|
326
|
+
cohere: adapters.cohere,
|
|
122
327
|
deepseek: adapters.deepseek,
|
|
328
|
+
fireworks: adapters.fireworks,
|
|
329
|
+
gemini: adapters.gemini,
|
|
123
330
|
grok: adapters.grok,
|
|
124
331
|
groq: adapters.groq,
|
|
332
|
+
huggingface: adapters.huggingface,
|
|
333
|
+
kimi: adapters.kimi,
|
|
334
|
+
llamacpp: adapters.llamacpp,
|
|
335
|
+
lmstudio: adapters.lmstudio,
|
|
125
336
|
mistral: adapters.mistral,
|
|
126
|
-
|
|
127
|
-
together: adapters.together,
|
|
128
|
-
fireworks: adapters.fireworks,
|
|
337
|
+
openai: adapters.openai,
|
|
129
338
|
openrouter: adapters.openrouter,
|
|
130
|
-
cerebras: adapters.cerebras,
|
|
131
|
-
kimi: adapters.kimi,
|
|
132
|
-
huggingface: adapters.huggingface,
|
|
133
339
|
qwen: adapters.qwen,
|
|
134
|
-
|
|
135
|
-
vllm: adapters.vllm
|
|
136
|
-
llamacpp: adapters.llamacpp
|
|
340
|
+
together: adapters.together,
|
|
341
|
+
vllm: adapters.vllm
|
|
137
342
|
};
|
|
138
343
|
var LOCAL = { ollama: adapters.ollama };
|
|
139
|
-
var LOCAL_COMPAT = /* @__PURE__ */ new Set(["
|
|
344
|
+
var LOCAL_COMPAT = /* @__PURE__ */ new Set(["llamacpp", "lmstudio", "vllm"]);
|
|
140
345
|
var DEFAULT_MODEL = {
|
|
141
|
-
openai: "gpt-4o",
|
|
142
346
|
anthropic: "claude-sonnet-4-6",
|
|
143
|
-
gemini: "gemini-2.0-flash",
|
|
144
347
|
deepseek: "deepseek-chat",
|
|
348
|
+
gemini: "gemini-2.0-flash",
|
|
145
349
|
grok: "grok-2",
|
|
146
350
|
groq: "llama-3.3-70b-versatile",
|
|
147
351
|
mistral: "mistral-large-latest",
|
|
148
|
-
ollama: "llama3"
|
|
352
|
+
ollama: "llama3",
|
|
353
|
+
openai: "gpt-4o"
|
|
354
|
+
};
|
|
355
|
+
var MCP_CLI_HELP = [
|
|
356
|
+
"Usage: agentskit-mcp [options]",
|
|
357
|
+
"--tools <fetch,search,filesystem,shell,sqlite>",
|
|
358
|
+
"--agents <registry-ids> --provider <provider> --model <model>",
|
|
359
|
+
"--fs-root <dir> --sqlite <file> --allow-shell"
|
|
360
|
+
].join("\n");
|
|
361
|
+
var buildPrimitiveTools = (options, warn2) => {
|
|
362
|
+
const tools$1 = [];
|
|
363
|
+
if (options.tools.includes("fetch")) tools$1.push(tools.fetchUrl());
|
|
364
|
+
if (options.tools.includes("search")) tools$1.push(tools.webSearch());
|
|
365
|
+
if (options.tools.includes("filesystem")) {
|
|
366
|
+
if (options.fsRoot) tools$1.push(...tools.filesystem({ basePath: options.fsRoot }));
|
|
367
|
+
else warn2('skipping "filesystem": pass --fs-root <dir>');
|
|
368
|
+
}
|
|
369
|
+
if (options.tools.includes("sqlite")) {
|
|
370
|
+
if (options.sqlite) tools$1.push(tools.sqliteQueryTool({ path: options.sqlite }));
|
|
371
|
+
else warn2('skipping "sqlite": pass --sqlite <file>');
|
|
372
|
+
}
|
|
373
|
+
if (options.tools.includes("shell")) {
|
|
374
|
+
if (options.allowShell) tools$1.push(tools.shell());
|
|
375
|
+
else warn2('skipping "shell": pass --allow-shell (runs commands)');
|
|
376
|
+
}
|
|
377
|
+
return tools$1;
|
|
149
378
|
};
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
const model = flag("--model") ?? DEFAULT_MODEL[provider];
|
|
379
|
+
var resolveAdapter = (options, env, warn2) => {
|
|
380
|
+
const model = options.model ?? DEFAULT_MODEL[options.provider];
|
|
153
381
|
if (!model) {
|
|
154
|
-
|
|
382
|
+
warn2(`--agents needs a model for "${options.provider}": pass --model`);
|
|
155
383
|
return null;
|
|
156
384
|
}
|
|
157
|
-
const
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
385
|
+
const local = LOCAL[options.provider];
|
|
386
|
+
if (local) return local({ baseUrl: options.baseUrl, model });
|
|
387
|
+
const envName = `${options.provider.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
388
|
+
const apiKey = options.apiKey ?? env[envName] ?? (LOCAL_COMPAT.has(options.provider) ? "local" : void 0);
|
|
160
389
|
if (!apiKey) {
|
|
161
|
-
|
|
390
|
+
warn2(`--agents needs a key for "${options.provider}": pass --api-key or set ${envName}`);
|
|
162
391
|
return null;
|
|
163
392
|
}
|
|
164
|
-
|
|
393
|
+
const keyed = KEYED[options.provider];
|
|
394
|
+
if (keyed) return keyed({ apiKey, baseUrl: options.baseUrl, model });
|
|
165
395
|
try {
|
|
166
|
-
return catalog.dispatchFromCatalog({
|
|
396
|
+
return catalog.dispatchFromCatalog({ apiKey, baseUrl: options.baseUrl, model, provider: options.provider });
|
|
167
397
|
} catch {
|
|
168
|
-
|
|
398
|
+
warn2(`unknown or incompatible provider "${options.provider}"`);
|
|
169
399
|
return null;
|
|
170
400
|
}
|
|
171
|
-
}
|
|
172
|
-
async
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
401
|
+
};
|
|
402
|
+
var runMcpCli = async (argv, dependencies = {}) => {
|
|
403
|
+
const warn2 = dependencies.warn ?? (() => void 0);
|
|
404
|
+
const parsed = parseMcpCliArgs(argv);
|
|
405
|
+
if (parsed.status === "rejected") {
|
|
406
|
+
warn2(parsed.message);
|
|
407
|
+
return { exitCode: 1, status: "rejected" };
|
|
408
|
+
}
|
|
409
|
+
if (parsed.options.help) {
|
|
410
|
+
warn2(MCP_CLI_HELP);
|
|
411
|
+
return { exitCode: 0, status: "help" };
|
|
412
|
+
}
|
|
413
|
+
const tools = buildPrimitiveTools(parsed.options, warn2);
|
|
414
|
+
if (parsed.options.agents.length > 0) {
|
|
415
|
+
const adapter = resolveAdapter(parsed.options, dependencies.env ?? process.env, warn2);
|
|
416
|
+
if (adapter) {
|
|
417
|
+
const fetchSkill = dependencies.fetchSkill ?? fetchAgentSkill;
|
|
418
|
+
for (const id of parsed.options.agents) {
|
|
419
|
+
const skill = await fetchSkill(id).catch(() => null);
|
|
420
|
+
if (!skill) {
|
|
421
|
+
warn2(`skipping agent "${id}": not found or not runnable`);
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
tools.push(createAgentTool({ ...skill, adapter, maxSteps: parsed.options.maxSteps }));
|
|
425
|
+
}
|
|
183
426
|
}
|
|
184
|
-
tools.push(
|
|
185
|
-
createAgentTool({ id: skill.id, description: skill.description, systemPrompt: skill.systemPrompt, adapter })
|
|
186
|
-
);
|
|
187
427
|
}
|
|
188
|
-
return tools;
|
|
189
|
-
}
|
|
190
|
-
async function main() {
|
|
191
|
-
const tools = [...buildTools(), ...await buildAgentTools()];
|
|
192
428
|
if (tools.length === 0) {
|
|
193
|
-
|
|
194
|
-
|
|
429
|
+
warn2("no tools or agents enabled \u2014 nothing to serve");
|
|
430
|
+
return { exitCode: 1, status: "rejected" };
|
|
195
431
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
432
|
+
const seen = /* @__PURE__ */ new Set();
|
|
433
|
+
const duplicate = tools.find((tool) => {
|
|
434
|
+
if (seen.has(tool.name)) return true;
|
|
435
|
+
seen.add(tool.name);
|
|
436
|
+
return false;
|
|
201
437
|
});
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
438
|
+
if (duplicate) {
|
|
439
|
+
warn2(`duplicate tool name: ${duplicate.name}`);
|
|
440
|
+
return { exitCode: 1, status: "rejected" };
|
|
441
|
+
}
|
|
442
|
+
const createServer = dependencies.createServer ?? createAgentsKitMcpServer;
|
|
443
|
+
let server;
|
|
444
|
+
try {
|
|
445
|
+
server = createServer({
|
|
446
|
+
tools,
|
|
447
|
+
onEvent: (event) => {
|
|
448
|
+
if (event.type === "error") warn2(`tool error (${event.tool ?? "unknown"}): ${event.error ?? "unknown"}`);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
} catch {
|
|
452
|
+
warn2("failed to start MCP server");
|
|
453
|
+
return { exitCode: 1, status: "rejected" };
|
|
454
|
+
}
|
|
455
|
+
const toolNames = tools.map((tool) => tool.name);
|
|
456
|
+
warn2(`serving ${toolNames.length} item(s) over stdio (${toolNames.join(", ")})`);
|
|
457
|
+
return { exitCode: 0, server, status: "started", toolNames };
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// src/bin.ts
|
|
461
|
+
var warn = (message) => {
|
|
462
|
+
process.stderr.write(`agentskit-mcp: ${message}
|
|
463
|
+
`);
|
|
464
|
+
};
|
|
465
|
+
void runMcpCli(process.argv.slice(2), { warn }).then((result) => {
|
|
466
|
+
process.exitCode = result.exitCode;
|
|
467
|
+
}).catch(() => {
|
|
468
|
+
warn("unexpected startup failure");
|
|
469
|
+
process.exitCode = 1;
|
|
470
|
+
});
|
|
205
471
|
//# sourceMappingURL=bin.cjs.map
|
|
206
472
|
//# sourceMappingURL=bin.cjs.map
|