Skip to main content
Glama
FishBase.node.ts10.2 kB
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, NodeOperationError, } from 'n8n-workflow'; export class FishBase implements INodeType { description: INodeTypeDescription = { displayName: 'FishBase', name: 'fishBase', icon: 'file:fishbase.svg', group: ['data'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Access FishBase marine biology data', defaults: { name: 'FishBase', }, inputs: ['main'], outputs: ['main'], credentials: [], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Species', value: 'species', }, { name: 'Ecology', value: 'ecology', }, { name: 'Distribution', value: 'distribution', }, { name: 'Morphology', value: 'morphology', }, { name: 'Common Names', value: 'commonNames', }, ], default: 'species', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['species'], }, }, options: [ { name: 'Get Species Info', value: 'getSpecies', action: 'Get species information', }, { name: 'Search Species', value: 'searchSpecies', action: 'Search for species', }, { name: 'Validate Name', value: 'validateName', action: 'Validate species name', }, ], default: 'getSpecies', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['ecology'], }, }, options: [ { name: 'Get Ecology Data', value: 'getEcology', action: 'Get ecological information', }, ], default: 'getEcology', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['distribution'], }, }, options: [ { name: 'Get Distribution', value: 'getDistribution', action: 'Get distribution data', }, ], default: 'getDistribution', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['morphology'], }, }, options: [ { name: 'Get Morphology', value: 'getMorphology', action: 'Get morphological data', }, ], default: 'getMorphology', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['commonNames'], }, }, options: [ { name: 'Common to Scientific', value: 'commonToScientific', action: 'Convert common name to scientific', }, ], default: 'commonToScientific', }, { displayName: 'Species Name', name: 'speciesName', type: 'string', displayOptions: { show: { operation: ['getSpecies', 'getEcology', 'getDistribution', 'getMorphology', 'validateName'], }, }, default: '', placeholder: 'e.g., Salmo trutta', description: 'Scientific name of the species (Genus species)', required: true, }, { displayName: 'Search Query', name: 'searchQuery', type: 'string', displayOptions: { show: { operation: ['searchSpecies'], }, }, default: '', placeholder: 'e.g., trout or Salmo', description: 'Search term for species (scientific or common name)', required: true, }, { displayName: 'Common Name', name: 'commonName', type: 'string', displayOptions: { show: { operation: ['commonToScientific'], }, }, default: '', placeholder: 'e.g., Brown trout', description: 'Common name of the fish', required: true, }, { displayName: 'Limit', name: 'limit', type: 'number', displayOptions: { show: { operation: ['searchSpecies'], }, }, default: 20, description: 'Maximum number of results to return', }, { displayName: 'Fields', name: 'fields', type: 'string', displayOptions: { show: { operation: ['getSpecies'], }, }, default: '', placeholder: 'Genus,Species,FBname,Length', description: 'Comma-separated list of fields to return (optional)', }, ], }; async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; for (let i = 0; i < items.length; i++) { try { const resource = this.getNodeParameter('resource', i) as string; const operation = this.getNodeParameter('operation', i) as string; let responseData: any; if (resource === 'species') { if (operation === 'getSpecies') { const speciesName = this.getNodeParameter('speciesName', i) as string; const fieldsParam = this.getNodeParameter('fields', i) as string; const fields = fieldsParam ? fieldsParam.split(',').map(f => f.trim()) : undefined; responseData = await this.callMCPTool('get_species', { species_name: speciesName, fields, }); } else if (operation === 'searchSpecies') { const searchQuery = this.getNodeParameter('searchQuery', i) as string; const limit = this.getNodeParameter('limit', i) as number; responseData = await this.callMCPTool('search_species', { query: searchQuery, limit, }); } else if (operation === 'validateName') { const speciesName = this.getNodeParameter('speciesName', i) as string; responseData = await this.callMCPTool('validate_species_name', { species_name: speciesName, }); } } else if (resource === 'ecology') { const speciesName = this.getNodeParameter('speciesName', i) as string; responseData = await this.callMCPTool('get_ecology', { species_name: speciesName, }); } else if (resource === 'distribution') { const speciesName = this.getNodeParameter('speciesName', i) as string; responseData = await this.callMCPTool('get_distribution', { species_name: speciesName, }); } else if (resource === 'morphology') { const speciesName = this.getNodeParameter('speciesName', i) as string; responseData = await this.callMCPTool('get_morphology', { species_name: speciesName, }); } else if (resource === 'commonNames') { const commonName = this.getNodeParameter('commonName', i) as string; responseData = await this.callMCPTool('common_to_scientific', { common_name: commonName, }); } const executionData = this.helpers.constructExecutionMetaData( [{ json: responseData }], { itemData: { item: i } } ); returnData.push(...executionData); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message, }, pairedItem: { item: i, }, }); continue; } throw error; } } return [returnData]; } private async callMCPTool(toolName: string, args: any): Promise<any> { try { const { spawn } = await import('child_process'); return new Promise((resolve, reject) => { const mcpProcess = spawn('node', ['/Users/lundgren/Documents/repo/fishing/mcp_fishbase/dist/index.js'], { stdio: ['pipe', 'pipe', 'pipe'], }); let stdout = ''; let stderr = ''; mcpProcess.stdout.on('data', (data) => { stdout += data.toString(); }); mcpProcess.stderr.on('data', (data) => { stderr += data.toString(); }); mcpProcess.on('close', (code) => { if (code !== 0) { reject(new Error(`MCP process exited with code ${code}: ${stderr}`)); return; } try { const response = JSON.parse(stdout); resolve(response); } catch (parseError) { reject(new Error(`Failed to parse MCP response: ${parseError}`)); } }); const request = { jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: toolName, arguments: args, }, }; mcpProcess.stdin.write(JSON.stringify(request) + '\n'); mcpProcess.stdin.end(); }); } catch (error) { throw new NodeOperationError( this.getNode(), `Failed to call MCP tool ${toolName}: ${error.message}` ); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lundgrenalex/mcp-fishbase'

If you have feedback or need assistance with the MCP directory API, please join our Discord server