@mcpc-tech/cli 0.1.31 → 0.1.32

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.
Files changed (3) hide show
  1. package/bin/mcpc.cjs +299 -9
  2. package/bin/mcpc.mjs +299 -9
  3. package/package.json +1 -1
package/bin/mcpc.cjs CHANGED
@@ -7794,7 +7794,9 @@ ${JSON.stringify(cleanedSchema, null, 2)}
7794
7794
  tool: tool2
7795
7795
  });
7796
7796
  try {
7797
- const result = await this.server.callTool(tool2, toolArgs);
7797
+ const result = await this.server.callTool(tool2, toolArgs, {
7798
+ agentName: this.name
7799
+ });
7798
7800
  const callToolResult = result ?? {
7799
7801
  content: []
7800
7802
  };
@@ -8829,7 +8831,7 @@ function isValidPlugin(plugin) {
8829
8831
  if (!p2.name || typeof p2.name !== "string" || p2.name.trim() === "") {
8830
8832
  return false;
8831
8833
  }
8832
- const hasHook = typeof p2.configureServer === "function" || typeof p2.composeStart === "function" || typeof p2.transformTool === "function" || typeof p2.finalizeComposition === "function" || typeof p2.registerAgentTool === "function" || typeof p2.composeEnd === "function" || typeof p2.transformInput === "function" || typeof p2.transformOutput === "function" || typeof p2.dispose === "function";
8834
+ const hasHook = typeof p2.configureServer === "function" || typeof p2.composeStart === "function" || typeof p2.transformTool === "function" || typeof p2.finalizeComposition === "function" || typeof p2.registerAgentTool === "function" || typeof p2.composeEnd === "function" || typeof p2.transformInput === "function" || typeof p2.transformOutput === "function" || typeof p2.beforeToolExecute === "function" || typeof p2.afterToolExecute === "function" || typeof p2.dispose === "function";
8833
8835
  if (!hasHook) return false;
8834
8836
  if (p2.enforce && p2.enforce !== "pre" && p2.enforce !== "post") {
8835
8837
  return false;
@@ -9136,6 +9138,113 @@ var PluginManager = class {
9136
9138
  }
9137
9139
  return false;
9138
9140
  }
9141
+ // === Tool Execution Lifecycle Hooks ===
9142
+ /**
9143
+ * Trigger beforeToolExecute hooks for all applicable plugins
9144
+ * Returns the combined result from all plugins
9145
+ *
9146
+ * Hook execution order:
9147
+ * 1. 'pre' enforced plugins first
9148
+ * 2. Normal plugins (no enforce)
9149
+ * 3. 'post' enforced plugins last
9150
+ *
9151
+ * If any plugin returns skipExecution=true, execution is skipped
9152
+ * and the result from that plugin is used.
9153
+ */
9154
+ async triggerBeforeToolExecute(context2) {
9155
+ const beforePlugins = this.plugins.filter((p2) => p2.beforeToolExecute);
9156
+ if (beforePlugins.length === 0) {
9157
+ return void 0;
9158
+ }
9159
+ const sortedPlugins = sortPluginsByOrder(beforePlugins);
9160
+ let currentArgs = context2.args;
9161
+ let combinedMetadata = {};
9162
+ for (const plugin of sortedPlugins) {
9163
+ if (plugin.beforeToolExecute) {
9164
+ try {
9165
+ const result = await plugin.beforeToolExecute({
9166
+ ...context2,
9167
+ args: currentArgs
9168
+ });
9169
+ if (result) {
9170
+ if (result.metadata) {
9171
+ combinedMetadata = {
9172
+ ...combinedMetadata,
9173
+ ...result.metadata
9174
+ };
9175
+ }
9176
+ if (result.skipExecution) {
9177
+ return {
9178
+ skipExecution: true,
9179
+ result: result.result,
9180
+ metadata: combinedMetadata
9181
+ };
9182
+ }
9183
+ if (result.modifiedArgs !== void 0) {
9184
+ currentArgs = result.modifiedArgs;
9185
+ }
9186
+ }
9187
+ } catch (error) {
9188
+ const errorMsg = error instanceof Error ? error.message : String(error);
9189
+ await this.logger.error(`Plugin "${plugin.name}" beforeToolExecute failed for "${context2.toolName}": ${errorMsg}`);
9190
+ }
9191
+ }
9192
+ }
9193
+ if (currentArgs !== context2.args) {
9194
+ return {
9195
+ modifiedArgs: currentArgs,
9196
+ metadata: Object.keys(combinedMetadata).length > 0 ? combinedMetadata : void 0
9197
+ };
9198
+ }
9199
+ if (Object.keys(combinedMetadata).length > 0) {
9200
+ return {
9201
+ metadata: combinedMetadata
9202
+ };
9203
+ }
9204
+ return void 0;
9205
+ }
9206
+ /**
9207
+ * Trigger afterToolExecute hooks for all applicable plugins
9208
+ * Returns the final result after all plugins have processed it
9209
+ */
9210
+ async triggerAfterToolExecute(context2) {
9211
+ const afterPlugins = this.plugins.filter((p2) => p2.afterToolExecute);
9212
+ if (afterPlugins.length === 0) {
9213
+ return void 0;
9214
+ }
9215
+ const sortedPlugins = sortPluginsByOrder(afterPlugins);
9216
+ let currentResult = context2.result;
9217
+ let markAsError = context2.isError;
9218
+ for (const plugin of sortedPlugins) {
9219
+ if (plugin.afterToolExecute) {
9220
+ try {
9221
+ const result = await plugin.afterToolExecute({
9222
+ ...context2,
9223
+ result: currentResult,
9224
+ isError: markAsError
9225
+ });
9226
+ if (result) {
9227
+ if (result.modifiedResult !== void 0) {
9228
+ currentResult = result.modifiedResult;
9229
+ }
9230
+ if (result.markAsError !== void 0) {
9231
+ markAsError = result.markAsError;
9232
+ }
9233
+ }
9234
+ } catch (error) {
9235
+ const errorMsg = error instanceof Error ? error.message : String(error);
9236
+ await this.logger.error(`Plugin "${plugin.name}" afterToolExecute failed for "${context2.toolName}": ${errorMsg}`);
9237
+ }
9238
+ }
9239
+ }
9240
+ if (currentResult !== context2.result || markAsError !== context2.isError) {
9241
+ return {
9242
+ modifiedResult: currentResult,
9243
+ markAsError
9244
+ };
9245
+ }
9246
+ return void 0;
9247
+ }
9139
9248
  /**
9140
9249
  * Dispose all plugins and cleanup resources
9141
9250
  */
@@ -9366,6 +9475,24 @@ var ToolManager = class {
9366
9475
  }
9367
9476
  return composedTools;
9368
9477
  }
9478
+ /**
9479
+ * Get a single tool as ComposedTool object by name
9480
+ */
9481
+ getComposedTool(name) {
9482
+ const tool2 = this.toolRegistry.get(name);
9483
+ if (!tool2) {
9484
+ return void 0;
9485
+ }
9486
+ return {
9487
+ name,
9488
+ description: tool2.description,
9489
+ inputSchema: tool2.schema ?? {
9490
+ type: "object",
9491
+ properties: {}
9492
+ },
9493
+ execute: tool2.callback
9494
+ };
9495
+ }
9369
9496
  };
9370
9497
 
9371
9498
  // __mcpc__cli_latest/node_modules/@jsr/mcpc__core/src/utils/common/schema.js
@@ -9566,9 +9693,81 @@ var ComposableMCPServer = class extends Server {
9566
9693
  if (!handler) {
9567
9694
  throw new Error(`Tool ${toolName} not found`);
9568
9695
  }
9569
- const processedArgs = await this.applyPluginTransforms(toolName, args, "input");
9570
- const result = await handler(processedArgs, extra);
9571
- return await this.applyPluginTransforms(toolName, result, "output", args);
9696
+ const toolDefinition = this.toolManager.getComposedTool(toolName);
9697
+ const startTime = Date.now();
9698
+ const beforeContext = {
9699
+ toolName,
9700
+ args,
9701
+ server: this,
9702
+ toolDefinition,
9703
+ isInternalCall: false
9704
+ };
9705
+ const beforeResult = await this.pluginManager.triggerBeforeToolExecute(beforeContext);
9706
+ if (beforeResult?.skipExecution) {
9707
+ const executionTimeMs2 = Date.now() - startTime;
9708
+ const afterContext2 = {
9709
+ toolName,
9710
+ args,
9711
+ result: beforeResult.result,
9712
+ server: this,
9713
+ wasSkipped: true,
9714
+ executionTimeMs: executionTimeMs2,
9715
+ isError: false,
9716
+ metadata: beforeResult.metadata,
9717
+ isInternalCall: false
9718
+ };
9719
+ const afterResult2 = await this.pluginManager.triggerAfterToolExecute(afterContext2);
9720
+ let finalResult = afterResult2?.modifiedResult ?? beforeResult.result;
9721
+ if (afterResult2?.markAsError && finalResult) {
9722
+ finalResult = {
9723
+ ...finalResult,
9724
+ isError: true
9725
+ };
9726
+ }
9727
+ return finalResult;
9728
+ }
9729
+ const effectiveArgs = beforeResult?.modifiedArgs ?? args;
9730
+ const processedArgs = await this.applyPluginTransforms(toolName, effectiveArgs, "input");
9731
+ let result = await handler(processedArgs, extra);
9732
+ const isError = !!result?.isError;
9733
+ result = await this.applyPluginTransforms(toolName, result, "output", args);
9734
+ if (isError && result && !("isError" in result)) {
9735
+ result = {
9736
+ ...result,
9737
+ isError: true
9738
+ };
9739
+ }
9740
+ const executionTimeMs = Date.now() - startTime;
9741
+ const afterContext = {
9742
+ toolName,
9743
+ args,
9744
+ result,
9745
+ server: this,
9746
+ wasSkipped: false,
9747
+ executionTimeMs,
9748
+ isError,
9749
+ metadata: beforeResult?.metadata,
9750
+ isInternalCall: false
9751
+ };
9752
+ const afterResult = await this.pluginManager.triggerAfterToolExecute(afterContext);
9753
+ if (afterResult?.modifiedResult !== void 0) {
9754
+ let finalResult = afterResult.modifiedResult;
9755
+ const hasExplicitIsError = finalResult && "isError" in finalResult;
9756
+ if (!hasExplicitIsError && afterResult.markAsError && finalResult) {
9757
+ finalResult = {
9758
+ ...finalResult,
9759
+ isError: true
9760
+ };
9761
+ }
9762
+ return finalResult;
9763
+ }
9764
+ if (afterResult?.markAsError && result) {
9765
+ return {
9766
+ ...result,
9767
+ isError: true
9768
+ };
9769
+ }
9770
+ return result;
9572
9771
  });
9573
9772
  this.setRequestHandler(SetLevelRequestSchema, (request) => {
9574
9773
  const { level } = request.params;
@@ -9590,8 +9789,9 @@ var ComposableMCPServer = class extends Server {
9590
9789
  }
9591
9790
  /**
9592
9791
  * Call any registered tool directly, whether it's public or internal
9792
+ * Supports tool execution lifecycle hooks for dynamic context handoff
9593
9793
  */
9594
- async callTool(name, args) {
9794
+ async callTool(name, args, options = {}) {
9595
9795
  const resolvedName = this.resolveToolName(name);
9596
9796
  if (!resolvedName) {
9597
9797
  throw new Error(`Tool ${name} not found`);
@@ -9600,9 +9800,99 @@ var ComposableMCPServer = class extends Server {
9600
9800
  if (!callback) {
9601
9801
  throw new Error(`Tool ${name} not found`);
9602
9802
  }
9603
- const processedArgs = await this.applyPluginTransforms(resolvedName, args, "input");
9604
- const result = await callback(processedArgs);
9605
- return await this.applyPluginTransforms(resolvedName, result, "output", args);
9803
+ const toolDefinition = this.toolManager.getComposedTool(resolvedName);
9804
+ const startTime = Date.now();
9805
+ const beforeContext = {
9806
+ toolName: resolvedName,
9807
+ args,
9808
+ server: this,
9809
+ toolDefinition,
9810
+ isInternalCall: true,
9811
+ agentName: options.agentName,
9812
+ executionChain: options.executionChain
9813
+ };
9814
+ const beforeResult = await this.pluginManager.triggerBeforeToolExecute(beforeContext);
9815
+ if (beforeResult?.skipExecution) {
9816
+ const executionTimeMs2 = Date.now() - startTime;
9817
+ const afterContext2 = {
9818
+ toolName: resolvedName,
9819
+ args,
9820
+ result: beforeResult.result,
9821
+ server: this,
9822
+ wasSkipped: true,
9823
+ executionTimeMs: executionTimeMs2,
9824
+ isError: false,
9825
+ metadata: beforeResult.metadata,
9826
+ isInternalCall: true,
9827
+ agentName: options.agentName
9828
+ };
9829
+ const afterResult2 = await this.pluginManager.triggerAfterToolExecute(afterContext2);
9830
+ let finalResult = afterResult2?.modifiedResult ?? beforeResult.result;
9831
+ if (afterResult2?.markAsError && finalResult && typeof finalResult === "object") {
9832
+ finalResult = {
9833
+ ...finalResult,
9834
+ isError: true
9835
+ };
9836
+ }
9837
+ return finalResult;
9838
+ }
9839
+ const effectiveArgs = beforeResult?.modifiedArgs ?? args;
9840
+ const processedArgs = await this.applyPluginTransforms(resolvedName, effectiveArgs, "input");
9841
+ let result;
9842
+ let isError = false;
9843
+ try {
9844
+ result = await callback(processedArgs);
9845
+ } catch (error) {
9846
+ isError = true;
9847
+ result = {
9848
+ content: [
9849
+ {
9850
+ type: "text",
9851
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
9852
+ }
9853
+ ],
9854
+ isError: true
9855
+ };
9856
+ }
9857
+ result = await this.applyPluginTransforms(resolvedName, result, "output", args);
9858
+ if (isError && result && typeof result === "object" && !("isError" in result)) {
9859
+ result = {
9860
+ ...result,
9861
+ isError: true
9862
+ };
9863
+ }
9864
+ const executionTimeMs = Date.now() - startTime;
9865
+ const afterContext = {
9866
+ toolName: resolvedName,
9867
+ args,
9868
+ result,
9869
+ server: this,
9870
+ wasSkipped: false,
9871
+ executionTimeMs,
9872
+ isError,
9873
+ metadata: beforeResult?.metadata,
9874
+ isInternalCall: true,
9875
+ agentName: options.agentName
9876
+ };
9877
+ const afterResult = await this.pluginManager.triggerAfterToolExecute(afterContext);
9878
+ if (afterResult?.modifiedResult !== void 0) {
9879
+ let finalResult = afterResult.modifiedResult;
9880
+ const hasExplicitIsError = finalResult && typeof finalResult === "object" && "isError" in finalResult;
9881
+ if (!hasExplicitIsError && afterResult.markAsError && finalResult && typeof finalResult === "object") {
9882
+ finalResult = {
9883
+ ...finalResult,
9884
+ isError: true
9885
+ };
9886
+ }
9887
+ return finalResult;
9888
+ }
9889
+ if (afterResult?.markAsError && result && typeof result === "object") {
9890
+ return {
9891
+ ...result,
9892
+ isError: true
9893
+ };
9894
+ }
9895
+ return result;
9606
9896
  }
9607
9897
  /**
9608
9898
  * Get all public tool names (exposed to MCP clients)
package/bin/mcpc.mjs CHANGED
@@ -7802,7 +7802,9 @@ ${JSON.stringify(cleanedSchema, null, 2)}
7802
7802
  tool: tool2
7803
7803
  });
7804
7804
  try {
7805
- const result = await this.server.callTool(tool2, toolArgs);
7805
+ const result = await this.server.callTool(tool2, toolArgs, {
7806
+ agentName: this.name
7807
+ });
7806
7808
  const callToolResult = result ?? {
7807
7809
  content: []
7808
7810
  };
@@ -8836,7 +8838,7 @@ function isValidPlugin(plugin) {
8836
8838
  if (!p2.name || typeof p2.name !== "string" || p2.name.trim() === "") {
8837
8839
  return false;
8838
8840
  }
8839
- const hasHook = typeof p2.configureServer === "function" || typeof p2.composeStart === "function" || typeof p2.transformTool === "function" || typeof p2.finalizeComposition === "function" || typeof p2.registerAgentTool === "function" || typeof p2.composeEnd === "function" || typeof p2.transformInput === "function" || typeof p2.transformOutput === "function" || typeof p2.dispose === "function";
8841
+ const hasHook = typeof p2.configureServer === "function" || typeof p2.composeStart === "function" || typeof p2.transformTool === "function" || typeof p2.finalizeComposition === "function" || typeof p2.registerAgentTool === "function" || typeof p2.composeEnd === "function" || typeof p2.transformInput === "function" || typeof p2.transformOutput === "function" || typeof p2.beforeToolExecute === "function" || typeof p2.afterToolExecute === "function" || typeof p2.dispose === "function";
8840
8842
  if (!hasHook) return false;
8841
8843
  if (p2.enforce && p2.enforce !== "pre" && p2.enforce !== "post") {
8842
8844
  return false;
@@ -9143,6 +9145,113 @@ var PluginManager = class {
9143
9145
  }
9144
9146
  return false;
9145
9147
  }
9148
+ // === Tool Execution Lifecycle Hooks ===
9149
+ /**
9150
+ * Trigger beforeToolExecute hooks for all applicable plugins
9151
+ * Returns the combined result from all plugins
9152
+ *
9153
+ * Hook execution order:
9154
+ * 1. 'pre' enforced plugins first
9155
+ * 2. Normal plugins (no enforce)
9156
+ * 3. 'post' enforced plugins last
9157
+ *
9158
+ * If any plugin returns skipExecution=true, execution is skipped
9159
+ * and the result from that plugin is used.
9160
+ */
9161
+ async triggerBeforeToolExecute(context2) {
9162
+ const beforePlugins = this.plugins.filter((p2) => p2.beforeToolExecute);
9163
+ if (beforePlugins.length === 0) {
9164
+ return void 0;
9165
+ }
9166
+ const sortedPlugins = sortPluginsByOrder(beforePlugins);
9167
+ let currentArgs = context2.args;
9168
+ let combinedMetadata = {};
9169
+ for (const plugin of sortedPlugins) {
9170
+ if (plugin.beforeToolExecute) {
9171
+ try {
9172
+ const result = await plugin.beforeToolExecute({
9173
+ ...context2,
9174
+ args: currentArgs
9175
+ });
9176
+ if (result) {
9177
+ if (result.metadata) {
9178
+ combinedMetadata = {
9179
+ ...combinedMetadata,
9180
+ ...result.metadata
9181
+ };
9182
+ }
9183
+ if (result.skipExecution) {
9184
+ return {
9185
+ skipExecution: true,
9186
+ result: result.result,
9187
+ metadata: combinedMetadata
9188
+ };
9189
+ }
9190
+ if (result.modifiedArgs !== void 0) {
9191
+ currentArgs = result.modifiedArgs;
9192
+ }
9193
+ }
9194
+ } catch (error) {
9195
+ const errorMsg = error instanceof Error ? error.message : String(error);
9196
+ await this.logger.error(`Plugin "${plugin.name}" beforeToolExecute failed for "${context2.toolName}": ${errorMsg}`);
9197
+ }
9198
+ }
9199
+ }
9200
+ if (currentArgs !== context2.args) {
9201
+ return {
9202
+ modifiedArgs: currentArgs,
9203
+ metadata: Object.keys(combinedMetadata).length > 0 ? combinedMetadata : void 0
9204
+ };
9205
+ }
9206
+ if (Object.keys(combinedMetadata).length > 0) {
9207
+ return {
9208
+ metadata: combinedMetadata
9209
+ };
9210
+ }
9211
+ return void 0;
9212
+ }
9213
+ /**
9214
+ * Trigger afterToolExecute hooks for all applicable plugins
9215
+ * Returns the final result after all plugins have processed it
9216
+ */
9217
+ async triggerAfterToolExecute(context2) {
9218
+ const afterPlugins = this.plugins.filter((p2) => p2.afterToolExecute);
9219
+ if (afterPlugins.length === 0) {
9220
+ return void 0;
9221
+ }
9222
+ const sortedPlugins = sortPluginsByOrder(afterPlugins);
9223
+ let currentResult = context2.result;
9224
+ let markAsError = context2.isError;
9225
+ for (const plugin of sortedPlugins) {
9226
+ if (plugin.afterToolExecute) {
9227
+ try {
9228
+ const result = await plugin.afterToolExecute({
9229
+ ...context2,
9230
+ result: currentResult,
9231
+ isError: markAsError
9232
+ });
9233
+ if (result) {
9234
+ if (result.modifiedResult !== void 0) {
9235
+ currentResult = result.modifiedResult;
9236
+ }
9237
+ if (result.markAsError !== void 0) {
9238
+ markAsError = result.markAsError;
9239
+ }
9240
+ }
9241
+ } catch (error) {
9242
+ const errorMsg = error instanceof Error ? error.message : String(error);
9243
+ await this.logger.error(`Plugin "${plugin.name}" afterToolExecute failed for "${context2.toolName}": ${errorMsg}`);
9244
+ }
9245
+ }
9246
+ }
9247
+ if (currentResult !== context2.result || markAsError !== context2.isError) {
9248
+ return {
9249
+ modifiedResult: currentResult,
9250
+ markAsError
9251
+ };
9252
+ }
9253
+ return void 0;
9254
+ }
9146
9255
  /**
9147
9256
  * Dispose all plugins and cleanup resources
9148
9257
  */
@@ -9373,6 +9482,24 @@ var ToolManager = class {
9373
9482
  }
9374
9483
  return composedTools;
9375
9484
  }
9485
+ /**
9486
+ * Get a single tool as ComposedTool object by name
9487
+ */
9488
+ getComposedTool(name) {
9489
+ const tool2 = this.toolRegistry.get(name);
9490
+ if (!tool2) {
9491
+ return void 0;
9492
+ }
9493
+ return {
9494
+ name,
9495
+ description: tool2.description,
9496
+ inputSchema: tool2.schema ?? {
9497
+ type: "object",
9498
+ properties: {}
9499
+ },
9500
+ execute: tool2.callback
9501
+ };
9502
+ }
9376
9503
  };
9377
9504
 
9378
9505
  // __mcpc__cli_latest/node_modules/@jsr/mcpc__core/src/utils/common/schema.js
@@ -9573,9 +9700,81 @@ var ComposableMCPServer = class extends Server {
9573
9700
  if (!handler) {
9574
9701
  throw new Error(`Tool ${toolName} not found`);
9575
9702
  }
9576
- const processedArgs = await this.applyPluginTransforms(toolName, args, "input");
9577
- const result = await handler(processedArgs, extra);
9578
- return await this.applyPluginTransforms(toolName, result, "output", args);
9703
+ const toolDefinition = this.toolManager.getComposedTool(toolName);
9704
+ const startTime = Date.now();
9705
+ const beforeContext = {
9706
+ toolName,
9707
+ args,
9708
+ server: this,
9709
+ toolDefinition,
9710
+ isInternalCall: false
9711
+ };
9712
+ const beforeResult = await this.pluginManager.triggerBeforeToolExecute(beforeContext);
9713
+ if (beforeResult?.skipExecution) {
9714
+ const executionTimeMs2 = Date.now() - startTime;
9715
+ const afterContext2 = {
9716
+ toolName,
9717
+ args,
9718
+ result: beforeResult.result,
9719
+ server: this,
9720
+ wasSkipped: true,
9721
+ executionTimeMs: executionTimeMs2,
9722
+ isError: false,
9723
+ metadata: beforeResult.metadata,
9724
+ isInternalCall: false
9725
+ };
9726
+ const afterResult2 = await this.pluginManager.triggerAfterToolExecute(afterContext2);
9727
+ let finalResult = afterResult2?.modifiedResult ?? beforeResult.result;
9728
+ if (afterResult2?.markAsError && finalResult) {
9729
+ finalResult = {
9730
+ ...finalResult,
9731
+ isError: true
9732
+ };
9733
+ }
9734
+ return finalResult;
9735
+ }
9736
+ const effectiveArgs = beforeResult?.modifiedArgs ?? args;
9737
+ const processedArgs = await this.applyPluginTransforms(toolName, effectiveArgs, "input");
9738
+ let result = await handler(processedArgs, extra);
9739
+ const isError = !!result?.isError;
9740
+ result = await this.applyPluginTransforms(toolName, result, "output", args);
9741
+ if (isError && result && !("isError" in result)) {
9742
+ result = {
9743
+ ...result,
9744
+ isError: true
9745
+ };
9746
+ }
9747
+ const executionTimeMs = Date.now() - startTime;
9748
+ const afterContext = {
9749
+ toolName,
9750
+ args,
9751
+ result,
9752
+ server: this,
9753
+ wasSkipped: false,
9754
+ executionTimeMs,
9755
+ isError,
9756
+ metadata: beforeResult?.metadata,
9757
+ isInternalCall: false
9758
+ };
9759
+ const afterResult = await this.pluginManager.triggerAfterToolExecute(afterContext);
9760
+ if (afterResult?.modifiedResult !== void 0) {
9761
+ let finalResult = afterResult.modifiedResult;
9762
+ const hasExplicitIsError = finalResult && "isError" in finalResult;
9763
+ if (!hasExplicitIsError && afterResult.markAsError && finalResult) {
9764
+ finalResult = {
9765
+ ...finalResult,
9766
+ isError: true
9767
+ };
9768
+ }
9769
+ return finalResult;
9770
+ }
9771
+ if (afterResult?.markAsError && result) {
9772
+ return {
9773
+ ...result,
9774
+ isError: true
9775
+ };
9776
+ }
9777
+ return result;
9579
9778
  });
9580
9779
  this.setRequestHandler(SetLevelRequestSchema, (request) => {
9581
9780
  const { level } = request.params;
@@ -9597,8 +9796,9 @@ var ComposableMCPServer = class extends Server {
9597
9796
  }
9598
9797
  /**
9599
9798
  * Call any registered tool directly, whether it's public or internal
9799
+ * Supports tool execution lifecycle hooks for dynamic context handoff
9600
9800
  */
9601
- async callTool(name, args) {
9801
+ async callTool(name, args, options = {}) {
9602
9802
  const resolvedName = this.resolveToolName(name);
9603
9803
  if (!resolvedName) {
9604
9804
  throw new Error(`Tool ${name} not found`);
@@ -9607,9 +9807,99 @@ var ComposableMCPServer = class extends Server {
9607
9807
  if (!callback) {
9608
9808
  throw new Error(`Tool ${name} not found`);
9609
9809
  }
9610
- const processedArgs = await this.applyPluginTransforms(resolvedName, args, "input");
9611
- const result = await callback(processedArgs);
9612
- return await this.applyPluginTransforms(resolvedName, result, "output", args);
9810
+ const toolDefinition = this.toolManager.getComposedTool(resolvedName);
9811
+ const startTime = Date.now();
9812
+ const beforeContext = {
9813
+ toolName: resolvedName,
9814
+ args,
9815
+ server: this,
9816
+ toolDefinition,
9817
+ isInternalCall: true,
9818
+ agentName: options.agentName,
9819
+ executionChain: options.executionChain
9820
+ };
9821
+ const beforeResult = await this.pluginManager.triggerBeforeToolExecute(beforeContext);
9822
+ if (beforeResult?.skipExecution) {
9823
+ const executionTimeMs2 = Date.now() - startTime;
9824
+ const afterContext2 = {
9825
+ toolName: resolvedName,
9826
+ args,
9827
+ result: beforeResult.result,
9828
+ server: this,
9829
+ wasSkipped: true,
9830
+ executionTimeMs: executionTimeMs2,
9831
+ isError: false,
9832
+ metadata: beforeResult.metadata,
9833
+ isInternalCall: true,
9834
+ agentName: options.agentName
9835
+ };
9836
+ const afterResult2 = await this.pluginManager.triggerAfterToolExecute(afterContext2);
9837
+ let finalResult = afterResult2?.modifiedResult ?? beforeResult.result;
9838
+ if (afterResult2?.markAsError && finalResult && typeof finalResult === "object") {
9839
+ finalResult = {
9840
+ ...finalResult,
9841
+ isError: true
9842
+ };
9843
+ }
9844
+ return finalResult;
9845
+ }
9846
+ const effectiveArgs = beforeResult?.modifiedArgs ?? args;
9847
+ const processedArgs = await this.applyPluginTransforms(resolvedName, effectiveArgs, "input");
9848
+ let result;
9849
+ let isError = false;
9850
+ try {
9851
+ result = await callback(processedArgs);
9852
+ } catch (error) {
9853
+ isError = true;
9854
+ result = {
9855
+ content: [
9856
+ {
9857
+ type: "text",
9858
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
9859
+ }
9860
+ ],
9861
+ isError: true
9862
+ };
9863
+ }
9864
+ result = await this.applyPluginTransforms(resolvedName, result, "output", args);
9865
+ if (isError && result && typeof result === "object" && !("isError" in result)) {
9866
+ result = {
9867
+ ...result,
9868
+ isError: true
9869
+ };
9870
+ }
9871
+ const executionTimeMs = Date.now() - startTime;
9872
+ const afterContext = {
9873
+ toolName: resolvedName,
9874
+ args,
9875
+ result,
9876
+ server: this,
9877
+ wasSkipped: false,
9878
+ executionTimeMs,
9879
+ isError,
9880
+ metadata: beforeResult?.metadata,
9881
+ isInternalCall: true,
9882
+ agentName: options.agentName
9883
+ };
9884
+ const afterResult = await this.pluginManager.triggerAfterToolExecute(afterContext);
9885
+ if (afterResult?.modifiedResult !== void 0) {
9886
+ let finalResult = afterResult.modifiedResult;
9887
+ const hasExplicitIsError = finalResult && typeof finalResult === "object" && "isError" in finalResult;
9888
+ if (!hasExplicitIsError && afterResult.markAsError && finalResult && typeof finalResult === "object") {
9889
+ finalResult = {
9890
+ ...finalResult,
9891
+ isError: true
9892
+ };
9893
+ }
9894
+ return finalResult;
9895
+ }
9896
+ if (afterResult?.markAsError && result && typeof result === "object") {
9897
+ return {
9898
+ ...result,
9899
+ isError: true
9900
+ };
9901
+ }
9902
+ return result;
9613
9903
  }
9614
9904
  /**
9615
9905
  * Get all public tool names (exposed to MCP clients)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpc-tech/cli",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "homepage": "https://jsr.io/@mcpc/cli",
5
5
  "dependencies": {
6
6
  "@hono/zod-openapi": "^0.19.2",