WoRMS Marine Taxa MCP Server
Public Hosted Server: https://worms-marine-taxa.caseyjhand.com/mcp
Overview
Marine taxonomy from the World Register of Marine Species (WoRMS). Resolve scientific or common names to AphiaIDs, follow accepted names, and pull classifications, synonyms, distributions, traits, and external identifiers from the keyless WoRMS REST API.
Every AphiaID selector accepts a positive safe integer, a decimal string, or a canonical WoRMS LSID such as urn:lsid:marinespecies.org:taxname:137205; returned AphiaIDs remain numbers. For other LSIDs use worms_crosswalk_id with externalId and type: "lsid", or resolve a scientific name with worms_resolve_taxon.
Tools
Tool | Description |
| Resolve scientific names (exact or fuzzy) or one common name to AphiaIDs, with accepted-name links |
| Fetch full Aphia records by AphiaID, optionally with common names or sources |
| Fetch the root-to-tip classification, optionally with direct children |
| List synonyms of the accepted taxon behind an AphiaID |
| Fetch recorded distributions, filtered by status, establishment means, invasiveness, or occurrence |
| Fetch attribute trees (body size, functional group, conservation listings) with sources and inheritance |
| Map an AphiaID to nine external identifier systems, or reverse an external ID |
| List identifier systems, statuses, environment flags, distribution filter values, ranks, and trait definitions |
Related MCP server: mcp-catalogueoflife
Capability reference
worms_resolve_taxon tool
A nonempty
nameslist (no total-input ceiling, at most 50 per upstream request) or onevernacular, never both.fuzzy: trueopts into TAXAMATCH matching;marineOnlyandextantOnlydefault totruefor names. Vernacular search matches a whole recorded common name, or withvernacularMatch: "contains"every recorded name containing the text (grouperfinds no exact match but many by contains); it applies neither filterEach result keeps its
inputIndex(duplicates included), every match withstatus,validAphiaId, andvalidName, and aguidanceline on a miss; continue withnextInputOffsetandnextMatchOffsetVernacular results page with the upstream
offset(1-based, steps of 50) and the localresultOffset
worms_get_taxon tool
A nonempty
aphiaIdslist with no total-input ceiling, at most 50 fetched per request; continue withnextInputOffsetusing the unchanged list. Unknown IDs stay in position asfound: false; every submitted element is validated before fetchingincludeVernaculars: true(one ID only) adds common names, paged withvernacularOffset; a failed lookup returnsvernacularErrorbeside the recordincludeSources: true(one ID only, not withincludeVernaculars) adds the taxon's sources, such as itsoriginal descriptionandbasis of record, withreference,page,url,link,fulltext, anddoiverbatim. OptionalsourceUse: "original description"filters whole use values ignoring case beforesourceOffsetand the byte budget; blanks omit the filter, populated values stay untrimmed. ContinuenextSourceOffsetwith unchanged options to repeat the full primary record and reconstruct every selected row in orderSuccessful source results report
sourceTotalCountfor the complete selected bibliography andunfilteredSourceCountonly with an effective filter. Notices distinguish no matching use, an empty bibliography, and a past-end offset. A failed lookup returnssourcesErrorbeside the record without counts;sourceUseis inactive withoutincludeSources
worms_get_classification tool
One
aphiaId;ranksis the root-to-tip lineage, withfound: falsewhen WoRMS has noneincludeChildren: trueadds one 50-row page of direct children (offset,marineOnly,extantOnly); a failed children lookup returnschildrenErrorbeside the lineageThe submitted AphiaID keeps its own recorded lineage. A
noticenames its linked accepted AphiaID, or the preferred AphiaID for an accepted alternative representation; a failed status lookup returnsstatusErrorbeside the lineage
worms_get_synonyms tool
One
aphiaId, accepted or not: synonyms are listed for its accepted taxon (validAphiaId), 50 per upstreamoffsetfoundandguidanceseparate a missing taxon from a name with no known accepted ID
worms_get_distributions tool
One
aphiaId; optionalrecordStatus(valid,doubtful,inaccurate),establishmentMeans,invasiveness, andoccurrencefilters combine with AND.recordStatusignores case and surrounding whitespace and echoes its lowercase code; the others match case-insensitive whole values without trimming populated strings, with observed values inworms_list_referencetopicdistribution_terms. Blank filters are omittedReports
unfilteredCountandfilteredCount; rows carry the locality, its MarineRegionslocationId, and status fields in source orderWoRMS attaches records to individual name usages, so by default the tool reads that AphiaID's own records.
includeSynonyms: truecombines the accepted taxon's records with those of its synonyms, 10 synonyms per call, each row taggedsourceAphiaId;synonymUnionreports the window, thenextSynonymOffsetto continue from, and anyfailedSynonymsA
noticenames the linked accepted AphiaID, distinguishing an accepted alternative representation from its preferred AphiaID; withoutincludeSynonyms, a failed status lookup returnsstatusErrorbeside the rows
worms_get_traits tool
One
aphiaId;includeInherited(defaulttrue) adds attributes recorded on higher taxa. On an accepted taxon WoRMS also returns attributes recorded on its synonyms whateverincludeInheritedis set to;inheritedFromnames the source taxon in both casesA
noticenames the linked accepted AphiaID, distinguishing an accepted alternative representation from its preferred AphiaID; a failed status lookup returnsstatusErrorbeside the attributesEvery node keeps
nodeIndex,parentIndex, anddepthfrom the full tree, so units and qualifiers stay attached to their values across pages; values and references are verbatimmeasurementType(case-insensitive whole value, such asBody size) keeps each matching node with its subtree and ancestors, indices unchanged;totalCountcounts that set andunfilteredCountthe whole tree
worms_crosswalk_id tool
Exactly one of
aphiaId(forward) orexternalIdwithtype(reverse). Forward reads onetypeor all nine:algaebase,bold,dyntaxa,fishbase,iucn,lsid,ncbi,tsn,gisdForward returns
idsper type,typeTotals(0 means none recorded), andfailedTypesfor systems that errored; reverse returnsfoundand the full record. IDs stay opaque strings, leading zeros included
worms_list_reference tool
topic:external_id_types,statuses,environment_flags, anddistribution_termsare served offline;ranksandtrait_typesare read livestatusescovers the 28 statuses the WoRMS manual and REST API document, each with a one-line meaning and agroup(accepted,unaccepted,uncertain,technical). A record's status can be the specific reason itself, such asjunior subjective synonym, so test the group rather thanstatus === "unaccepted"; the guide is non-exhaustivedistribution_termslists theestablishmentMeans,invasiveness, andoccurrencevalues observed in WoRMS distributions, for the whole-value filters ofworms_get_distributions; the lists are non-exhaustivePages with
resultOffset; trait definitions keep their tree indices across pages
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
WoRMS-specific:
Exact and TAXAMATCH fuzzy name matching with marine and extant filters; every match and record carries its accepted-name links
One shared request queue: one upstream request at a time, 500 ms between starts, a 45-second tool deadline, and an 8 MiB response ceiling
Per-call retrieval with no cache or bulk harvesting, as the WoRMS webservice guidance asks
Every response carries WoRMS attribution (doi:10.14284/170); credit the WoRMS Editorial Board and keep per-record citations when reusing results (terms)
Agent-friendly output:
Byte-bounded pages: reads return whole items within a 24,000-byte response and name the next offset (
nextResultOffset,nextInputOffset, upstreampage.nextOffset); a full 50-row upstream page reportshasMore: nullrather than guessingUnknown stays unknown: null and absent fields pass through, a null environment flag means not recorded, and empty evidence never claims biological absence
Partial failure: optional lookups (
vernacularError,sourcesError,childrenError,statusError), synonym-unionfailedSynonyms, and crosswalkfailedTypeskeep the data that did arrive, with typed reasons and recovery hints
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http worms-marine-taxa-mcp-server https://worms-marine-taxa.caseyjhand.com/mcpOr run it locally:
claude mcp add worms-marine-taxa-mcp-server -- npx -y @cyanheads/worms-marine-taxa-mcp-serverFor other clients, add this to the MCP config file:
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/worms-marine-taxa-mcp-server"]
}
}
}No API key or account is needed: the WoRMS REST API is public. For Docker or a source build, see Running the server.
Configuration
The server has no variables of its own; these are the common framework settings.
Variable | Description | Default |
| Transport: |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry. |
|
See .env.example for the common framework overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
Clone and install:
git clone https://github.com/cyanheads/worms-marine-taxa-mcp-server.git cd worms-marine-taxa-mcp-server && bun install cp .env.example .envBuild and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdioRun checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Docker
docker run --rm -p 3010:3010 ghcr.io/cyanheads/worms-marine-taxa-mcp-server:latestThe image defaults to HTTP transport, stateless session mode, and logs to /var/log/worms-marine-taxa-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/worms-marine-taxa-mcp-server:latest"]. To build locally, docker build -t worms-marine-taxa-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
| Tool definitions ( |
| WoRMS service: paced transport, normalization, domain schemas, response budgeting, and formatting. |
| Design contract ( |
| Service, tool-contract, and JSON-RPC integration tests. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches; optional lookups report classified failures beside the primary data instead of discarding it
Register new tools in the
createApp()arrays insrc/index.tsInternal imports are relative ESM paths with
.jsextensionsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
WoRMS (World Register of Marine Species) MCP — keyless.
Reference data API for classification systems, real-time world data, and unit conversions
Query STRING interactions, enrichment, annotations, homology, and PPI networks.
Look up genes, sequences, variants, homologs, and cross-database xrefs from Ensembl REST.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides access to FishBase marine biology data including species information, ecological data, distribution records, and morphological details. Enables species name validation and conversion between common and scientific names through natural language queries.8MIT
- AlicenseNot gradedqualityBmaintenanceEnables queries about global taxonomic data, including scientific name matching, classification chains, common names, and synonyms from the Catalogue of Life index.94 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to resolve scientific names to Taxonomic Serial Numbers, traverse complete taxonomic lineages from kingdom to children, and retrieve vernacular names in all languages from an authoritative US-government taxonomy.283 npm1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to resolve marine species names to OBIS taxon records, retrieve georeferenced ocean occurrence records with optional date filtering, and pull aggregate statistics such as record counts, contributing datasets, and observed year ranges. Queries the Ocean Biodiversity Information System keylessly over the Pipeworx gateway or as a local stdio server.326 npmMIT