Skip to main content
Glama
cyanheads

WoRMS Marine Taxa MCP Server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Overview

Explore the World Register of Marine Species (WoRMS): resolve scientific or common names to AphiaIDs, follow accepted names, and retrieve taxonomic and biological evidence. The public REST API needs no key.

Tools

Tool

Description

worms_resolve_taxon

Resolve exact or fuzzy scientific names, or search a common name

worms_get_taxon

Fetch full Aphia records and optional vernacular names

worms_get_classification

Fetch root-to-tip classification and optional direct children

worms_get_synonyms

Follow the accepted taxon and fetch a synonym page

worms_get_distributions

Fetch recorded distributions with optional local filters

worms_get_traits

Fetch attributes, references, and inheritance evidence

worms_crosswalk_id

Map AphiaIDs to external identifiers, or reverse an external ID

worms_list_reference

Inspect identifier codes, statuses, environment flags, ranks, and trait definitions

Related MCP server: mcp-catalogueoflife

Capability reference

Names, external IDs, and text filters accept up to 512 characters. AphiaIDs are positive safe integers; paged tools use one-based offsets advancing by 50.

Reads return whole items within a 24,000-byte paired-surface response target. Keep the original inputs and options when following zero-based continuation selectors; null means consumed. budgetLimited identifies an early byte cut. One indivisible oversized scientific item is retained intact with oversizedItem: true and requiredBytes, then continuation advances. Values are never clipped. Continuations refetch upstream data, so changes at the source can affect later segments.

worms_resolve_taxon tool

  • Supply either names (up to 500 scientific names) or one vernacular; scientific reads use at most 50-name windows and return original inputIndex positions, preserving duplicates. Resume nextInputOffset and nextMatchOffset as inputOffset and matchOffset against the unchanged names; deferredCount counts unfinished input positions

  • Scientific names match exactly by default; fuzzy: true opts in. marineOnly and extantOnly default to true; inspect every match and its validAphiaId / validName rather than assuming an ambiguous name has one answer

  • Vernacular mode accepts upstream offset (one-based, default 1) and local resultOffset (zero-based, default 0); it cannot apply fuzzy matching or marine/extant filters. Consume nextResultOffset at the same upstream offset before advancing page.nextOffset and resetting resultOffset to zero

  • Full 50-row upstream pages have uncertain continuation: page.nextOffset can lead to an empty page. Local scientific-match continuation exposes all fetched matches; a 50-match scientific group still has unknown upstream completeness


worms_get_taxon tool

  • Up to 500 aphiaIds; read at most 50 from inputOffset and resume nextInputOffset using the original array. inputIndex preserves duplicate and missing positions (found: false, record: null); deferredCount counts unfinished positions

  • includeVernaculars: true requires exactly one submitted ID; follow nextVernacularOffset as vernacularOffset, repeating the full unchanged primary record. An optional lookup failure appears as vernacularError while retaining the record

  • Records preserve citations, accepted-name links, and unknown fields; a null environment flag means unknown, not false


worms_get_classification tool

  • One aphiaId returns root-to-tip ranks segments; found distinguishes absent classification. resultOffset indexes the complete lineage followed by fetched children; follow nextResultOffset with unchanged options

  • includeChildren: true adds one page of direct children, with one-based offset, marineOnly: true, and extantOnly: true defaults; these options are inactive without children

  • Consume local segments at the same upstream offset before advancing page.nextOffset and resetting resultOffset to zero. A full fetched 50-row children page has uncertain continuation; childrenError retains the lineage when optional retrieval fails


worms_get_synonyms tool

  • One aphiaId follows the accepted taxon's validAphiaId before retrieving synonyms; found and guidance distinguish a missing taxon from a name without a known accepted ID

  • One-based offset defaults to 1; consume nextResultOffset as zero-based resultOffset at the same upstream offset before advancing page.nextOffset and resetting resultOffset to zero. A full fetched 50-row page has uncertain continuation


worms_get_distributions tool

  • One aphiaId returns recorded distributions in source order, retaining duplicates; follow nextResultOffset as resultOffset with unchanged filters

  • Optional recordStatus (valid, doubtful, inaccurate), establishmentMeans, invasiveness, and occurrence filters combine by conjunction; status uses exact equality, the others case-insensitive whole-value equality

  • Filtering scans the complete fetched set before pagination. unfilteredCount and filteredCount describe complete local evidence; returnedCount describes this segment. No rows does not establish biological or taxon absence


worms_get_traits tool

  • One aphiaId; includeInherited defaults to true

  • Follow nextResultOffset as resultOffset with unchanged options. Attribute evidence retains values, references, inheritance markers, and complete-tree topology (nodeIndex, parentIndex, depth) in preorder; parents may be on earlier segments

  • Missing traits do not prove biological absence; IUCN list membership is not a Red List threat category


worms_crosswalk_id tool

  • Supply exactly one of aphiaId (forward) or externalId (reverse); reverse requires type, while forward can omit it to query all nine systems

  • Types: algaebase, bold, dyntaxa, fishbase, iucn, lsid, ncbi, tsn, gisd; IDs remain opaque strings, including leading zeros and LSIDs

  • Forward resultOffset indexes whole identifiers across types in request order; follow nextResultOffset with unchanged selectors. ids contains this segment; typeTotals distinguishes successful absence (zero) from IDs on other segments, and omits failedTypes. Reverse returns found and a full record; resultOffset is inactive. No external IDs does not prove taxon absence, and an IUCN ID is not a threat assessment


worms_list_reference tool

  • Required topic: external_id_types, statuses, environment_flags, ranks, or trait_types

  • The first three are available offline; statuses are a non-exhaustive guide. Ranks and trait definitions are retrieved live, with trait-key topology preserved

  • Follow nextResultOffset as resultOffset with the same topic; totalCount is the complete fetched entry count. Tree indices stay global across segments

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:

  • Accepted-name relationships, sparse scientific facts, complete classifications, and trait hierarchy retained

  • Shared conservative pacing: one active upstream request and at least 500 ms between starts; bounded calls rather than register harvesting

  • A 45-second tool deadline and 8 MiB upstream response ceiling fail explicitly instead of clipping scientific data

Agent-friendly output:

  • The same data in structured output and readable text, including effective options, continuation guidance, and attribution

  • Optional enrichment and multi-system crosswalk outages retain useful results with typed errors; required reads fail explicitly

  • Credit the WoRMS Editorial Board (doi:10.14284/170) and preserve per-record citations when reusing results; see WoRMS terms of use

Getting started

Self-Hosted / Local

Add this to your MCP client configuration:

{
  "mcpServers": {
    "worms-marine-taxa-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/worms-marine-taxa-mcp-server@latest"]
    }
  }
}

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"]
    }
  }
}

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, run from the installed repository:

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+ to run the built package

  • No WoRMS account or API key required

Installation

git clone https://github.com/cyanheads/worms-marine-taxa-mcp-server.git
cd worms-marine-taxa-mcp-server
bun install
cp .env.example .env
bun run rebuild

Configuration

No server-specific environment variables are required.

Variable

Description

Default

MCP_TRANSPORT_TYPE

Transport: stdio or http.

stdio

MCP_HTTP_HOST

HTTP bind address.

127.0.0.1

MCP_HTTP_PORT

HTTP server port.

3010

MCP_HTTP_ENDPOINT_PATH

MCP endpoint path.

/mcp

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.

info

LOGS_DIR

Directory for log files (Node.js only).

<app-root>/logs

STORAGE_PROVIDER_TYPE

Framework storage backend.

in-memory

OTEL_ENABLED

Enable OpenTelemetry.

false

See .env.example for common framework overrides.

Running the server

Local development

bun run rebuild
bun run start:stdio
# or
bun run start:http

Run checks and tests:

bun run devcheck
bun run test

Project structure

Directory

Purpose

src/mcp-server/tools/definitions/

Eight read-only tool definitions.

src/services/worms/

WoRMS transport, normalization, schemas, and lossless formatting.

tests/

Service, tool-contract, and JSON-RPC integration tests.

scripts/

Build, validation, documentation, and packaging commands.

See docs/tree.md for the full tree.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches; optional enrichment reports classified failures without discarding primary evidence

  • Register tools in the createApp() arrays in src/index.ts

  • Use relative ESM .js paths for internal source imports; package imports use their package names

  • Validate upstream responses and preserve missing facts, source order, and attribution

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.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Provides 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.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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.
    9 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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.
    8 npm
    MIT