worms-marine-taxa-mcp-server

v0.1.2 pre-1.0

Resolve WoRMS marine species names; fetch classifications, synonyms, distributions, traits, and IDs via MCP. STDIO or Streamable HTTP.

worms-marine-taxa.caseyjhand.com/mcp
claude mcp add --transport http worms-marine-taxa-mcp-server https://worms-marine-taxa.caseyjhand.com/mcp
codex mcp add worms-marine-taxa-mcp-server --url https://worms-marine-taxa.caseyjhand.com/mcp
{
  "mcpServers": {
    "worms-marine-taxa-mcp-server": {
      "url": "https://worms-marine-taxa.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http worms-marine-taxa-mcp-server https://worms-marine-taxa.caseyjhand.com/mcp
{
  "mcpServers": {
    "worms-marine-taxa-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://worms-marine-taxa.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "worms-marine-taxa-mcp-server": {
      "type": "http",
      "url": "https://worms-marine-taxa.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://worms-marine-taxa.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

8

worms_list_reference

open-world

List supported external identifier systems, a non-exhaustive taxonomic-status guide grouped as accepted, unaccepted, uncertain, or technical, environment-flag semantics, observed worms_get_distributions filter values, live taxonomic ranks, or live trait definitions. Resume nextResultOffset as resultOffset with the same topic. Identifier codes, statuses, environment flags, and distribution terms are available offline. A record status can be the specific reason itself, such as junior subjective synonym, rather than unaccepted. IUCN identifiers are not threat categories; null flags mean not recorded. Trait definitions retain complete-tree preorder indices across pages; parents may be on earlier pages.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_list_reference",
    "arguments": {
      "topic": "<topic>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "resultOffset": {
      "default": 0,
      "description": "Zero-based local position; resubmit unchanged selectors and options.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "topic": {
      "type": "string",
      "enum": [
        "external_id_types",
        "statuses",
        "environment_flags",
        "distribution_terms",
        "ranks",
        "trait_types"
      ],
      "description": "Reference topic: external_id_types, statuses, environment_flags, distribution_terms, ranks, or trait_types."
    }
  },
  "required": [
    "resultOffset",
    "topic"
  ],
  "additionalProperties": false
}
view source ↗

worms_resolve_taxon

open-world

Resolve exact or explicitly fuzzy scientific names, or search one vernacular name as a whole recorded common name or, with vernacularMatch: "contains", as part of one. Names default to marine and extant taxa; vernacular cannot filter. Resume scientific segments with nextInputOffset and nextMatchOffset against unchanged names and options; inputIndex preserves duplicates and partialGroup identifies split groups. For vernacular, consume nextResultOffset within the same upstream offset before advancing page.nextOffset and resetting resultOffset to zero. Full 50-match upstream groups remain completeness-unknown; accepted-name fields do not choose an ambiguous match.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_resolve_taxon",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "inputOffset": {
      "default": 0,
      "description": "Zero-based original scientific names position; inactive for vernacular.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "matchOffset": {
      "default": 0,
      "description": "Zero-based match within the scientific-name group at inputOffset; inactive for vernacular.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "resultOffset": {
      "default": 0,
      "description": "Zero-based match within the fetched vernacular page; keep upstream offset until consumed. Inactive for scientific names.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "names": {
      "description": "Original scientific names; resubmit unchanged with continuation offsets, preserving duplicates.",
      "minItems": 1,
      "maxItems": 500,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512,
        "description": "Nonempty name, at most 512 characters."
      }
    },
    "vernacular": {
      "description": "Common name, mutually exclusive with names; blank means unset.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "vernacularMatch": {
      "description": "Vernacular only: exact matches a whole recorded common name; contains matches every recorded common name containing the text, such as grouper in Nassau grouper. Names accept only exact; blank means exact.",
      "default": "exact",
      "type": "string",
      "enum": [
        "exact",
        "contains"
      ]
    },
    "fuzzy": {
      "default": false,
      "description": "Explicit fuzzy scientific-name matching; unavailable for vernacular.",
      "type": "boolean"
    },
    "marineOnly": {
      "default": true,
      "description": "Filter scientific names to marine taxa; vernacular cannot filter and rejects false.",
      "type": "boolean"
    },
    "extantOnly": {
      "default": true,
      "description": "Filter scientific names to extant taxa; vernacular cannot filter and rejects false.",
      "type": "boolean"
    },
    "offset": {
      "default": 1,
      "description": "Vernacular only: one-based upstream starting record, advancing by 50; default 1. Scientific names accept only 1.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740941
    }
  },
  "required": [
    "inputOffset",
    "matchOffset",
    "resultOffset",
    "vernacularMatch",
    "fuzzy",
    "marineOnly",
    "extantOnly",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

worms_get_taxon

open-world

Retrieve full Aphia records by IDs from worms_resolve_taxon in byte-budgeted segments. Resume nextInputOffset as inputOffset using unchanged aphiaIds and options; inputIndex preserves duplicate and missing positions. includeVernaculars (common names) or includeSources (original description, basis of record, and other sources) requires one submitted ID, one of the two per call; resume nextVernacularOffset as vernacularOffset or nextSourceOffset as sourceOffset, repeating the full primary record. Optional failure retains that record; unknown facts remain omitted or null.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_get_taxon",
    "arguments": {
      "aphiaIds": "<aphiaIds>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "inputOffset": {
      "default": 0,
      "description": "Zero-based local position; resubmit unchanged selectors and options.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "vernacularOffset": {
      "default": 0,
      "description": "Zero-based common-name position for the singleton ID; repeat unchanged options. Inactive without includeVernaculars.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "sourceOffset": {
      "default": 0,
      "description": "Zero-based source position for the singleton ID; repeat unchanged options. Inactive without includeSources.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "aphiaIds": {
      "minItems": 1,
      "maxItems": 500,
      "type": "array",
      "items": {
        "type": "integer",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991,
        "description": "Positive safe-integer AphiaID; obtain from worms_resolve_taxon."
      },
      "description": "Original AphiaIDs in order; resubmit unchanged with inputOffset, without deduplicating."
    },
    "includeVernaculars": {
      "default": false,
      "description": "Retrieve common names; requires exactly one submitted ID.",
      "type": "boolean"
    },
    "includeSources": {
      "default": false,
      "description": "Retrieve the taxon sources, such as its original description and basis of record; requires exactly one submitted ID and cannot combine with includeVernaculars.",
      "type": "boolean"
    }
  },
  "required": [
    "inputOffset",
    "vernacularOffset",
    "sourceOffset",
    "aphiaIds",
    "includeVernaculars",
    "includeSources"
  ],
  "additionalProperties": false
}
view source ↗

worms_get_classification

open-world

Retrieve root-to-tip classification and optional direct children for an AphiaID from worms_resolve_taxon. resultOffset indexes lineage followed by fetched children; consume nextResultOffset with unchanged options and upstream offset before advancing page.nextOffset and resetting resultOffset to zero. Missing ranks remain unknown; child offset and filters are inactive without includeChildren. A full fetched 50-row child page has uncertain continuation and can lead to an empty page. An AphiaID that is not the accepted name keeps its own recorded lineage, and a notice names the accepted AphiaID.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_get_classification",
    "arguments": {
      "aphiaId": "<aphiaId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "resultOffset": {
      "default": 0,
      "description": "Zero-based position in lineage followed by fetched children; keep upstream offset unchanged until nextResultOffset is null.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "aphiaId": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Positive safe-integer AphiaID; obtain from worms_resolve_taxon."
    },
    "includeChildren": {
      "default": false,
      "description": "Also fetch one page of direct children.",
      "type": "boolean"
    },
    "offset": {
      "default": 1,
      "description": "One-based starting record, advancing by 50; default 1.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740941
    },
    "marineOnly": {
      "default": true,
      "description": "Marine children only; inactive without includeChildren.",
      "type": "boolean"
    },
    "extantOnly": {
      "default": true,
      "description": "Extant children only; inactive without includeChildren.",
      "type": "boolean"
    }
  },
  "required": [
    "resultOffset",
    "aphiaId",
    "includeChildren",
    "offset",
    "marineOnly",
    "extantOnly"
  ],
  "additionalProperties": false
}
view source ↗

worms_get_synonyms

open-world

Retrieve synonyms for the accepted taxon linked from an AphiaID obtained with worms_resolve_taxon. Consume nextResultOffset within the same upstream offset before advancing page.nextOffset and resetting resultOffset to zero. A present name without an accepted ID has no synonym lookup; inspect it with worms_get_taxon. A full fetched 50-row page has uncertain continuation and may lead to an empty page.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_get_synonyms",
    "arguments": {
      "aphiaId": "<aphiaId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "aphiaId": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Positive safe-integer AphiaID; obtain from worms_resolve_taxon."
    },
    "offset": {
      "default": 1,
      "description": "One-based starting record, advancing by 50; default 1.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740941
    },
    "resultOffset": {
      "default": 0,
      "description": "Zero-based local position; resubmit unchanged selectors and options.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "aphiaId",
    "offset",
    "resultOffset"
  ],
  "additionalProperties": false
}
view source ↗

worms_get_distributions

open-world

Retrieve recorded distributions for an AphiaID from worms_resolve_taxon in byte-budgeted segments; resume nextResultOffset as resultOffset with unchanged selectors and filters. WoRMS attaches records to individual name usages, so one AphiaID's rows can miss those of its synonyms: includeSynonyms combines the accepted taxon's rows with those of up to 10 synonyms per call, each row tagged sourceAphiaId; consume nextResultOffset before advancing synonymOffset to synonymUnion.nextSynonymOffset with resultOffset 0. Filters apply to the complete fetched set before pagination and combine by conjunction: recordStatus is exact, others use case-insensitive whole-value equality. Rows retain duplicates and source order; no rows does not prove biological or taxon absence. A notice flags an AphiaID that is not the accepted name.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_get_distributions",
    "arguments": {
      "aphiaId": "<aphiaId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "recordStatus": {
      "description": "Exact record status; blank means no filter.",
      "type": "string",
      "enum": [
        "valid",
        "doubtful",
        "inaccurate"
      ]
    },
    "establishmentMeans": {
      "description": "Case-insensitive whole-value establishment filter, such as Alien; blank omitted. Observed values: worms_list_reference topic: distribution_terms.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "invasiveness": {
      "description": "Case-insensitive whole-value invasiveness filter, such as Invasive; blank omitted. Observed values: worms_list_reference topic: distribution_terms.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "occurrence": {
      "description": "Case-insensitive whole-value occurrence filter, such as Established; blank omitted. Observed values: worms_list_reference topic: distribution_terms.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "aphiaId": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Positive safe-integer AphiaID; obtain from worms_resolve_taxon."
    },
    "resultOffset": {
      "default": 0,
      "description": "Zero-based local position; resubmit unchanged selectors and options.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "includeSynonyms": {
      "default": false,
      "description": "Combine the accepted taxon's records with its synonyms', 10 synonyms per call; rows then carry sourceAphiaId.",
      "type": "boolean"
    },
    "synonymOffset": {
      "default": 0,
      "description": "Zero-based synonym position; once nextResultOffset is null, resubmit synonymUnion.nextSynonymOffset here with resultOffset 0. Inactive without includeSynonyms.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "aphiaId",
    "resultOffset",
    "includeSynonyms",
    "synonymOffset"
  ],
  "additionalProperties": false
}
view source ↗

worms_get_traits

open-world

Retrieve recorded attributes for an AphiaID from worms_resolve_taxon, including inherited attributes by default. Resume nextResultOffset as resultOffset with unchanged selectors and options. Whole rows retain original preorder nodeIndex and parentIndex across pages; parents may be on earlier pages. measurementType keeps each matching node with its subtree and ancestors, indices unchanged; totalCount counts that set and unfilteredCount the whole tree. Values, references and inheritance markers remain unchanged; on an accepted taxon WoRMS also returns attributes recorded on its synonyms whatever includeInherited is set to, marked by inheritedFrom. A notice flags an AphiaID that is not the accepted name. Missing traits do not prove biological absence; IUCN list membership is not a threat category.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_get_traits",
    "arguments": {
      "aphiaId": "<aphiaId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "resultOffset": {
      "default": 0,
      "description": "Zero-based local position; resubmit unchanged selectors and options.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "aphiaId": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Positive safe-integer AphiaID; obtain from worms_resolve_taxon."
    },
    "includeInherited": {
      "default": true,
      "description": "Include attributes inherited from higher taxa; default true.",
      "type": "boolean"
    },
    "measurementType": {
      "description": "Case-insensitive whole-value measurement type, not trimmed, e.g. Body size; blank means no filter. Names come from worms_list_reference with topic: trait_types.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    }
  },
  "required": [
    "resultOffset",
    "aphiaId",
    "includeInherited"
  ],
  "additionalProperties": false
}
view source ↗

worms_crosswalk_id

open-world

Crosswalk an AphiaID from worms_resolve_taxon to one or all nine external identifier systems, or reverse an externalId with required type to a full taxon record. Supply exactly one selector. Forward resultOffset indexes whole identifiers across types in requested order; resume nextResultOffset with unchanged selectors. typeTotals distinguishes successful absence from IDs on another segment; failed types remain separate. IDs stay opaque, including leading zeros and LSIDs. No IDs cannot establish taxon absence; IUCN identifiers are not threat categories.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "worms_crosswalk_id",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "resultOffset": {
      "default": 0,
      "description": "Zero-based forward identifier position across types in requested order; repeat unchanged selectors. Inactive for reverse lookup.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "aphiaId": {
      "description": "Forward selector; mutually exclusive with externalId.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "externalId": {
      "description": "Reverse selector; opaque identifier up to 512 characters; blank omitted.",
      "type": "string",
      "minLength": 1,
      "maxLength": 512
    },
    "type": {
      "description": "Required for reverse; omit forward to query all nine types. Codes ignore case and surrounding whitespace. See worms_list_reference external_id_types.",
      "type": "string",
      "enum": [
        "algaebase",
        "bold",
        "dyntaxa",
        "fishbase",
        "iucn",
        "lsid",
        "ncbi",
        "tsn",
        "gisd"
      ]
    }
  },
  "required": [
    "resultOffset"
  ],
  "additionalProperties": false
}
view source ↗