About worms-marine-taxa-mcp-server
An MCP server that provides access to marine taxonomy data from the World Register of Marine Species (WoRMS). Researchers and developers can resolve names and retrieve classifications, synonyms, distributions, traits, and external identifiers.
Key features
- 01Resolve scientific and common names
- 02Retrieve taxon records and classifications
- 03Look up synonyms and distributions
- 04Fetch traits and external identifiers
- 05Filter results and page through records
Use cases
- 01Resolve a marine species name to an AphiaID
- 02Review a taxon's lineage and synonyms
- 03Check recorded distributions and traits
- 04Map AphiaIDs to external identifiers
MCP support
Exposes eight tools to MCP clients over STDIO or Streamable HTTP, using the public WoRMS REST API to resolve taxa and retrieve related data.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://worms-marine-taxa.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-worms-marine-taxa https://worms-marine-taxa.caseyjhand.com/mcp{"mcpServers":{"cyanheads-worms-marine-taxa":{"type":"http","url":"https://worms-marine-taxa.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-worms-marine-taxa":{"type":"http","url":"https://worms-marine-taxa.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-worms-marine-taxa":{"type":"http","url":"https://worms-marine-taxa.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-worms-marine-taxa":{"serverUrl":"https://worms-marine-taxa.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
8| Parameter | Type | Required | Description |
|---|---|---|---|
| topic | enum | Yes | Reference topic: external_id_types, statuses, environment_flags, distribution_terms, ranks, or trait_types.external_id_types | statuses | environment_flags | distribution_terms | ranks | trait_types |
| resultOffset | integer | No | Zero-based local position; resubmit unchanged selectors and options. |
Details
From the project README@cyanheads/worms-marine-taxa-mcp-server
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
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 |
|---|---|
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 |
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 filter - Each result keeps its
inputIndex(duplicates included), every match withstatus,validAphiaId, andvalidName, and aguidanceline on a miss; continue withnextInputOffsetandnextMatchOffset - Vernacular 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 fetching includeVernaculars: 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 order- Successful 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 none includeChildren: trueadds one 50-row page of direct children (offset,marineOnly,extantOnly); a failed children lookup returnschildrenErrorbeside the lineage- The 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 upstreamoffset foundandguidanceseparate 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 omitted - Reports
unfilteredCountandfilteredCount; rows carry the locality, its MarineRegionslocationId, and status fields in source order - WoRMS 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 anyfailedSynonyms - A
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 cases - A
noticenames the linked accepted AphiaID, distinguishing an accepted alternative representation from its preferred AphiaID; a failed status lookup returnsstatusErrorbeside the attributes - Every node keeps
nodeIndex,parentIndex, anddepthfrom the full tree, so units and qualifiers stay attached to their values across pages; values and references are verbatim measurementType(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,gisd - Forward 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-exhaustive- Pages 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 guessing - Unknown 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
Public Hosted Instance
A 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.
Self-Hosted / Local
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
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key or account: the WoRMS REST API is public.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/worms-marine-taxa-mcp-server.git
- Navigate into the directory:
cd worms-marine-taxa-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
Configuration
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.
Running the server
Local development
-
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
Project structure
| 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. |
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.ts - Internal imports are relative ESM paths with
.jsextensions - Wrap 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 test
License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.