Resolve WoRMS marine species names; fetch classifications, synonyms, distributions, traits, and IDs.
One address for any MCP client. No sign-in needed on this server.
7 read1 other
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Resolve WoRMS marine species names; fetch classifications, synonyms, distributions, traits, and IDs via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://worms-marine-taxa.caseyjhand.com/mcp
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.
| Tool | Description |
|---|---|
worms_resolve_taxon | Resolve scientific names (exact or fuzzy) or one common name to AphiaIDs, with accepted-name links |
worms_get_taxon | Fetch full Aphia records by AphiaID, optionally with common names or sources |
worms_get_classification | Fetch the root-to-tip classification, optionally with direct children |
worms_get_synonyms | List synonyms of the accepted taxon behind an AphiaID |
worms_get_distributions | Fetch recorded distributions, filtered by status, establishment means, invasiveness, or occurrence |
worms_get_traits | Fetch attribute trees (body size, functional group, conservation listings) with sources and inheritance |
worms_crosswalk_id | Map an AphiaID to nine external identifier systems, or reverse an external ID |
worms_list_reference | List identifier systems, statuses, environment flags, distribution filter values, ranks, and trait definitions |
worms_resolve_taxon toolnames list (no total-input ceiling, at most 50 per upstream request) or one vernacular, never both. fuzzy: true opts into TAXAMATCH matching; marineOnly and extantOnly default to true for names. Vernacular search matches a whole recorded common name, or with vernacularMatch: "contains" every recorded name containing the text (grouper finds no exact match but many by contains); it applies neither filterinputIndex (duplicates included), every match with status, validAphiaId, and validName, and a guidance line on a miss; continue with nextInputOffset and nextMatchOffsetoffset (1-based, steps of 50) and the local resultOffsetworms_get_taxon toolaphiaIds list with no total-input ceiling, at most 50 fetched per request; continue with nextInputOffset using the unchanged list. Unknown IDs stay in position as found: false; every submitted element is validated before fetchingincludeVernaculars: true (one ID only) adds common names, paged with vernacularOffset; a failed lookup returns vernacularError beside the recordincludeSources: true (one ID only, not with includeVernaculars) adds the taxon's sources, such as its original description and basis of record, with reference, page, url, link, fulltext, and doi verbatim. Optional sourceUse: "original description" filters whole use values ignoring case before sourceOffset and the byte budget; blanks omit the filter, populated values stay untrimmed. Continue nextSourceOffset with unchanged options to repeat the full primary record and reconstruct every selected row in ordersourceTotalCount for the complete selected bibliography and unfilteredSourceCount only with an effective filter. Notices distinguish no matching use, an empty bibliography, and a past-end offset. A failed lookup returns sourcesError beside the record without counts; sourceUse is inactive without includeSourcesworms_get_classification toolaphiaId; ranks is the root-to-tip lineage, with found: false when WoRMS has noneincludeChildren: true adds one 50-row page of direct children (offset, marineOnly, extantOnly); a failed children lookup returns childrenError beside the lineagenotice names its linked accepted AphiaID, or the preferred AphiaID for an accepted alternative representation; a failed status lookup returns statusError beside the lineageworms_get_synonyms toolaphiaId, accepted or not: synonyms are listed for its accepted taxon (validAphiaId), 50 per upstream offsetfound and guidance separate a missing taxon from a name with no known accepted IDworms_get_distributions toolaphiaId; optional recordStatus (valid, doubtful, inaccurate), establishmentMeans, invasiveness, and occurrence filters combine with AND. recordStatus ignores case and surrounding whitespace and echoes its lowercase code; the others match case-insensitive whole values without trimming populated strings, with observed values in worms_list_reference topic distribution_terms. Blank filters are omittedunfilteredCount and filteredCount; rows carry the locality, its MarineRegions locationId, and status fields in source orderincludeSynonyms: true combines the accepted taxon's records with those of its synonyms, 10 synonyms per call, each row tagged sourceAphiaId; synonymUnion reports the window, the nextSynonymOffset to continue from, and any failedSynonymsnotice names the linked accepted AphiaID, distinguishing an accepted alternative representation from its preferred AphiaID; without includeSynonyms, a failed status lookup returns statusError beside the rowsworms_get_traits toolaphiaId; includeInherited (default true) adds attributes recorded on higher taxa. On an accepted taxon WoRMS also returns attributes recorded on its synonyms whatever includeInherited is set to; inheritedFrom names the source taxon in both casesnotice names the linked accepted AphiaID, distinguishing an accepted alternative representation from its preferred AphiaID; a failed status lookup returns statusError beside the attributesnodeIndex, parentIndex, and depth from the full tree, so units and qualifiers stay attached to their values across pages; values and references are verbatimmeasurementType (case-insensitive whole value, such as Body size) keeps each matching node with its subtree and ancestors, indices unchanged; totalCount counts that set and unfilteredCount the whole treeworms_crosswalk_id toolaphiaId (forward) or externalId with type (reverse). Forward reads one type or all nine: algaebase, bold, dyntaxa, fishbase, iucn, lsid, ncbi, tsn, gisdids per type, typeTotals (0 means none recorded), and failedTypes for systems that errored; reverse returns found and the full record. IDs stay opaque strings, leading zeros includedworms_list_reference tooltopic: external_id_types, statuses, environment_flags, and distribution_terms are served offline; ranks and trait_types are read livestatuses covers the 28 statuses the WoRMS manual and REST API document, each with a one-line meaning and a group (accepted, unaccepted, uncertain, technical). A record's status can be the specific reason itself, such as junior subjective synonym, so test the group rather than status === "unaccepted"; the guide is non-exhaustivedistribution_terms lists the establishmentMeans, invasiveness, and occurrence values observed in WoRMS distributions, for the whole-value filters of worms_get_distributions; the lists are non-exhaustiveresultOffset; trait definitions keep their tree indices across pagesBuilt 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:
Agent-friendly output:
nextResultOffset, nextInputOffset, upstream page.nextOffset); a full 50-row upstream page reports hasMore: null rather than guessingvernacularError, sourcesError, childrenError, statusError), synonym-union failedSynonyms, and crosswalk failedTypes keep the data that did arrive, with typed reasons and recovery hintsA public instance is available at https://worms-marine-taxa.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own configuration shape.
For Claude Code:
claude mcp add --transport http worms-marine-taxa-mcp-server https://worms-marine-taxa.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"type": "streamableHttp",
"url": "https://worms-marine-taxa.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"url": "https://worms-marine-taxa.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Add the following to your MCP client configuration file.
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/worms-marine-taxa-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/worms-marine-taxa-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"worms-marine-taxa-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/worms-marine-taxa-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/worms-marine-taxa-mcp-server.git
cd worms-marine-taxa-mcp-server
bun install
cp .env.example .env
The server has no variables of its own; these are the common framework settings.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the common framework overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
| Directory | Purpose |
|---|---|
src/mcp-server/tools/definitions | Tool definitions (*.tool.ts). Eight read-only tools. |
src/services/worms | WoRMS service: paced transport, normalization, domain schemas, response budgeting, and formatting. |
docs/ | Design contract (design.md) and the generated directory tree. |
tests/ | Service, tool-contract, and JSON-RPC integration tests. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
createApp() arrays in src/index.ts.js extensionsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.