@mcpc-tech/cli 0.1.52 → 0.1.54

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/server.cjs CHANGED
@@ -543,10 +543,9 @@ var ProgressTokenSchema = z.union([z.string(), z.number().int()]);
543
543
  var CursorSchema = z.string();
544
544
  var TaskCreationParamsSchema = z.looseObject({
545
545
  /**
546
- * Time in milliseconds to keep task results available after completion.
547
- * If null, the task has unlimited lifetime until manually cleaned up.
546
+ * Requested duration in milliseconds to retain task from creation.
548
547
  */
549
- ttl: z.union([z.number(), z.null()]).optional(),
548
+ ttl: z.number().optional(),
550
549
  /**
551
550
  * Time in milliseconds to wait between task status requests.
552
551
  */
@@ -846,7 +845,11 @@ var ClientCapabilitiesSchema = z.object({
846
845
  /**
847
846
  * Present if the client supports task creation.
848
847
  */
849
- tasks: ClientTasksCapabilitySchema.optional()
848
+ tasks: ClientTasksCapabilitySchema.optional(),
849
+ /**
850
+ * Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
851
+ */
852
+ extensions: z.record(z.string(), AssertObjectSchema).optional()
850
853
  });
851
854
  var InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
852
855
  /**
@@ -908,7 +911,11 @@ var ServerCapabilitiesSchema = z.object({
908
911
  /**
909
912
  * Present if the server supports task creation.
910
913
  */
911
- tasks: ServerTasksCapabilitySchema.optional()
914
+ tasks: ServerTasksCapabilitySchema.optional(),
915
+ /**
916
+ * Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
917
+ */
918
+ extensions: z.record(z.string(), AssertObjectSchema).optional()
912
919
  });
913
920
  var InitializeResultSchema = ResultSchema.extend({
914
921
  /**
@@ -1101,6 +1108,12 @@ var ResourceSchema = z.object({
1101
1108
  * The MIME type of this resource, if known.
1102
1109
  */
1103
1110
  mimeType: z.optional(z.string()),
1111
+ /**
1112
+ * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
1113
+ *
1114
+ * This can be used by Hosts to display file sizes and estimate context window usage.
1115
+ */
1116
+ size: z.optional(z.number()),
1104
1117
  /**
1105
1118
  * Optional annotations for the client.
1106
1119
  */
@@ -2575,15 +2588,17 @@ var Response2 = class _Response {
2575
2588
  this.#init = init;
2576
2589
  }
2577
2590
  if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
2578
- headers ||= init?.headers || { "content-type": "text/plain; charset=UTF-8" };
2579
- this[cacheKey] = [init?.status || 200, body, headers];
2591
+ ;
2592
+ this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
2580
2593
  }
2581
2594
  }
2582
2595
  get headers() {
2583
2596
  const cache = this[cacheKey];
2584
2597
  if (cache) {
2585
2598
  if (!(cache[2] instanceof Headers)) {
2586
- cache[2] = new Headers(cache[2]);
2599
+ cache[2] = new Headers(
2600
+ cache[2] || { "content-type": "text/plain; charset=UTF-8" }
2601
+ );
2587
2602
  }
2588
2603
  return cache[2];
2589
2604
  }
@@ -2682,6 +2697,50 @@ if (typeof global.crypto === "undefined") {
2682
2697
  global.crypto = import_crypto.default;
2683
2698
  }
2684
2699
  var outgoingEnded = Symbol("outgoingEnded");
2700
+ var incomingDraining = Symbol("incomingDraining");
2701
+ var DRAIN_TIMEOUT_MS = 500;
2702
+ var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
2703
+ var drainIncoming = (incoming) => {
2704
+ const incomingWithDrainState = incoming;
2705
+ if (incoming.destroyed || incomingWithDrainState[incomingDraining]) {
2706
+ return;
2707
+ }
2708
+ incomingWithDrainState[incomingDraining] = true;
2709
+ if (incoming instanceof import_http2.Http2ServerRequest) {
2710
+ try {
2711
+ ;
2712
+ incoming.stream?.close?.(import_http2.constants.NGHTTP2_NO_ERROR);
2713
+ } catch {
2714
+ }
2715
+ return;
2716
+ }
2717
+ let bytesRead = 0;
2718
+ const cleanup = () => {
2719
+ clearTimeout(timer);
2720
+ incoming.off("data", onData);
2721
+ incoming.off("end", cleanup);
2722
+ incoming.off("error", cleanup);
2723
+ };
2724
+ const forceClose = () => {
2725
+ cleanup();
2726
+ const socket = incoming.socket;
2727
+ if (socket && !socket.destroyed) {
2728
+ socket.destroySoon();
2729
+ }
2730
+ };
2731
+ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
2732
+ timer.unref?.();
2733
+ const onData = (chunk) => {
2734
+ bytesRead += chunk.length;
2735
+ if (bytesRead > MAX_DRAIN_BYTES) {
2736
+ forceClose();
2737
+ }
2738
+ };
2739
+ incoming.on("data", onData);
2740
+ incoming.on("end", cleanup);
2741
+ incoming.on("error", cleanup);
2742
+ incoming.resume();
2743
+ };
2685
2744
  var handleRequestError = () => new Response(null, {
2686
2745
  status: 400
2687
2746
  });
@@ -2708,15 +2767,32 @@ var flushHeaders = (outgoing) => {
2708
2767
  };
2709
2768
  var responseViaCache = async (res, outgoing) => {
2710
2769
  let [status, body, header] = res[cacheKey];
2711
- if (header instanceof Headers) {
2770
+ let hasContentLength = false;
2771
+ if (!header) {
2772
+ header = { "content-type": "text/plain; charset=UTF-8" };
2773
+ } else if (header instanceof Headers) {
2774
+ hasContentLength = header.has("content-length");
2712
2775
  header = buildOutgoingHttpHeaders(header);
2776
+ } else if (Array.isArray(header)) {
2777
+ const headerObj = new Headers(header);
2778
+ hasContentLength = headerObj.has("content-length");
2779
+ header = buildOutgoingHttpHeaders(headerObj);
2780
+ } else {
2781
+ for (const key in header) {
2782
+ if (key.length === 14 && key.toLowerCase() === "content-length") {
2783
+ hasContentLength = true;
2784
+ break;
2785
+ }
2786
+ }
2713
2787
  }
2714
- if (typeof body === "string") {
2715
- header["Content-Length"] = Buffer.byteLength(body);
2716
- } else if (body instanceof Uint8Array) {
2717
- header["Content-Length"] = body.byteLength;
2718
- } else if (body instanceof Blob) {
2719
- header["Content-Length"] = body.size;
2788
+ if (!hasContentLength) {
2789
+ if (typeof body === "string") {
2790
+ header["Content-Length"] = Buffer.byteLength(body);
2791
+ } else if (body instanceof Uint8Array) {
2792
+ header["Content-Length"] = body.byteLength;
2793
+ } else if (body instanceof Blob) {
2794
+ header["Content-Length"] = body.size;
2795
+ }
2720
2796
  }
2721
2797
  outgoing.writeHead(status, header);
2722
2798
  if (typeof body === "string" || body instanceof Uint8Array) {
@@ -2836,14 +2912,18 @@ var getRequestListener = (fetchCallback, options = {}) => {
2836
2912
  setTimeout(() => {
2837
2913
  if (!incomingEnded) {
2838
2914
  setTimeout(() => {
2839
- incoming.destroy();
2840
- outgoing.destroy();
2915
+ drainIncoming(incoming);
2841
2916
  });
2842
2917
  }
2843
2918
  });
2844
2919
  }
2845
2920
  };
2846
2921
  }
2922
+ outgoing.on("finish", () => {
2923
+ if (!incomingEnded) {
2924
+ drainIncoming(incoming);
2925
+ }
2926
+ });
2847
2927
  }
2848
2928
  outgoing.on("close", () => {
2849
2929
  const abortController = req[abortControllerKey];
@@ -2858,7 +2938,7 @@ var getRequestListener = (fetchCallback, options = {}) => {
2858
2938
  setTimeout(() => {
2859
2939
  if (!incomingEnded) {
2860
2940
  setTimeout(() => {
2861
- incoming.destroy();
2941
+ drainIncoming(incoming);
2862
2942
  });
2863
2943
  }
2864
2944
  });
@@ -6698,7 +6778,7 @@ function getDefaultAgents() {
6698
6778
  }
6699
6779
 
6700
6780
  // __mcpc__cli_latest/node_modules/@mcpc/cli/src/config/loader.js
6701
- var CLI_VERSION = "0.1.52";
6781
+ var CLI_VERSION = "0.1.54";
6702
6782
  function extractServerName(command, commandArgs) {
6703
6783
  for (const arg of commandArgs) {
6704
6784
  if (!arg.startsWith("-")) {
@@ -7121,7 +7201,7 @@ function applyModeOverride(config, mode) {
7121
7201
  agent.options.mode = mode;
7122
7202
  if (mode === "ai_acp" && !agent.options.acpSettings) {
7123
7203
  agent.options.acpSettings = {
7124
- command: "claude-code-acp",
7204
+ command: "claude-agent-acp",
7125
7205
  args: [],
7126
7206
  session: {}
7127
7207
  };
@@ -7542,6 +7622,10 @@ var Protocol = class {
7542
7622
  this._progressHandlers.clear();
7543
7623
  this._taskProgressTokens.clear();
7544
7624
  this._pendingDebouncedNotifications.clear();
7625
+ for (const info of this._timeoutInfo.values()) {
7626
+ clearTimeout(info.timeoutId);
7627
+ }
7628
+ this._timeoutInfo.clear();
7545
7629
  for (const controller of this._requestHandlerAbortControllers.values()) {
7546
7630
  controller.abort();
7547
7631
  }
@@ -7672,7 +7756,9 @@ var Protocol = class {
7672
7756
  await capturedTransport?.send(errorResponse);
7673
7757
  }
7674
7758
  }).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
7675
- this._requestHandlerAbortControllers.delete(request.id);
7759
+ if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
7760
+ this._requestHandlerAbortControllers.delete(request.id);
7761
+ }
7676
7762
  });
7677
7763
  }
7678
7764
  _onprogress(notification) {
@@ -9796,7 +9882,7 @@ var StdioClientTransport = class {
9796
9882
  },
9797
9883
  stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
9798
9884
  shell: false,
9799
- windowsHide: import_node_process5.default.platform === "win32" && isElectron(),
9885
+ windowsHide: import_node_process5.default.platform === "win32",
9800
9886
  cwd: this._serverParams.cwd
9801
9887
  });
9802
9888
  this._process.on("error", (error) => {
@@ -9903,9 +9989,6 @@ var StdioClientTransport = class {
9903
9989
  });
9904
9990
  }
9905
9991
  };
9906
- function isElectron() {
9907
- return "type" in import_node_process5.default;
9908
- }
9909
9992
 
9910
9993
  // __mcpc__cli_latest/node_modules/eventsource-parser/dist/index.js
9911
9994
  var ParseError = class extends Error {
@@ -10650,12 +10733,12 @@ var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
10650
10733
  var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
10651
10734
  function selectClientAuthMethod(clientInformation, supportedMethods) {
10652
10735
  const hasClientSecret = clientInformation.client_secret !== void 0;
10653
- if (supportedMethods.length === 0) {
10654
- return hasClientSecret ? "client_secret_post" : "none";
10655
- }
10656
- if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && supportedMethods.includes(clientInformation.token_endpoint_auth_method)) {
10736
+ if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) {
10657
10737
  return clientInformation.token_endpoint_auth_method;
10658
10738
  }
10739
+ if (supportedMethods.length === 0) {
10740
+ return hasClientSecret ? "client_secret_basic" : "none";
10741
+ }
10659
10742
  if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
10660
10743
  return "client_secret_basic";
10661
10744
  }
@@ -10766,6 +10849,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10766
10849
  });
10767
10850
  }
10768
10851
  const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
10852
+ const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
10769
10853
  let clientInformation = await Promise.resolve(provider.clientInformation());
10770
10854
  if (!clientInformation) {
10771
10855
  if (authorizationCode !== void 0) {
@@ -10789,6 +10873,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10789
10873
  const fullInformation = await registerClient(authorizationServerUrl, {
10790
10874
  metadata,
10791
10875
  clientMetadata: provider.clientMetadata,
10876
+ scope: resolvedScope,
10792
10877
  fetchFn
10793
10878
  });
10794
10879
  await provider.saveClientInformation(fullInformation);
@@ -10832,7 +10917,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10832
10917
  clientInformation,
10833
10918
  state,
10834
10919
  redirectUrl: provider.redirectUrl,
10835
- scope: scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope,
10920
+ scope: resolvedScope,
10836
10921
  resource
10837
10922
  });
10838
10923
  await provider.saveCodeVerifier(codeVerifier);
@@ -11150,7 +11235,7 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
11150
11235
  fetchFn
11151
11236
  });
11152
11237
  }
11153
- async function registerClient(authorizationServerUrl, { metadata, clientMetadata, fetchFn }) {
11238
+ async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
11154
11239
  let registrationUrl;
11155
11240
  if (metadata) {
11156
11241
  if (!metadata.registration_endpoint) {
@@ -11165,7 +11250,10 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
11165
11250
  headers: {
11166
11251
  "Content-Type": "application/json"
11167
11252
  },
11168
- body: JSON.stringify(clientMetadata)
11253
+ body: JSON.stringify({
11254
+ ...clientMetadata,
11255
+ ...scope !== void 0 ? { scope } : {}
11256
+ })
11169
11257
  });
11170
11258
  if (!response.ok) {
11171
11259
  throw await parseErrorResponse(response);
@@ -12260,7 +12348,7 @@ var SystemPrompts = {
12260
12348
  </rules>
12261
12349
 
12262
12350
  <format>
12263
- Get tool schemas: \`{ "tool": "man", "args": { "tools": ["tool1", "tool2"] } }\`
12351
+ Get tool definitions: \`{ "tool": "man", "args": { "tools": ["tool1", "tool2"] } }\`
12264
12352
  Execute a tool: \`{ "tool": "tool_name", "args": { /* parameters */ } }\`
12265
12353
  </format>`,
12266
12354
  /**
@@ -12385,7 +12473,7 @@ function createArgsDefFactory(_name, _allToolNames, _depGroups, _predefinedSteps
12385
12473
  *
12386
12474
  * Only two fields:
12387
12475
  * - `tool`: which tool to execute (enum includes "man" + all tool names)
12388
- * - `args`: object with parameters. For "man": { tools: ["a", "b"] }. For others: tool parameters.
12476
+ * - `args`: object with parameters. For "man": { tools: ["a", "b"] } to fetch tool definitions (including input/output schemas). For others: tool parameters.
12389
12477
  */
12390
12478
  forAgentic: function(allToolNames) {
12391
12479
  const toolEnum = [
@@ -14337,11 +14425,12 @@ var ToolManager = class {
14337
14425
  /**
14338
14426
  * Register a tool in the registry
14339
14427
  */
14340
- registerTool(name, description, schema, callback, options = {}) {
14428
+ registerTool(name, description, inputSchema, callback, options = {}) {
14341
14429
  this.toolRegistry.set(name, {
14342
14430
  callback,
14343
14431
  description,
14344
- schema
14432
+ inputSchema,
14433
+ outputSchema: options.outputSchema
14345
14434
  });
14346
14435
  if (options.hidden) {
14347
14436
  this.toolConfigs.set(name, {
@@ -14354,13 +14443,16 @@ var ToolManager = class {
14354
14443
  /**
14355
14444
  * Explicitly mark a tool as public (exposed to MCP clients)
14356
14445
  */
14357
- addPublicTool(name, description, schema) {
14446
+ addPublicTool(name, description, inputSchema, outputSchema) {
14358
14447
  const existingTool = this.publicTools.find((t) => t.name === name);
14359
14448
  if (!existingTool) {
14360
14449
  this.publicTools.push({
14361
14450
  name,
14362
14451
  description,
14363
- inputSchema: schema
14452
+ inputSchema,
14453
+ ...outputSchema ? {
14454
+ outputSchema
14455
+ } : {}
14364
14456
  });
14365
14457
  }
14366
14458
  this.toolConfigs.set(name, {
@@ -14486,10 +14578,13 @@ var ToolManager = class {
14486
14578
  getHiddenToolSchema(name) {
14487
14579
  const tool2 = this.toolRegistry.get(name);
14488
14580
  const config = this.toolConfigs.get(name);
14489
- if (tool2 && config?.visibility?.hidden && tool2.schema) {
14581
+ if (tool2 && config?.visibility?.hidden && tool2.inputSchema) {
14490
14582
  return {
14491
14583
  description: tool2.description,
14492
- schema: tool2.schema
14584
+ inputSchema: tool2.inputSchema,
14585
+ ...tool2.outputSchema ? {
14586
+ outputSchema: tool2.outputSchema
14587
+ } : {}
14493
14588
  };
14494
14589
  }
14495
14590
  return void 0;
@@ -14525,10 +14620,13 @@ var ToolManager = class {
14525
14620
  composedTools[name] = {
14526
14621
  name,
14527
14622
  description: tool2.description,
14528
- inputSchema: jsonSchema(tool2.schema || {
14623
+ inputSchema: jsonSchema(tool2.inputSchema || {
14529
14624
  type: "object",
14530
14625
  properties: {}
14531
14626
  }),
14627
+ ...tool2.outputSchema ? {
14628
+ outputSchema: jsonSchema(tool2.outputSchema)
14629
+ } : {},
14532
14630
  execute: tool2.callback
14533
14631
  };
14534
14632
  }
@@ -14545,10 +14643,13 @@ var ToolManager = class {
14545
14643
  return {
14546
14644
  name,
14547
14645
  description: tool2.description,
14548
- inputSchema: tool2.schema ?? {
14646
+ inputSchema: tool2.inputSchema ?? {
14549
14647
  type: "object",
14550
14648
  properties: {}
14551
14649
  },
14650
+ ...tool2.outputSchema ? {
14651
+ outputSchema: tool2.outputSchema
14652
+ } : {},
14552
14653
  execute: tool2.callback
14553
14654
  };
14554
14655
  }
@@ -14562,10 +14663,13 @@ var ToolManager = class {
14562
14663
  composedTools.push({
14563
14664
  name,
14564
14665
  description: tool2.description,
14565
- inputSchema: tool2.schema ?? {
14666
+ inputSchema: tool2.inputSchema ?? {
14566
14667
  type: "object",
14567
14668
  properties: {}
14568
14669
  },
14670
+ ...tool2.outputSchema ? {
14671
+ outputSchema: tool2.outputSchema
14672
+ } : {},
14569
14673
  execute: tool2.callback
14570
14674
  });
14571
14675
  }
@@ -14618,7 +14722,10 @@ async function processToolsWithPlugins(server, _externalTools, mode) {
14618
14722
  const tempTool = {
14619
14723
  name: toolId,
14620
14724
  description: toolData.description,
14621
- inputSchema: toolData.schema || defaultSchema,
14725
+ inputSchema: toolData.inputSchema || defaultSchema,
14726
+ ...toolData.outputSchema ? {
14727
+ outputSchema: toolData.outputSchema
14728
+ } : {},
14622
14729
  execute: toolData.callback
14623
14730
  };
14624
14731
  const processedTool = await pluginManager.applyTransformToolHooks(tempTool, {
@@ -14630,7 +14737,9 @@ async function processToolsWithPlugins(server, _externalTools, mode) {
14630
14737
  },
14631
14738
  transformationIndex: 0
14632
14739
  });
14633
- toolManager.registerTool(toolId, processedTool.description || toolData.description, processedTool.inputSchema, processedTool.execute);
14740
+ toolManager.registerTool(toolId, processedTool.description || toolData.description, processedTool.inputSchema, processedTool.execute, {
14741
+ outputSchema: processedTool.outputSchema
14742
+ });
14634
14743
  }
14635
14744
  }
14636
14745
  function buildDependencyGroups(toolNameToDetailList, hiddenToolNames, publicToolNames, server) {
@@ -14676,6 +14785,7 @@ var ComposableMCPServer = class extends Server {
14676
14785
  toolManager;
14677
14786
  logger = createLogger("mcpc.compose");
14678
14787
  fileLoaders = /* @__PURE__ */ new Map();
14788
+ pluginsDisposed = false;
14679
14789
  // Legacy property for backward compatibility
14680
14790
  get toolNameMapping() {
14681
14791
  return this.toolManager.getToolNameMapping();
@@ -14804,9 +14914,13 @@ var ComposableMCPServer = class extends Server {
14804
14914
  }
14805
14915
  tool(name, description, paramsSchema, cb, options = {}) {
14806
14916
  const jsonSchemaObj = extractJsonSchema(paramsSchema);
14807
- this.toolManager.registerTool(name, description, jsonSchemaObj, cb, options);
14917
+ const outputSchemaObj = options.outputSchema ? extractJsonSchema(options.outputSchema) : void 0;
14918
+ this.toolManager.registerTool(name, description, jsonSchemaObj, cb, {
14919
+ ...options,
14920
+ outputSchema: outputSchemaObj
14921
+ });
14808
14922
  if (!options.internal) {
14809
- this.toolManager.addPublicTool(name, description, jsonSchemaObj);
14923
+ this.toolManager.addPublicTool(name, description, jsonSchemaObj, outputSchemaObj);
14810
14924
  }
14811
14925
  if (options.plugins) {
14812
14926
  for (const plugin of options.plugins) {
@@ -15063,9 +15177,12 @@ var ComposableMCPServer = class extends Server {
15063
15177
  return {
15064
15178
  name,
15065
15179
  description: tool2?.description || "",
15066
- inputSchema: tool2?.schema || {
15180
+ inputSchema: tool2?.inputSchema || {
15067
15181
  type: "object"
15068
- }
15182
+ },
15183
+ ...tool2?.outputSchema ? {
15184
+ outputSchema: tool2.outputSchema
15185
+ } : {}
15069
15186
  };
15070
15187
  });
15071
15188
  }
@@ -15090,9 +15207,12 @@ var ComposableMCPServer = class extends Server {
15090
15207
  return Array.from(registry.entries()).map(([name, tool2]) => ({
15091
15208
  name,
15092
15209
  description: tool2?.description || "",
15093
- inputSchema: tool2?.schema || {
15210
+ inputSchema: tool2?.inputSchema || {
15094
15211
  type: "object"
15095
- }
15212
+ },
15213
+ ...tool2?.outputSchema ? {
15214
+ outputSchema: tool2.outputSchema
15215
+ } : {}
15096
15216
  }));
15097
15217
  }
15098
15218
  /**
@@ -15151,11 +15271,21 @@ var ComposableMCPServer = class extends Server {
15151
15271
  async disposePlugins() {
15152
15272
  await this.pluginManager.dispose();
15153
15273
  }
15274
+ /**
15275
+ * Dispose plugins only once to avoid duplicated cleanup in chained handlers.
15276
+ */
15277
+ async disposePluginsOnce() {
15278
+ if (this.pluginsDisposed) {
15279
+ return;
15280
+ }
15281
+ this.pluginsDisposed = true;
15282
+ await this.disposePlugins();
15283
+ }
15154
15284
  /**
15155
15285
  * Close the server and ensure all plugins are disposed
15156
15286
  */
15157
15287
  async close() {
15158
- await this.disposePlugins();
15288
+ await this.disposePluginsOnce();
15159
15289
  await super.close();
15160
15290
  }
15161
15291
  async compose(name, description, depsConfig = {
@@ -15224,7 +15354,9 @@ var ComposableMCPServer = class extends Server {
15224
15354
  });
15225
15355
  });
15226
15356
  Object.entries(tools).forEach(([toolId, tool2]) => {
15227
- this.toolManager.registerTool(toolId, tool2.description || "", tool2.inputSchema, tool2.execute);
15357
+ this.toolManager.registerTool(toolId, tool2.description || "", tool2.inputSchema, tool2.execute, {
15358
+ outputSchema: tool2.outputSchema
15359
+ });
15228
15360
  });
15229
15361
  const registeredTools = this.toolManager.getRegisteredToolsAsComposed();
15230
15362
  const allTools = {
@@ -15260,16 +15392,20 @@ var ComposableMCPServer = class extends Server {
15260
15392
  server: this,
15261
15393
  toolNames: Object.keys(allTools)
15262
15394
  });
15395
+ const previousOnClose = this.onclose;
15263
15396
  this.onclose = async () => {
15264
15397
  await cleanupClients();
15265
- await this.disposePlugins();
15398
+ await this.disposePluginsOnce();
15266
15399
  await this.logger.info(`[${name}] Event: closed - cleaned up dependent clients and plugins`);
15400
+ previousOnClose?.();
15267
15401
  };
15402
+ const previousOnError = this.onerror;
15268
15403
  this.onerror = async (error) => {
15269
15404
  await this.logger.error(`[${name}] Event: error - ${error?.stack ?? String(error)}`);
15270
15405
  await cleanupClients();
15271
- await this.disposePlugins();
15406
+ await this.disposePluginsOnce();
15272
15407
  await this.logger.info(`[${name}] Action: cleaned up dependent clients and plugins`);
15408
+ previousOnError?.(error);
15273
15409
  };
15274
15410
  const toolNameToDetailList = Object.entries(allTools);
15275
15411
  const publicToolNames = this.getPublicToolNames();
@@ -15281,7 +15417,8 @@ var ComposableMCPServer = class extends Server {
15281
15417
  return;
15282
15418
  }
15283
15419
  this.tool(toolId, tool2.description || "", jsonSchema(tool2.inputSchema), tool2.execute, {
15284
- internal: false
15420
+ internal: false,
15421
+ outputSchema: tool2.outputSchema
15285
15422
  });
15286
15423
  });
15287
15424
  await this.pluginManager.triggerComposeEnd({