import { Tool } from '@langchain/core/tools' import { INode, INodeData, INodeOptionsValue, INodeParams } from '../../../../src/Interface' import { MCPToolkit } from '../core' const mcpServerConfig = `{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"] }` class Custom_MCP implements INode { label: string name: string version: number description: string type: string icon: string category: string baseClasses: string[] documentation: string credential: INodeParams inputs: INodeParams[] constructor() { this.label = 'Custom MCP' this.name = 'customMCP' this.version = 1.0 this.type = 'Custom MCP Tool' this.icon = 'customMCP.png' this.category = 'Tools (MCP)' this.description = 'Custom MCP Config' this.documentation = 'https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search' this.inputs = [ { label: 'MCP Server Config', name: 'mcpServerConfig', type: 'code', hideCodeExecute: true, placeholder: mcpServerConfig }, { label: 'Available Actions', name: 'mcpActions', type: 'asyncMultiOptions', loadMethod: 'listActions', refresh: true } ] this.baseClasses = ['Tool'] } //@ts-ignore loadMethods = { listActions: async (nodeData: INodeData): Promise => { try { const toolset = await this.getTools(nodeData) toolset.sort((a: any, b: any) => a.name.localeCompare(b.name)) return toolset.map(({ name, ...rest }) => ({ label: name.toUpperCase(), name: name, description: rest.description || name })) } catch (error) { return [ { label: 'No Available Actions', name: 'error', description: 'No available actions, please check your API key and refresh' } ] } } } async init(nodeData: INodeData): Promise { const tools = await this.getTools(nodeData) const _mcpActions = nodeData.inputs?.mcpActions let mcpActions = [] if (_mcpActions) { try { mcpActions = typeof _mcpActions === 'string' ? JSON.parse(_mcpActions) : _mcpActions } catch (error) { console.error('Error parsing mcp actions:', error) } } return tools.filter((tool: any) => mcpActions.includes(tool.name)) } async getTools(nodeData: INodeData): Promise { const mcpServerConfig = nodeData.inputs?.mcpServerConfig as string if (!mcpServerConfig) { throw new Error('MCP Server Config is required') } try { let serverParams if (typeof mcpServerConfig === 'object') { serverParams = mcpServerConfig } else if (typeof mcpServerConfig === 'string') { const serverParamsString = convertToValidJSONString(mcpServerConfig) serverParams = JSON.parse(serverParamsString) } const toolkit = new MCPToolkit(serverParams, 'stdio') await toolkit.initialize() const tools = toolkit.tools ?? [] return tools as Tool[] } catch (error) { throw new Error(`Invalid MCP Server Config: ${error}`) } } } function convertToValidJSONString(inputString: string) { try { const jsObject = Function('return ' + inputString)() return JSON.stringify(jsObject, null, 2) } catch (error) { console.error('Error converting to JSON:', error) return '' } } module.exports = { nodeClass: Custom_MCP }