@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/index.cjs CHANGED
@@ -555,10 +555,9 @@ var ProgressTokenSchema = z.union([z.string(), z.number().int()]);
555
555
  var CursorSchema = z.string();
556
556
  var TaskCreationParamsSchema = z.looseObject({
557
557
  /**
558
- * Time in milliseconds to keep task results available after completion.
559
- * If null, the task has unlimited lifetime until manually cleaned up.
558
+ * Requested duration in milliseconds to retain task from creation.
560
559
  */
561
- ttl: z.union([z.number(), z.null()]).optional(),
560
+ ttl: z.number().optional(),
562
561
  /**
563
562
  * Time in milliseconds to wait between task status requests.
564
563
  */
@@ -858,7 +857,11 @@ var ClientCapabilitiesSchema = z.object({
858
857
  /**
859
858
  * Present if the client supports task creation.
860
859
  */
861
- tasks: ClientTasksCapabilitySchema.optional()
860
+ tasks: ClientTasksCapabilitySchema.optional(),
861
+ /**
862
+ * Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
863
+ */
864
+ extensions: z.record(z.string(), AssertObjectSchema).optional()
862
865
  });
863
866
  var InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
864
867
  /**
@@ -920,7 +923,11 @@ var ServerCapabilitiesSchema = z.object({
920
923
  /**
921
924
  * Present if the server supports task creation.
922
925
  */
923
- tasks: ServerTasksCapabilitySchema.optional()
926
+ tasks: ServerTasksCapabilitySchema.optional(),
927
+ /**
928
+ * Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
929
+ */
930
+ extensions: z.record(z.string(), AssertObjectSchema).optional()
924
931
  });
925
932
  var InitializeResultSchema = ResultSchema.extend({
926
933
  /**
@@ -1113,6 +1120,12 @@ var ResourceSchema = z.object({
1113
1120
  * The MIME type of this resource, if known.
1114
1121
  */
1115
1122
  mimeType: z.optional(z.string()),
1123
+ /**
1124
+ * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
1125
+ *
1126
+ * This can be used by Hosts to display file sizes and estimate context window usage.
1127
+ */
1128
+ size: z.optional(z.number()),
1116
1129
  /**
1117
1130
  * Optional annotations for the client.
1118
1131
  */
@@ -2587,15 +2600,17 @@ var Response2 = class _Response {
2587
2600
  this.#init = init;
2588
2601
  }
2589
2602
  if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
2590
- headers ||= init?.headers || { "content-type": "text/plain; charset=UTF-8" };
2591
- this[cacheKey] = [init?.status || 200, body, headers];
2603
+ ;
2604
+ this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
2592
2605
  }
2593
2606
  }
2594
2607
  get headers() {
2595
2608
  const cache = this[cacheKey];
2596
2609
  if (cache) {
2597
2610
  if (!(cache[2] instanceof Headers)) {
2598
- cache[2] = new Headers(cache[2]);
2611
+ cache[2] = new Headers(
2612
+ cache[2] || { "content-type": "text/plain; charset=UTF-8" }
2613
+ );
2599
2614
  }
2600
2615
  return cache[2];
2601
2616
  }
@@ -2694,6 +2709,50 @@ if (typeof global.crypto === "undefined") {
2694
2709
  global.crypto = import_crypto.default;
2695
2710
  }
2696
2711
  var outgoingEnded = Symbol("outgoingEnded");
2712
+ var incomingDraining = Symbol("incomingDraining");
2713
+ var DRAIN_TIMEOUT_MS = 500;
2714
+ var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
2715
+ var drainIncoming = (incoming) => {
2716
+ const incomingWithDrainState = incoming;
2717
+ if (incoming.destroyed || incomingWithDrainState[incomingDraining]) {
2718
+ return;
2719
+ }
2720
+ incomingWithDrainState[incomingDraining] = true;
2721
+ if (incoming instanceof import_http2.Http2ServerRequest) {
2722
+ try {
2723
+ ;
2724
+ incoming.stream?.close?.(import_http2.constants.NGHTTP2_NO_ERROR);
2725
+ } catch {
2726
+ }
2727
+ return;
2728
+ }
2729
+ let bytesRead = 0;
2730
+ const cleanup = () => {
2731
+ clearTimeout(timer);
2732
+ incoming.off("data", onData);
2733
+ incoming.off("end", cleanup);
2734
+ incoming.off("error", cleanup);
2735
+ };
2736
+ const forceClose = () => {
2737
+ cleanup();
2738
+ const socket = incoming.socket;
2739
+ if (socket && !socket.destroyed) {
2740
+ socket.destroySoon();
2741
+ }
2742
+ };
2743
+ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
2744
+ timer.unref?.();
2745
+ const onData = (chunk) => {
2746
+ bytesRead += chunk.length;
2747
+ if (bytesRead > MAX_DRAIN_BYTES) {
2748
+ forceClose();
2749
+ }
2750
+ };
2751
+ incoming.on("data", onData);
2752
+ incoming.on("end", cleanup);
2753
+ incoming.on("error", cleanup);
2754
+ incoming.resume();
2755
+ };
2697
2756
  var handleRequestError = () => new Response(null, {
2698
2757
  status: 400
2699
2758
  });
@@ -2720,15 +2779,32 @@ var flushHeaders = (outgoing) => {
2720
2779
  };
2721
2780
  var responseViaCache = async (res, outgoing) => {
2722
2781
  let [status, body, header] = res[cacheKey];
2723
- if (header instanceof Headers) {
2782
+ let hasContentLength = false;
2783
+ if (!header) {
2784
+ header = { "content-type": "text/plain; charset=UTF-8" };
2785
+ } else if (header instanceof Headers) {
2786
+ hasContentLength = header.has("content-length");
2724
2787
  header = buildOutgoingHttpHeaders(header);
2788
+ } else if (Array.isArray(header)) {
2789
+ const headerObj = new Headers(header);
2790
+ hasContentLength = headerObj.has("content-length");
2791
+ header = buildOutgoingHttpHeaders(headerObj);
2792
+ } else {
2793
+ for (const key in header) {
2794
+ if (key.length === 14 && key.toLowerCase() === "content-length") {
2795
+ hasContentLength = true;
2796
+ break;
2797
+ }
2798
+ }
2725
2799
  }
2726
- if (typeof body === "string") {
2727
- header["Content-Length"] = Buffer.byteLength(body);
2728
- } else if (body instanceof Uint8Array) {
2729
- header["Content-Length"] = body.byteLength;
2730
- } else if (body instanceof Blob) {
2731
- header["Content-Length"] = body.size;
2800
+ if (!hasContentLength) {
2801
+ if (typeof body === "string") {
2802
+ header["Content-Length"] = Buffer.byteLength(body);
2803
+ } else if (body instanceof Uint8Array) {
2804
+ header["Content-Length"] = body.byteLength;
2805
+ } else if (body instanceof Blob) {
2806
+ header["Content-Length"] = body.size;
2807
+ }
2732
2808
  }
2733
2809
  outgoing.writeHead(status, header);
2734
2810
  if (typeof body === "string" || body instanceof Uint8Array) {
@@ -2848,14 +2924,18 @@ var getRequestListener = (fetchCallback, options = {}) => {
2848
2924
  setTimeout(() => {
2849
2925
  if (!incomingEnded) {
2850
2926
  setTimeout(() => {
2851
- incoming.destroy();
2852
- outgoing.destroy();
2927
+ drainIncoming(incoming);
2853
2928
  });
2854
2929
  }
2855
2930
  });
2856
2931
  }
2857
2932
  };
2858
2933
  }
2934
+ outgoing.on("finish", () => {
2935
+ if (!incomingEnded) {
2936
+ drainIncoming(incoming);
2937
+ }
2938
+ });
2859
2939
  }
2860
2940
  outgoing.on("close", () => {
2861
2941
  const abortController = req[abortControllerKey];
@@ -2870,7 +2950,7 @@ var getRequestListener = (fetchCallback, options = {}) => {
2870
2950
  setTimeout(() => {
2871
2951
  if (!incomingEnded) {
2872
2952
  setTimeout(() => {
2873
- incoming.destroy();
2953
+ drainIncoming(incoming);
2874
2954
  });
2875
2955
  }
2876
2956
  });
@@ -6710,7 +6790,7 @@ function getDefaultAgents() {
6710
6790
  }
6711
6791
 
6712
6792
  // __mcpc__cli_latest/node_modules/@mcpc/cli/src/config/loader.js
6713
- var CLI_VERSION = "0.1.52";
6793
+ var CLI_VERSION = "0.1.54";
6714
6794
  function extractServerName(command, commandArgs) {
6715
6795
  for (const arg of commandArgs) {
6716
6796
  if (!arg.startsWith("-")) {
@@ -7133,7 +7213,7 @@ function applyModeOverride(config, mode) {
7133
7213
  agent.options.mode = mode;
7134
7214
  if (mode === "ai_acp" && !agent.options.acpSettings) {
7135
7215
  agent.options.acpSettings = {
7136
- command: "claude-code-acp",
7216
+ command: "claude-agent-acp",
7137
7217
  args: [],
7138
7218
  session: {}
7139
7219
  };
@@ -7565,6 +7645,10 @@ var Protocol = class {
7565
7645
  this._progressHandlers.clear();
7566
7646
  this._taskProgressTokens.clear();
7567
7647
  this._pendingDebouncedNotifications.clear();
7648
+ for (const info of this._timeoutInfo.values()) {
7649
+ clearTimeout(info.timeoutId);
7650
+ }
7651
+ this._timeoutInfo.clear();
7568
7652
  for (const controller of this._requestHandlerAbortControllers.values()) {
7569
7653
  controller.abort();
7570
7654
  }
@@ -7695,7 +7779,9 @@ var Protocol = class {
7695
7779
  await capturedTransport?.send(errorResponse);
7696
7780
  }
7697
7781
  }).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
7698
- this._requestHandlerAbortControllers.delete(request.id);
7782
+ if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
7783
+ this._requestHandlerAbortControllers.delete(request.id);
7784
+ }
7699
7785
  });
7700
7786
  }
7701
7787
  _onprogress(notification) {
@@ -9819,7 +9905,7 @@ var StdioClientTransport = class {
9819
9905
  },
9820
9906
  stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
9821
9907
  shell: false,
9822
- windowsHide: import_node_process5.default.platform === "win32" && isElectron(),
9908
+ windowsHide: import_node_process5.default.platform === "win32",
9823
9909
  cwd: this._serverParams.cwd
9824
9910
  });
9825
9911
  this._process.on("error", (error) => {
@@ -9926,9 +10012,6 @@ var StdioClientTransport = class {
9926
10012
  });
9927
10013
  }
9928
10014
  };
9929
- function isElectron() {
9930
- return "type" in import_node_process5.default;
9931
- }
9932
10015
 
9933
10016
  // __mcpc__cli_latest/node_modules/eventsource-parser/dist/index.js
9934
10017
  var ParseError = class extends Error {
@@ -10673,12 +10756,12 @@ var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
10673
10756
  var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
10674
10757
  function selectClientAuthMethod(clientInformation, supportedMethods) {
10675
10758
  const hasClientSecret = clientInformation.client_secret !== void 0;
10676
- if (supportedMethods.length === 0) {
10677
- return hasClientSecret ? "client_secret_post" : "none";
10678
- }
10679
- 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)) {
10759
+ 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))) {
10680
10760
  return clientInformation.token_endpoint_auth_method;
10681
10761
  }
10762
+ if (supportedMethods.length === 0) {
10763
+ return hasClientSecret ? "client_secret_basic" : "none";
10764
+ }
10682
10765
  if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
10683
10766
  return "client_secret_basic";
10684
10767
  }
@@ -10789,6 +10872,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10789
10872
  });
10790
10873
  }
10791
10874
  const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
10875
+ const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
10792
10876
  let clientInformation = await Promise.resolve(provider.clientInformation());
10793
10877
  if (!clientInformation) {
10794
10878
  if (authorizationCode !== void 0) {
@@ -10812,6 +10896,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10812
10896
  const fullInformation = await registerClient(authorizationServerUrl, {
10813
10897
  metadata,
10814
10898
  clientMetadata: provider.clientMetadata,
10899
+ scope: resolvedScope,
10815
10900
  fetchFn
10816
10901
  });
10817
10902
  await provider.saveClientInformation(fullInformation);
@@ -10855,7 +10940,7 @@ async function authInternal(provider, { serverUrl, authorizationCode, scope, res
10855
10940
  clientInformation,
10856
10941
  state,
10857
10942
  redirectUrl: provider.redirectUrl,
10858
- scope: scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope,
10943
+ scope: resolvedScope,
10859
10944
  resource
10860
10945
  });
10861
10946
  await provider.saveCodeVerifier(codeVerifier);
@@ -11173,7 +11258,7 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
11173
11258
  fetchFn
11174
11259
  });
11175
11260
  }
11176
- async function registerClient(authorizationServerUrl, { metadata, clientMetadata, fetchFn }) {
11261
+ async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
11177
11262
  let registrationUrl;
11178
11263
  if (metadata) {
11179
11264
  if (!metadata.registration_endpoint) {
@@ -11188,7 +11273,10 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
11188
11273
  headers: {
11189
11274
  "Content-Type": "application/json"
11190
11275
  },
11191
- body: JSON.stringify(clientMetadata)
11276
+ body: JSON.stringify({
11277
+ ...clientMetadata,
11278
+ ...scope !== void 0 ? { scope } : {}
11279
+ })
11192
11280
  });
11193
11281
  if (!response.ok) {
11194
11282
  throw await parseErrorResponse(response);
@@ -12283,7 +12371,7 @@ var SystemPrompts = {
12283
12371
  </rules>
12284
12372
 
12285
12373
  <format>
12286
- Get tool schemas: \`{ "tool": "man", "args": { "tools": ["tool1", "tool2"] } }\`
12374
+ Get tool definitions: \`{ "tool": "man", "args": { "tools": ["tool1", "tool2"] } }\`
12287
12375
  Execute a tool: \`{ "tool": "tool_name", "args": { /* parameters */ } }\`
12288
12376
  </format>`,
12289
12377
  /**
@@ -12408,7 +12496,7 @@ function createArgsDefFactory(_name, _allToolNames, _depGroups, _predefinedSteps
12408
12496
  *
12409
12497
  * Only two fields:
12410
12498
  * - `tool`: which tool to execute (enum includes "man" + all tool names)
12411
- * - `args`: object with parameters. For "man": { tools: ["a", "b"] }. For others: tool parameters.
12499
+ * - `args`: object with parameters. For "man": { tools: ["a", "b"] } to fetch tool definitions (including input/output schemas). For others: tool parameters.
12412
12500
  */
12413
12501
  forAgentic: function(allToolNames) {
12414
12502
  const toolEnum = [
@@ -14360,11 +14448,12 @@ var ToolManager = class {
14360
14448
  /**
14361
14449
  * Register a tool in the registry
14362
14450
  */
14363
- registerTool(name, description, schema, callback, options = {}) {
14451
+ registerTool(name, description, inputSchema, callback, options = {}) {
14364
14452
  this.toolRegistry.set(name, {
14365
14453
  callback,
14366
14454
  description,
14367
- schema
14455
+ inputSchema,
14456
+ outputSchema: options.outputSchema
14368
14457
  });
14369
14458
  if (options.hidden) {
14370
14459
  this.toolConfigs.set(name, {
@@ -14377,13 +14466,16 @@ var ToolManager = class {
14377
14466
  /**
14378
14467
  * Explicitly mark a tool as public (exposed to MCP clients)
14379
14468
  */
14380
- addPublicTool(name, description, schema) {
14469
+ addPublicTool(name, description, inputSchema, outputSchema) {
14381
14470
  const existingTool = this.publicTools.find((t) => t.name === name);
14382
14471
  if (!existingTool) {
14383
14472
  this.publicTools.push({
14384
14473
  name,
14385
14474
  description,
14386
- inputSchema: schema
14475
+ inputSchema,
14476
+ ...outputSchema ? {
14477
+ outputSchema
14478
+ } : {}
14387
14479
  });
14388
14480
  }
14389
14481
  this.toolConfigs.set(name, {
@@ -14509,10 +14601,13 @@ var ToolManager = class {
14509
14601
  getHiddenToolSchema(name) {
14510
14602
  const tool2 = this.toolRegistry.get(name);
14511
14603
  const config = this.toolConfigs.get(name);
14512
- if (tool2 && config?.visibility?.hidden && tool2.schema) {
14604
+ if (tool2 && config?.visibility?.hidden && tool2.inputSchema) {
14513
14605
  return {
14514
14606
  description: tool2.description,
14515
- schema: tool2.schema
14607
+ inputSchema: tool2.inputSchema,
14608
+ ...tool2.outputSchema ? {
14609
+ outputSchema: tool2.outputSchema
14610
+ } : {}
14516
14611
  };
14517
14612
  }
14518
14613
  return void 0;
@@ -14548,10 +14643,13 @@ var ToolManager = class {
14548
14643
  composedTools[name] = {
14549
14644
  name,
14550
14645
  description: tool2.description,
14551
- inputSchema: jsonSchema(tool2.schema || {
14646
+ inputSchema: jsonSchema(tool2.inputSchema || {
14552
14647
  type: "object",
14553
14648
  properties: {}
14554
14649
  }),
14650
+ ...tool2.outputSchema ? {
14651
+ outputSchema: jsonSchema(tool2.outputSchema)
14652
+ } : {},
14555
14653
  execute: tool2.callback
14556
14654
  };
14557
14655
  }
@@ -14568,10 +14666,13 @@ var ToolManager = class {
14568
14666
  return {
14569
14667
  name,
14570
14668
  description: tool2.description,
14571
- inputSchema: tool2.schema ?? {
14669
+ inputSchema: tool2.inputSchema ?? {
14572
14670
  type: "object",
14573
14671
  properties: {}
14574
14672
  },
14673
+ ...tool2.outputSchema ? {
14674
+ outputSchema: tool2.outputSchema
14675
+ } : {},
14575
14676
  execute: tool2.callback
14576
14677
  };
14577
14678
  }
@@ -14585,10 +14686,13 @@ var ToolManager = class {
14585
14686
  composedTools.push({
14586
14687
  name,
14587
14688
  description: tool2.description,
14588
- inputSchema: tool2.schema ?? {
14689
+ inputSchema: tool2.inputSchema ?? {
14589
14690
  type: "object",
14590
14691
  properties: {}
14591
14692
  },
14693
+ ...tool2.outputSchema ? {
14694
+ outputSchema: tool2.outputSchema
14695
+ } : {},
14592
14696
  execute: tool2.callback
14593
14697
  });
14594
14698
  }
@@ -14641,7 +14745,10 @@ async function processToolsWithPlugins(server, _externalTools, mode) {
14641
14745
  const tempTool = {
14642
14746
  name: toolId,
14643
14747
  description: toolData.description,
14644
- inputSchema: toolData.schema || defaultSchema,
14748
+ inputSchema: toolData.inputSchema || defaultSchema,
14749
+ ...toolData.outputSchema ? {
14750
+ outputSchema: toolData.outputSchema
14751
+ } : {},
14645
14752
  execute: toolData.callback
14646
14753
  };
14647
14754
  const processedTool = await pluginManager.applyTransformToolHooks(tempTool, {
@@ -14653,7 +14760,9 @@ async function processToolsWithPlugins(server, _externalTools, mode) {
14653
14760
  },
14654
14761
  transformationIndex: 0
14655
14762
  });
14656
- toolManager.registerTool(toolId, processedTool.description || toolData.description, processedTool.inputSchema, processedTool.execute);
14763
+ toolManager.registerTool(toolId, processedTool.description || toolData.description, processedTool.inputSchema, processedTool.execute, {
14764
+ outputSchema: processedTool.outputSchema
14765
+ });
14657
14766
  }
14658
14767
  }
14659
14768
  function buildDependencyGroups(toolNameToDetailList, hiddenToolNames, publicToolNames, server) {
@@ -14699,6 +14808,7 @@ var ComposableMCPServer = class extends Server {
14699
14808
  toolManager;
14700
14809
  logger = createLogger("mcpc.compose");
14701
14810
  fileLoaders = /* @__PURE__ */ new Map();
14811
+ pluginsDisposed = false;
14702
14812
  // Legacy property for backward compatibility
14703
14813
  get toolNameMapping() {
14704
14814
  return this.toolManager.getToolNameMapping();
@@ -14827,9 +14937,13 @@ var ComposableMCPServer = class extends Server {
14827
14937
  }
14828
14938
  tool(name, description, paramsSchema, cb, options = {}) {
14829
14939
  const jsonSchemaObj = extractJsonSchema(paramsSchema);
14830
- this.toolManager.registerTool(name, description, jsonSchemaObj, cb, options);
14940
+ const outputSchemaObj = options.outputSchema ? extractJsonSchema(options.outputSchema) : void 0;
14941
+ this.toolManager.registerTool(name, description, jsonSchemaObj, cb, {
14942
+ ...options,
14943
+ outputSchema: outputSchemaObj
14944
+ });
14831
14945
  if (!options.internal) {
14832
- this.toolManager.addPublicTool(name, description, jsonSchemaObj);
14946
+ this.toolManager.addPublicTool(name, description, jsonSchemaObj, outputSchemaObj);
14833
14947
  }
14834
14948
  if (options.plugins) {
14835
14949
  for (const plugin of options.plugins) {
@@ -15086,9 +15200,12 @@ var ComposableMCPServer = class extends Server {
15086
15200
  return {
15087
15201
  name,
15088
15202
  description: tool2?.description || "",
15089
- inputSchema: tool2?.schema || {
15203
+ inputSchema: tool2?.inputSchema || {
15090
15204
  type: "object"
15091
- }
15205
+ },
15206
+ ...tool2?.outputSchema ? {
15207
+ outputSchema: tool2.outputSchema
15208
+ } : {}
15092
15209
  };
15093
15210
  });
15094
15211
  }
@@ -15113,9 +15230,12 @@ var ComposableMCPServer = class extends Server {
15113
15230
  return Array.from(registry.entries()).map(([name, tool2]) => ({
15114
15231
  name,
15115
15232
  description: tool2?.description || "",
15116
- inputSchema: tool2?.schema || {
15233
+ inputSchema: tool2?.inputSchema || {
15117
15234
  type: "object"
15118
- }
15235
+ },
15236
+ ...tool2?.outputSchema ? {
15237
+ outputSchema: tool2.outputSchema
15238
+ } : {}
15119
15239
  }));
15120
15240
  }
15121
15241
  /**
@@ -15174,11 +15294,21 @@ var ComposableMCPServer = class extends Server {
15174
15294
  async disposePlugins() {
15175
15295
  await this.pluginManager.dispose();
15176
15296
  }
15297
+ /**
15298
+ * Dispose plugins only once to avoid duplicated cleanup in chained handlers.
15299
+ */
15300
+ async disposePluginsOnce() {
15301
+ if (this.pluginsDisposed) {
15302
+ return;
15303
+ }
15304
+ this.pluginsDisposed = true;
15305
+ await this.disposePlugins();
15306
+ }
15177
15307
  /**
15178
15308
  * Close the server and ensure all plugins are disposed
15179
15309
  */
15180
15310
  async close() {
15181
- await this.disposePlugins();
15311
+ await this.disposePluginsOnce();
15182
15312
  await super.close();
15183
15313
  }
15184
15314
  async compose(name, description, depsConfig = {
@@ -15247,7 +15377,9 @@ var ComposableMCPServer = class extends Server {
15247
15377
  });
15248
15378
  });
15249
15379
  Object.entries(tools).forEach(([toolId, tool2]) => {
15250
- this.toolManager.registerTool(toolId, tool2.description || "", tool2.inputSchema, tool2.execute);
15380
+ this.toolManager.registerTool(toolId, tool2.description || "", tool2.inputSchema, tool2.execute, {
15381
+ outputSchema: tool2.outputSchema
15382
+ });
15251
15383
  });
15252
15384
  const registeredTools = this.toolManager.getRegisteredToolsAsComposed();
15253
15385
  const allTools = {
@@ -15283,16 +15415,20 @@ var ComposableMCPServer = class extends Server {
15283
15415
  server: this,
15284
15416
  toolNames: Object.keys(allTools)
15285
15417
  });
15418
+ const previousOnClose = this.onclose;
15286
15419
  this.onclose = async () => {
15287
15420
  await cleanupClients();
15288
- await this.disposePlugins();
15421
+ await this.disposePluginsOnce();
15289
15422
  await this.logger.info(`[${name}] Event: closed - cleaned up dependent clients and plugins`);
15423
+ previousOnClose?.();
15290
15424
  };
15425
+ const previousOnError = this.onerror;
15291
15426
  this.onerror = async (error) => {
15292
15427
  await this.logger.error(`[${name}] Event: error - ${error?.stack ?? String(error)}`);
15293
15428
  await cleanupClients();
15294
- await this.disposePlugins();
15429
+ await this.disposePluginsOnce();
15295
15430
  await this.logger.info(`[${name}] Action: cleaned up dependent clients and plugins`);
15431
+ previousOnError?.(error);
15296
15432
  };
15297
15433
  const toolNameToDetailList = Object.entries(allTools);
15298
15434
  const publicToolNames = this.getPublicToolNames();
@@ -15304,7 +15440,8 @@ var ComposableMCPServer = class extends Server {
15304
15440
  return;
15305
15441
  }
15306
15442
  this.tool(toolId, tool2.description || "", jsonSchema(tool2.inputSchema), tool2.execute, {
15307
- internal: false
15443
+ internal: false,
15444
+ outputSchema: tool2.outputSchema
15308
15445
  });
15309
15446
  });
15310
15447
  await this.pluginManager.triggerComposeEnd({