@@ -28,6 +28,25 @@ const getResourceSchema = z.object({
2828 . describe ( 'URI of the resource to fetch in the format "scheme://path"' ) ,
2929} ) ;
3030
31+ // Parameters for listTools method
32+ const listToolsSchema = z . object ( {
33+ server : z
34+ . string ( )
35+ . optional ( )
36+ . describe ( 'Optional server name to filter tools by' ) ,
37+ } ) ;
38+
39+ // Parameters for executeTool method
40+ const executeToolSchema = z . object ( {
41+ uri : z
42+ . string ( )
43+ . describe ( 'URI of the tool to execute in the format "scheme://path"' ) ,
44+ params : z
45+ . record ( z . unknown ( ) )
46+ . optional ( )
47+ . describe ( 'Parameters to pass to the tool' ) ,
48+ } ) ;
49+
3150// Return type for listResources
3251const listResourcesReturnSchema = z . array (
3352 z . object ( {
@@ -39,6 +58,20 @@ const listResourcesReturnSchema = z.array(
3958// Return type for getResource
4059const getResourceReturnSchema = z . string ( ) ;
4160
61+ // Return type for listTools
62+ const listToolsReturnSchema = z . array (
63+ z . object ( {
64+ uri : z . string ( ) ,
65+ name : z . string ( ) ,
66+ description : z . string ( ) . optional ( ) ,
67+ parameters : z . record ( z . unknown ( ) ) . optional ( ) ,
68+ returns : z . record ( z . unknown ( ) ) . optional ( ) ,
69+ } ) ,
70+ ) ;
71+
72+ // Return type for executeTool - can be any JSON value
73+ const executeToolReturnSchema = z . unknown ( ) ;
74+
4275// Map to store MCP clients
4376const mcpClients = new Map < string , any > ( ) ;
4477
@@ -87,7 +120,7 @@ export function createMcpTool(config: McpConfig): Tool {
87120 return {
88121 name : 'mcp' ,
89122 description :
90- 'Interact with Model Context Protocol (MCP) servers to retrieve resources' ,
123+ 'Interact with Model Context Protocol (MCP) servers to retrieve resources and execute tools ' ,
91124 parameters : z . discriminatedUnion ( 'method' , [
92125 z . object ( {
93126 method : z . literal ( 'listResources' ) ,
@@ -97,6 +130,14 @@ export function createMcpTool(config: McpConfig): Tool {
97130 method : z . literal ( 'getResource' ) ,
98131 params : getResourceSchema ,
99132 } ) ,
133+ z . object ( {
134+ method : z . literal ( 'listTools' ) ,
135+ params : listToolsSchema . optional ( ) ,
136+ } ) ,
137+ z . object ( {
138+ method : z . literal ( 'executeTool' ) ,
139+ params : executeToolSchema ,
140+ } ) ,
100141 ] ) ,
101142 parametersJsonSchema : zodToJsonSchema (
102143 z . discriminatedUnion ( 'method' , [
@@ -108,15 +149,33 @@ export function createMcpTool(config: McpConfig): Tool {
108149 method : z . literal ( 'getResource' ) ,
109150 params : getResourceSchema ,
110151 } ) ,
152+ z . object ( {
153+ method : z . literal ( 'listTools' ) ,
154+ params : listToolsSchema . optional ( ) ,
155+ } ) ,
156+ z . object ( {
157+ method : z . literal ( 'executeTool' ) ,
158+ params : executeToolSchema ,
159+ } ) ,
111160 ] ) ,
112161 ) ,
113- returns : z . union ( [ listResourcesReturnSchema , getResourceReturnSchema ] ) ,
162+ returns : z . union ( [
163+ listResourcesReturnSchema ,
164+ getResourceReturnSchema ,
165+ listToolsReturnSchema ,
166+ executeToolReturnSchema ,
167+ ] ) ,
114168 returnsJsonSchema : zodToJsonSchema (
115- z . union ( [ listResourcesReturnSchema , getResourceReturnSchema ] ) ,
169+ z . union ( [
170+ listResourcesReturnSchema ,
171+ getResourceReturnSchema ,
172+ listToolsReturnSchema ,
173+ executeToolReturnSchema ,
174+ ] ) ,
116175 ) ,
117176
118177 execute : async ( { method, params } , { logger } ) => {
119- // Extract the server name from a resource URI
178+ // Extract the server name from a URI ( resource or tool)
120179 function getServerNameFromUri ( uri : string ) : string | undefined {
121180 const match = uri . match ( / ^ ( [ ^ : ] + ) : \/ \/ / ) ;
122181 return match ? match [ 1 ] : undefined ;
@@ -180,6 +239,64 @@ export function createMcpTool(config: McpConfig): Tool {
180239 logger . verbose ( `Fetching resource: ${ uri } ` ) ;
181240 const resource = await client . resource ( uri ) ;
182241 return resource . content ;
242+ } else if ( method === 'listTools' ) {
243+ // List available tools from MCP servers
244+ const tools : any [ ] = [ ] ;
245+ const serverFilter = params ?. server ;
246+
247+ // If a specific server is requested, only check that server
248+ if ( serverFilter ) {
249+ const client = mcpClients . get ( serverFilter ) ;
250+ if ( client ) {
251+ try {
252+ logger . verbose ( `Fetching tools from server: ${ serverFilter } ` ) ;
253+ const serverTools = await client . tools ( ) ;
254+ tools . push ( ...( serverTools as any [ ] ) ) ;
255+ } catch ( error ) {
256+ logger . error (
257+ `Failed to fetch tools from server ${ serverFilter } :` ,
258+ error ,
259+ ) ;
260+ }
261+ } else {
262+ logger . warn ( `Server not found: ${ serverFilter } ` ) ;
263+ }
264+ } else {
265+ // Otherwise, check all servers
266+ for ( const [ serverName , client ] of mcpClients . entries ( ) ) {
267+ try {
268+ logger . verbose ( `Fetching tools from server: ${ serverName } ` ) ;
269+ const serverTools = await client . tools ( ) ;
270+ tools . push ( ...( serverTools as any [ ] ) ) ;
271+ } catch ( error ) {
272+ logger . error (
273+ `Failed to fetch tools from server ${ serverName } :` ,
274+ error ,
275+ ) ;
276+ }
277+ }
278+ }
279+
280+ return tools ;
281+ } else if ( method === 'executeTool' ) {
282+ // Execute a tool from an MCP server
283+ const { uri, params : toolParams = { } } = params ;
284+
285+ // Parse the URI to determine which server to use
286+ const serverName = getServerNameFromUri ( uri ) ;
287+ if ( ! serverName ) {
288+ throw new Error ( `Could not determine server from URI: ${ uri } ` ) ;
289+ }
290+
291+ const client = mcpClients . get ( serverName ) ;
292+ if ( ! client ) {
293+ throw new Error ( `Server not found: ${ serverName } ` ) ;
294+ }
295+
296+ // Use the MCP SDK to execute the tool
297+ logger . verbose ( `Executing tool: ${ uri } with params:` , toolParams ) ;
298+ const result = await client . tool ( uri , toolParams ) ;
299+ return result ;
183300 }
184301
185302 throw new Error ( `Unknown method: ${ method } ` ) ;
@@ -188,20 +305,36 @@ export function createMcpTool(config: McpConfig): Tool {
188305 logParameters : ( params , { logger } ) => {
189306 if ( params . method === 'listResources' ) {
190307 logger . verbose (
191- `Listing MCP resources${ params . params ?. server ? ` from server: ${ params . params . server } ` : '' } ` ,
308+ `Listing MCP resources${
309+ params . params ?. server ? ` from server: ${ params . params . server } ` : ''
310+ } `,
192311 ) ;
193312 } else if ( params . method === 'getResource' ) {
194313 logger . verbose ( `Fetching MCP resource: ${ params . params . uri } ` ) ;
314+ } else if ( params . method === 'listTools' ) {
315+ logger . verbose (
316+ `Listing MCP tools${
317+ params . params ?. server ? ` from server: ${ params . params . server } ` : ''
318+ } `,
319+ ) ;
320+ } else if ( params . method === 'executeTool' ) {
321+ logger . verbose ( `Executing MCP tool: ${ params . params . uri } ` ) ;
195322 }
196323 } ,
197324
198325 logReturns : ( result , { logger } ) => {
199326 if ( Array . isArray ( result ) ) {
200- logger . verbose ( `Found ${ result . length } MCP resources` ) ;
201- } else {
327+ if ( result . length > 0 && 'description' in result [ 0 ] ) {
328+ logger . verbose ( `Found ${ result . length } MCP tools` ) ;
329+ } else {
330+ logger . verbose ( `Found ${ result . length } MCP resources` ) ;
331+ }
332+ } else if ( typeof result === 'string' ) {
202333 logger . verbose (
203334 `Retrieved MCP resource content (${ result . length } characters)` ,
204335 ) ;
336+ } else {
337+ logger . verbose ( `Executed MCP tool and received result` ) ;
205338 }
206339 } ,
207340 } ;
0 commit comments