Skip to main content
Glama

ITIS MCP Server

by knustx
tools.ts19.2 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from '@modelcontextprotocol/sdk/types.js'; import { ITISClient, processVernacularNames } from './itis-client.js'; // Define the tools export const tools: Tool[] = [ { name: 'search_itis', description: 'Search ITIS database using SOLR queries. Supports general search with flexible query parameters.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'SOLR query string (e.g., "nameWInd:Homo*", "kingdom:Plantae", or "*:*" for all)', }, start: { type: 'number', description: 'Starting index for pagination (default: 0)', }, rows: { type: 'number', description: 'Number of results to return (default: 10, max: 100)', }, sort: { type: 'string', description: 'Sort order (e.g., "nameWInd asc", "tsn desc")', }, fields: { type: 'array', items: { type: 'string' }, description: 'Specific fields to return (default: all available fields)', }, filters: { type: 'object', additionalProperties: { type: 'string' }, description: 'Additional filters as key-value pairs (e.g., {"kingdom": "Animalia", "rank": "Species"})', }, }, }, }, { name: 'search_by_scientific_name', description: 'Search for organisms by their scientific name in ITIS database.', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Scientific name to search for (e.g., "Homo sapiens", "Quercus")', }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, start: { type: 'number', description: 'Starting index for pagination (default: 0)', }, }, required: ['name'], }, }, { name: 'search_by_tsn', description: 'Search for organisms by their Taxonomic Serial Number (TSN) in ITIS database.', inputSchema: { type: 'object', properties: { tsn: { type: 'string', description: 'Taxonomic Serial Number (TSN) to search for', }, }, required: ['tsn'], }, }, { name: 'search_by_kingdom', description: 'Search for organisms within a specific kingdom in ITIS database.', inputSchema: { type: 'object', properties: { kingdom: { type: 'string', description: 'Kingdom name (e.g., "Animalia", "Plantae", "Fungi", "Bacteria")', }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, start: { type: 'number', description: 'Starting index for pagination (default: 0)', }, }, required: ['kingdom'], }, }, { name: 'search_by_rank', description: 'Search for organisms by their taxonomic rank in ITIS database.', inputSchema: { type: 'object', properties: { rank: { type: 'string', description: 'Taxonomic rank (e.g., "Species", "Genus", "Family", "Order", "Class", "Phylum", "Kingdom")', }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, start: { type: 'number', description: 'Starting index for pagination (default: 0)', }, }, required: ['rank'], }, }, { name: 'get_hierarchy', description: 'Get the complete taxonomic hierarchy for a given TSN.', inputSchema: { type: 'object', properties: { tsn: { type: 'string', description: 'Taxonomic Serial Number (TSN) to get hierarchy for', }, }, required: ['tsn'], }, }, { name: 'autocomplete_search', description: 'Search for organisms with autocomplete functionality using partial names.', inputSchema: { type: 'object', properties: { partialName: { type: 'string', description: 'Partial scientific name for autocomplete (e.g., "Homo", "Quer")', }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, }, required: ['partialName'], }, }, { name: 'get_statistics', description: 'Get basic statistics about the ITIS database (total number of records).', inputSchema: { type: 'object', properties: {}, }, }, { name: 'search_by_vernacular_name', description: 'Search for organisms by their common/vernacular names in ITIS database.', inputSchema: { type: 'object', properties: { vernacularName: { type: 'string', description: 'Common/vernacular name to search for (e.g., "human", "dog", "oak tree")', }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, start: { type: 'number', description: 'Starting index for pagination (default: 0)', }, }, required: ['vernacularName'], }, }, { name: 'explore_taxonomy', description: 'Explore taxonomic relationships by finding related organisms at different taxonomic levels.', inputSchema: { type: 'object', properties: { scientificName: { type: 'string', description: 'Scientific name to explore (e.g., "Homo sapiens")', }, level: { type: 'string', description: 'Taxonomic level to explore: "siblings" (same genus), "family" (same family), "order" (same order), "class" (same class)', enum: ['siblings', 'family', 'order', 'class'] }, rows: { type: 'number', description: 'Number of results to return (default: 10)', }, }, required: ['scientificName', 'level'], }, }, { name: 'get_random_species', description: 'Get random species from ITIS database with optional taxonomic filters.', inputSchema: { type: 'object', properties: { kingdom: { type: 'string', description: 'Kingdom filter (e.g., "Animalia", "Plantae", "Fungi")', }, phylum: { type: 'string', description: 'Phylum filter (e.g., "Chordata", "Arthropoda")', }, class: { type: 'string', description: 'Class filter (e.g., "Mammalia", "Aves", "Reptilia")', }, order: { type: 'string', description: 'Order filter (e.g., "Carnivora", "Primates")', }, family: { type: 'string', description: 'Family filter (e.g., "Felidae", "Canidae")', }, genus: { type: 'string', description: 'Genus filter (e.g., "Panthera", "Canis")', }, count: { type: 'number', description: 'Number of random species to return (default: 1, max: 10)', }, requireVernacular: { type: 'boolean', description: 'Only return species that have common names (default: false)', }, vernacularLanguage: { type: 'string', description: 'Language for vernacular names (default: "English"). Other options: "French", "Spanish", etc.', }, }, }, }, ]; export function setupToolHandlers(server: Server, itisClient: ITISClient) { // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools, }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'search_itis': { const result = await itisClient.search(args as any); return { content: [ { type: 'text', text: JSON.stringify({ totalResults: result.response.numFound, start: result.response.start, results: result.response.docs, }, null, 2), }, ], }; } case 'search_by_scientific_name': { const { name, rows, start } = args as any; const result = await itisClient.searchByScientificName(name, { rows, start }); return { content: [ { type: 'text', text: JSON.stringify({ searchTerm: name, totalResults: result.response.numFound, start: result.response.start, results: result.response.docs, }, null, 2), }, ], }; } case 'search_by_tsn': { const { tsn } = args as any; const result = await itisClient.searchByTSN(tsn); return { content: [ { type: 'text', text: JSON.stringify({ tsn, totalResults: result.response.numFound, results: result.response.docs, }, null, 2), }, ], }; } case 'search_by_kingdom': { const { kingdom, rows, start } = args as any; const result = await itisClient.searchByKingdom(kingdom, { rows, start }); return { content: [ { type: 'text', text: JSON.stringify({ kingdom, totalResults: result.response.numFound, start: result.response.start, results: result.response.docs, }, null, 2), }, ], }; } case 'search_by_rank': { const { rank, rows, start } = args as any; const result = await itisClient.searchByTaxonomicRank(rank, { rows, start }); return { content: [ { type: 'text', text: JSON.stringify({ rank, totalResults: result.response.numFound, start: result.response.start, results: result.response.docs, }, null, 2), }, ], }; } case 'get_hierarchy': { const { tsn } = args as any; const result = await itisClient.getHierarchy(tsn); return { content: [ { type: 'text', text: JSON.stringify({ tsn, hierarchy: result.response.docs, }, null, 2), }, ], }; } case 'autocomplete_search': { const { partialName, rows } = args as any; const result = await itisClient.searchWithAutocomplete(partialName, { rows }); return { content: [ { type: 'text', text: JSON.stringify({ partialName, totalResults: result.response.numFound, suggestions: result.response.docs.map((doc: any) => ({ tsn: doc.tsn, name: doc.nameWInd, kingdom: doc.kingdom, rank: doc.rank, })), }, null, 2), }, ], }; } case 'get_statistics': { const result = await itisClient.getStatistics(); return { content: [ { type: 'text', text: JSON.stringify({ totalRecords: result.response.numFound, lastUpdated: new Date().toISOString(), }, null, 2), }, ], }; } case 'search_by_vernacular_name': { const { vernacularName, rows, start } = args as any; const result = await itisClient.searchByVernacularName(vernacularName, { rows, start }); return { content: [ { type: 'text', text: JSON.stringify({ searchTerm: vernacularName, searchType: 'vernacular/common name', totalResults: result.response.numFound, start: result.response.start, results: result.response.docs.map((doc: any) => ({ tsn: doc.tsn, scientificName: doc.nameWInd, kingdom: doc.kingdom, rank: doc.rank, commonNames: processVernacularNames(doc.vernacular, 'English'), usage: doc.usage, })), }, null, 2), }, ], }; } case 'explore_taxonomy': { const { scientificName, level, rows } = args as any; // First, get the target organism's details const targetResult = await itisClient.searchByScientificName(scientificName); if (targetResult.response.numFound === 0) { return { content: [ { type: 'text', text: JSON.stringify({ error: `No organism found with scientific name: ${scientificName}`, }, null, 2), }, ], }; } const target = targetResult.response.docs[0]; let searchQuery = ''; let description = ''; switch (level) { case 'siblings': if (target.unit1) { searchQuery = `unit1:"${target.unit1}" AND rank:Species`; description = `Other species in genus ${target.unit1}`; } break; case 'family': if (target.hierarchySoFarWRanks && target.hierarchySoFarWRanks[0]) { const hierarchy = target.hierarchySoFarWRanks[0]; const familyMatch = hierarchy.match(/Family:([^$]+)/); if (familyMatch) { const family = familyMatch[1]; searchQuery = `hierarchySoFarWRanks:*Family\\:${family}* AND rank:Species`; description = `Other species in family ${family}`; } } break; case 'order': if (target.hierarchySoFarWRanks && target.hierarchySoFarWRanks[0]) { const hierarchy = target.hierarchySoFarWRanks[0]; const orderMatch = hierarchy.match(/Order:([^$]+)/); if (orderMatch) { const order = orderMatch[1]; searchQuery = `hierarchySoFarWRanks:*Order\\:${order}* AND rank:Species`; description = `Other species in order ${order}`; } } break; case 'class': if (target.hierarchySoFarWRanks && target.hierarchySoFarWRanks[0]) { const hierarchy = target.hierarchySoFarWRanks[0]; const classMatch = hierarchy.match(/Class:([^$]+)/); if (classMatch) { const cls = classMatch[1]; searchQuery = `hierarchySoFarWRanks:*Class\\:${cls}* AND rank:Species`; description = `Other species in class ${cls}`; } } break; } if (!searchQuery) { return { content: [ { type: 'text', text: JSON.stringify({ error: `Unable to find taxonomic information for level: ${level}`, target: target, }, null, 2), }, ], }; } const relatedResult = await itisClient.search({ query: searchQuery, rows: rows || 10, sort: 'nameWInd asc' }); return { content: [ { type: 'text', text: JSON.stringify({ target: { name: target.nameWInd, tsn: target.tsn, rank: target.rank, }, exploration: { level: level, description: description, totalResults: relatedResult.response.numFound, results: relatedResult.response.docs.map((doc: any) => ({ tsn: doc.tsn, name: doc.nameWInd, kingdom: doc.kingdom, rank: doc.rank, commonNames: processVernacularNames(doc.vernacular, 'English'), usage: doc.usage, })), }, }, null, 2), }, ], }; } case 'get_random_species': { const args = request.params.arguments as any; const { count = 1, requireVernacular = false, vernacularLanguage = 'English', ...filters } = args; // Limit count to reasonable maximum const limitedCount = Math.min(count, 10); const result = await itisClient.getRandomSpecies({ ...filters, count: limitedCount, requireVernacular, vernacularLanguage }); return { content: [ { type: 'text', text: JSON.stringify({ searchType: 'random species', filters: filters, requireVernacular, vernacularLanguage, totalPossible: result.response.numFound, results: result.response.docs.map((doc: any) => ({ tsn: doc.tsn, scientificName: doc.nameWInd, kingdom: doc.kingdom, rank: doc.rank, commonNames: processVernacularNames(doc.vernacular, vernacularLanguage), hierarchy: doc.hierarchySoFarWRanks?.[0] || '', usage: doc.usage, })), }, null, 2), }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); }

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/knustx/itis-mcp-server'

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