Files
flynn/src/mcp/bridge.ts
T
William Valentin 6090508bad style: auto-fix ESLint issues (curly braces and formatting)
- Add curly braces to all if/else/for/while statements
- Fix indentation and trailing spaces
- Auto-fixed 372 linting errors using eslint --fix
- Remaining issues are warnings only (non-null assertions, explicit any types)
2026-02-11 10:30:24 -08:00

79 lines
2.4 KiB
TypeScript

/**
* MCP Bridge — converts MCP tools into Flynn's Tool interface.
*
* Each MCP tool is prefixed with "mcp:<serverName>:" to avoid
* namespace collisions with builtin tools. When the tool is executed,
* the bridge routes the call back to the originating McpClient.
*/
import type { Tool, ToolResult } from '../tools/types.js';
import type { McpClient } from './client.js';
import type { McpToolInfo } from './types.js';
/**
* Create the prefixed tool name used in Flynn's tool registry.
*
* Example: MCP server "filesystem" with tool "read_file" -> "mcp:filesystem:read_file"
*/
export function mcpToolName(serverName: string, toolName: string): string {
return `mcp:${serverName}:${toolName}`;
}
/**
* Parse a prefixed tool name back into server + tool components.
* Returns null if the name doesn't match the mcp: prefix pattern.
*/
export function parseMcpToolName(prefixedName: string): { serverName: string; toolName: string } | null {
const match = prefixedName.match(/^mcp:([^:]+):(.+)$/);
if (!match) {return null;}
return { serverName: match[1], toolName: match[2] };
}
/**
* Convert a single MCP tool into a Flynn Tool.
*
* The returned Tool's execute() calls back into the McpClient
* to invoke the tool on the remote MCP server.
*/
export function bridgeMcpTool(client: McpClient, toolInfo: McpToolInfo): Tool {
const prefixedName = mcpToolName(client.serverName, toolInfo.name);
return {
name: prefixedName,
description: `[MCP:${client.serverName}] ${toolInfo.description}`,
inputSchema: {
type: 'object',
properties: toolInfo.inputSchema.properties ?? {},
required: toolInfo.inputSchema.required,
},
async execute(args: unknown): Promise<ToolResult> {
try {
const result = await client.callTool(
toolInfo.name,
(args ?? {}) as Record<string, unknown>,
);
return {
success: !result.isError,
output: result.content,
error: result.isError ? result.content : undefined,
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
}
/**
* Bridge all tools from an MCP client into Flynn Tool objects.
*/
export function bridgeAllTools(client: McpClient): Tool[] {
return client.tools.map((t) => bridgeMcpTool(client, t));
}