Flowise/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts

130 lines
4.0 KiB
TypeScript

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<INodeOptionsValue[]> => {
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<any> {
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<Tool[]> {
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 }