11import { type RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js' ;
22import { server } from '../server/server-state.ts' ;
33import type { ToolResponse } from '../types/common.ts' ;
4+ import type { ToolCatalog , ToolDefinition } from '../runtime/types.ts' ;
45import { log } from './logger.ts' ;
56import { processToolResponse } from './responses/index.ts' ;
67import { loadManifest } from '../core/manifest/load-manifest.ts' ;
78import { importToolModule } from '../core/manifest/import-tool-module.ts' ;
9+ import { getEffectiveCliName } from '../core/manifest/schema.ts' ;
10+ import { createToolCatalog } from '../runtime/tool-catalog.ts' ;
11+ import { postProcessToolResponse } from '../runtime/tool-invoker.ts' ;
812import type { PredicateContext } from '../visibility/predicate-types.ts' ;
913import { selectWorkflowsForMcp , isToolExposedForRuntime } from '../visibility/exposure.ts' ;
1014import { getConfig } from './config-store.ts' ;
@@ -20,10 +24,13 @@ const registryState: {
2024 enabledWorkflows : Set < string > ;
2125 /** Current MCP predicate context (stored for use by manage_workflows) */
2226 currentContext : PredicateContext | null ;
27+ /** Catalog of currently registered MCP tools for next-step template resolution */
28+ catalog : ToolCatalog | null ;
2329} = {
2430 tools : new Map < string , RegisteredTool > ( ) ,
2531 enabledWorkflows : new Set < string > ( ) ,
2632 currentContext : null ,
33+ catalog : null ,
2734} ;
2835
2936export function getRuntimeRegistration ( ) : RuntimeToolInfo | null {
@@ -79,6 +86,8 @@ export async function applyWorkflowSelectionFromManifest(
7986
8087 const desiredToolNames = new Set < string > ( ) ;
8188 const desiredWorkflows = new Set < string > ( ) ;
89+ const catalogTools : ToolDefinition [ ] = [ ] ;
90+ const moduleCache = new Map < string , Awaited < ReturnType < typeof importToolModule > > > ( ) ;
8291
8392 for ( const workflow of selectedWorkflows ) {
8493 desiredWorkflows . add ( workflow . id ) ;
@@ -95,16 +104,32 @@ export async function applyWorkflowSelectionFromManifest(
95104 const toolName = toolManifest . names . mcp ;
96105 desiredToolNames . add ( toolName ) ;
97106
98- if ( ! registryState . tools . has ( toolName ) ) {
99- // Import the tool module
100- let toolModule ;
107+ let toolModule = moduleCache . get ( toolId ) ;
108+ if ( ! toolModule ) {
101109 try {
102110 toolModule = await importToolModule ( toolManifest . module ) ;
111+ moduleCache . set ( toolId , toolModule ) ;
103112 } catch ( err ) {
104113 log ( 'warning' , `Failed to import tool module ${ toolManifest . module } : ${ err } ` ) ;
105114 continue ;
106115 }
116+ }
107117
118+ catalogTools . push ( {
119+ id : toolManifest . id ,
120+ cliName : getEffectiveCliName ( toolManifest ) ,
121+ mcpName : toolName ,
122+ workflow : workflow . id ,
123+ description : toolManifest . description ,
124+ annotations : toolManifest . annotations ,
125+ nextStepTemplates : toolManifest . nextSteps ,
126+ mcpSchema : toolModule . schema ,
127+ cliSchema : toolModule . schema ,
128+ stateful : toolManifest . routing ?. stateful ?? false ,
129+ handler : toolModule . handler as ToolDefinition [ 'handler' ] ,
130+ } ) ;
131+
132+ if ( ! registryState . tools . has ( toolName ) ) {
108133 const registeredTool = server . registerTool (
109134 toolName ,
110135 {
@@ -116,14 +141,28 @@ export async function applyWorkflowSelectionFromManifest(
116141 const startedAt = Date . now ( ) ;
117142 try {
118143 const response = await toolModule . handler ( args as Record < string , unknown > ) ;
144+ const catalog = registryState . catalog ;
145+ const catalogTool = catalog ?. getByMcpName ( toolName ) ;
146+ const postProcessedResponse =
147+ catalog && catalogTool
148+ ? postProcessToolResponse ( {
149+ tool : catalogTool ,
150+ response : response as ToolResponse ,
151+ args : args as Record < string , unknown > ,
152+ catalog,
153+ runtime : 'mcp' ,
154+ } )
155+ : ( response as ToolResponse ) ;
156+
119157 recordToolInvocationMetric ( {
120158 toolName,
121159 runtime : 'mcp' ,
122160 transport : 'direct' ,
123161 outcome : 'completed' ,
124162 durationMs : Date . now ( ) - startedAt ,
125163 } ) ;
126- return processToolResponse ( response as ToolResponse , 'mcp' , 'normal' ) ;
164+
165+ return processToolResponse ( postProcessedResponse , 'mcp' , 'normal' ) ;
127166 } catch ( error ) {
128167 recordInternalErrorMetric ( {
129168 component : 'mcp-tool-registry' ,
@@ -146,6 +185,8 @@ export async function applyWorkflowSelectionFromManifest(
146185 }
147186 }
148187
188+ registryState . catalog = createToolCatalog ( catalogTools ) ;
189+
149190 // Unregister tools no longer in selection
150191 for ( const [ toolName , registeredTool ] of registryState . tools . entries ( ) ) {
151192 if ( ! desiredToolNames . has ( toolName ) ) {
@@ -196,4 +237,5 @@ export function __resetToolRegistryForTests(): void {
196237 registryState . tools . clear ( ) ;
197238 registryState . enabledWorkflows . clear ( ) ;
198239 registryState . currentContext = null ;
240+ registryState . catalog = null ;
199241}
0 commit comments