@agentskit/mcp 0.2.17 → 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/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 mcp = require('@agentskit/tools/mcp');
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: config.id,
13
- description: config.description,
14
- systemPrompt: config.systemPrompt
60
+ name: id,
61
+ description,
62
+ systemPrompt
15
63
  };
16
- return {
17
- name: config.id,
18
- description: config.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
- const runtime$1 = runtime.createRuntime({ adapter: config.adapter, maxSteps: config.maxSteps ?? 8 });
26
- const result = await runtime$1.run(String(args.task ?? ""), { skill });
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
- async function fetchAgentSkill(id, fetchImpl = globalThis.fetch) {
36
- const tryUrl = async (url) => {
37
- try {
38
- const res = await fetchImpl(url);
39
- return res.ok ? await res.json() : null;
40
- } catch {
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
- const hosted = await tryUrl(`${HOSTED}/${id}.json`);
45
- if (hosted?.skill?.systemPrompt) {
46
- return { id, description: hosted.description ?? id, systemPrompt: hosted.skill.systemPrompt };
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
- const meta = await tryUrl(`${RAW}/registry/${id}/meta.json`);
49
- if (!meta) return null;
50
- let src = null;
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
- const res = await fetchImpl(`${RAW}/registry/${id}/agent.ts`);
53
- src = res.ok ? await res.text() : null;
158
+ return JSON.parse(text);
54
159
  } catch {
55
- src = null;
160
+ return null;
56
161
  }
57
- if (!src) return null;
58
- const m = src.match(/systemPrompt:\s*`((?:\\.|[^`\\])*)`/);
59
- if (!m) return null;
60
- return {
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: m[1].replace(/\\`/g, "`").replace(/\\\$\{/g, "${")
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: options.tools,
83
- serverInfo: options.serverInfo ?? { name: "agentskit-mcp", version: "0.1.0" },
84
- onEvent: options.onEvent
257
+ tools,
258
+ serverInfo,
259
+ onEvent
85
260
  });
86
261
  }
87
262
 
88
- // src/bin.ts
89
- var warn = (msg) => process.stderr.write(`agentskit-mcp: ${msg}
90
- `);
91
- var flag = (name) => {
92
- const i = process.argv.indexOf(name);
93
- return i >= 0 ? process.argv[i + 1] : void 0;
94
- };
95
- var has = (name) => process.argv.includes(name);
96
- function buildTools() {
97
- if (!has("--tools")) return [tools.fetchUrl(), tools.webSearch()];
98
- const requested = (flag("--tools") ?? "").split(",").map((s) => s.trim());
99
- const tools$1 = [];
100
- if (requested.includes("fetch")) tools$1.push(tools.fetchUrl());
101
- if (requested.includes("search")) tools$1.push(tools.webSearch());
102
- if (requested.includes("filesystem")) {
103
- const root = flag("--fs-root");
104
- if (root) tools$1.push(...tools.filesystem({ basePath: root }));
105
- else warn('skipping "filesystem": pass --fs-root <dir>');
106
- }
107
- if (requested.includes("sqlite")) {
108
- const file = flag("--sqlite");
109
- if (file) tools$1.push(tools.sqliteQueryTool({ path: file }));
110
- else warn('skipping "sqlite": pass --sqlite <file>');
111
- }
112
- if (requested.includes("shell")) {
113
- if (has("--allow-shell")) tools$1.push(tools.shell());
114
- else warn('skipping "shell": pass --allow-shell (runs commands)');
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
- return tools$1;
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
- gemini: adapters.gemini,
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
- cohere: adapters.cohere,
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
- lmstudio: adapters.lmstudio,
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(["lmstudio", "vllm", "llamacpp"]);
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
- function resolveAdapter() {
151
- const provider = flag("--provider") ?? "openai";
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
- warn(`--agents needs a model for "${provider}": pass --model`);
382
+ warn2(`--agents needs a model for "${options.provider}": pass --model`);
155
383
  return null;
156
384
  }
157
- const baseUrl = flag("--base-url");
158
- if (LOCAL[provider]) return LOCAL[provider]({ model, baseUrl });
159
- const apiKey = flag("--api-key") ?? process.env[`${provider.toUpperCase().replace(/-/g, "_")}_API_KEY`] ?? (LOCAL_COMPAT.has(provider) ? "local" : void 0);
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
- warn(`--agents needs a key for "${provider}": pass --api-key or set ${provider.toUpperCase()}_API_KEY`);
390
+ warn2(`--agents needs a key for "${options.provider}": pass --api-key or set ${envName}`);
162
391
  return null;
163
392
  }
164
- if (KEYED[provider]) return KEYED[provider]({ apiKey, model });
393
+ const keyed = KEYED[options.provider];
394
+ if (keyed) return keyed({ apiKey, baseUrl: options.baseUrl, model });
165
395
  try {
166
- return catalog.dispatchFromCatalog({ provider, model, apiKey, baseUrl });
396
+ return catalog.dispatchFromCatalog({ apiKey, baseUrl: options.baseUrl, model, provider: options.provider });
167
397
  } catch {
168
- warn(`unknown provider "${provider}". Known: ${[...Object.keys(KEYED), ...Object.keys(LOCAL)].join(", ")}, or any catalog OpenAI-compatible provider.`);
398
+ warn2(`unknown or incompatible provider "${options.provider}"`);
169
399
  return null;
170
400
  }
171
- }
172
- async function buildAgentTools() {
173
- const ids = (flag("--agents") ?? "").split(",").map((s) => s.trim()).filter(Boolean);
174
- if (ids.length === 0) return [];
175
- const adapter = resolveAdapter();
176
- if (!adapter) return [];
177
- const tools = [];
178
- for (const id of ids) {
179
- const skill = await fetchAgentSkill(id);
180
- if (!skill) {
181
- warn(`skipping agent "${id}": not found or not runnable (tool-composing agent)`);
182
- continue;
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
- warn("no tools or agents enabled \u2014 nothing to serve. See --tools / --agents.");
194
- process.exit(1);
429
+ warn2("no tools or agents enabled \u2014 nothing to serve");
430
+ return { exitCode: 1, status: "rejected" };
195
431
  }
196
- createAgentsKitMcpServer({
197
- tools,
198
- onEvent: (e) => {
199
- if (e.type === "error") warn(`tool error (${e.tool}): ${e.error}`);
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
- warn(`serving ${tools.length} item(s) over stdio (${tools.map((t) => t.name).join(", ")})`);
203
- }
204
- void main();
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