GBIF生物多样性数据MCP服务

GBIF MCP Server 通过模型上下文协议为AI助手提供全球生物多样性信息设施(GBIF)API的程序化访问,支持物种分类查询、超20亿条发生记录检索、数据集与文献搜索以及地图瓦片生成,适用于生物多样性研究和数据分析场景。

  • by tyson-swetnam
  • HTML
  • 本地部署
  • 更新于
在 GitHub 查看 tyson-swetnam/gbif-mcp

使用说明

GBIF MCP Server

A Model Context Protocol server that gives AI assistants programmatic access to the Global Biodiversity Information Facility (GBIF) API: species taxonomy, 2+ billion occurrence records, datasets and publishers, map tiles, literature citing GBIF data, controlled vocabularies and data validation.

Works with Claude Code, Claude Desktop, OpenAI Codex CLI, Gemini CLI, Goose, OpenCode and any other MCP client that can launch a stdio server.

Quick start

git clone https://github.com/idss-mesa/gbif-mcp.git
cd gbif-mcp
npm install
npm run build

# Register the server with every supported agent found on this machine
npm run install:agents

Then ask your assistant something like "Search GBIF for Panthera leo occurrences in Kenya".

Requires Node.js 20 or newer. GBIF credentials are optional and only needed for occurrence download requests (see Configuration).

Contents

Protocol support

The server implements MCP protocol revision 2026-07-28 through the v2 TypeScript SDK (@modelcontextprotocol/server). Each connection is served in whichever era the client speaks:

Client Handshake Served
2026-07-28 per-request _meta envelope, optional server/discover probe yes
2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05 classic initialize yes (default)

Current Claude Desktop and Claude Code builds still use the initialize handshake and work without any configuration change. Set MCP_LEGACY_CLIENTS=reject to accept 2026-07-28 clients only; older clients then receive error -32022 (unsupported protocol version).

Other 2026-07-28 details:

  • tools/list is advertised as cacheable (ttlMs 1 hour, cacheScope: public).
  • Every tool carries annotations (readOnlyHint, idempotentHint, openWorldHint). Only the download and validator tools, which create jobs on GBIF, are marked non-read-only.
  • Tool arguments are validated against the advertised JSON Schema before execution. Invalid arguments and unknown tools return JSON-RPC error -32602.
  • Failed GBIF calls come back as tool results with isError: true and a JSON error envelope, never as a crashed connection.
  • ping, logging/setLevel, sampling, roots and elicitation are not used. Logs go to stderr.
  • The process exits when the client closes stdin, so no orphaned servers are left behind.

Installation

Install script

scripts/install.sh registers the server with every supported agent it finds. It builds the server if build/index.js is missing, prefers each agent's own CLI when one is installed (claude mcp add, codex mcp add, gemini mcp add) and otherwise merges an entry into the agent's config file, keeping everything else in the file and leaving a .bak copy.

npm run install:agents                           # every agent detected on this machine
scripts/install.sh --agents all --dry-run        # preview the change for every agent
scripts/install.sh --agents claude,goose         # just Claude Code and Goose
scripts/install.sh --scope project               # project-level config (claude, codex, gemini, opencode)
scripts/install.sh --username you --password …   # store GBIF credentials for download requests
scripts/install.sh --env LOG_LEVEL=debug         # any extra environment variable
scripts/install.sh --uninstall                   # remove the registration everywhere
Agent What the script does
claude (Claude Code) claude mcp add --scope user gbif -- node build/index.js
claude-desktop adds mcpServers.gbif to claude_desktop_config.json (macOS / Linux paths)
codex (OpenAI Codex CLI) codex mcp add gbif -- node build/index.js, or a [mcp_servers.gbif] table in ~/.codex/config.toml
gemini (Gemini CLI) gemini mcp add --scope user gbif node build/index.js, or mcpServers.gbif in ~/.gemini/settings.json
goose adds a gbif stdio extension to ~/.config/goose/config.yaml
opencode adds mcp.servers.gbif (v2) or mcp.gbif (v1) to ~/.config/opencode/opencode.json

The script writes absolute paths for node and build/index.js, because desktop apps do not inherit your shell PATH. It needs bash and Node.js 20+. On Windows run it from WSL or Git Bash, or follow the manual steps below. Restart desktop apps (Claude Desktop, Goose Desktop) after installing.

Claude Code

cd /path/to/gbif-mcp
claude mcp add gbif -- node "$(pwd)/build/index.js"

# with GBIF credentials for download requests
claude mcp add gbif -e GBIF_USERNAME=you -e GBIF_PASSWORD=secret -- node "$(pwd)/build/index.js"

claude mcp list        # shows gbif with a health check
claude mcp get gbif    # details and connection status
claude mcp remove gbif

Use --scope project to write the entry to .mcp.json in the current repository instead of your user config.

Claude Desktop

Add the server to the configuration file and restart Claude Desktop:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "gbif": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/gbif-mcp/build/index.js"],
      "env": {
        "GBIF_USERNAME": "optional-username",
        "GBIF_PASSWORD": "optional-password"
      }
    }
  }
}

Use absolute paths (not ~/ or ./). On Windows escape backslashes: "C:\\Users\\You\\gbif-mcp\\build\\index.js". If node is not found, replace "command": "node" with the full path printed by which node (or where node on Windows).

Codex CLI, Gemini CLI, Goose, OpenCode

The install script handles all four. The equivalent manual entries are:

# ~/.codex/config.toml
[mcp_servers.gbif]
command = "node"
args = ["/ABSOLUTE/PATH/TO/gbif-mcp/build/index.js"]
// ~/.gemini/settings.json
{ "mcpServers": { "gbif": { "command": "node", "args": ["/ABSOLUTE/PATH/TO/gbif-mcp/build/index.js"] } } }
# ~/.config/goose/config.yaml
extensions:
  gbif:
    enabled: true
    type: stdio
    name: gbif
    cmd: node
    args: ["/ABSOLUTE/PATH/TO/gbif-mcp/build/index.js"]
    envs: {}
    timeout: 300
// ~/.config/opencode/opencode.json (OpenCode v2; v1 uses "mcp": { "gbif": … })
{ "mcp": { "servers": { "gbif": { "type": "local", "command": ["node", "/ABSOLUTE/PATH/TO/gbif-mcp/build/index.js"], "enabled": true } } } }

Any other MCP client that can launch a stdio command works the same way: node /ABSOLUTE/PATH/TO/gbif-mcp/build/index.js.

Docker

docker build -t gbif-mcp:latest .
docker run -i --rm gbif-mcp:latest            # stdio: keep -i, never -d

Claude Desktop / any JSON-configured client:

{
  "mcpServers": {
    "gbif": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "-e", "GBIF_USERNAME=you", "-e", "GBIF_PASSWORD=secret", "gbif-mcp:latest"]
    }
  }
}

Claude Code:

claude mcp add gbif -- docker run -i --rm gbif-mcp:latest

With Docker Compose, build with docker compose build and point the client at docker compose run --rm gbif-mcp. The image is a multi-stage Node 20 Alpine build (about 150 MB) that runs as a non-root user on a read-only root filesystem.

Configuration

All settings are environment variables. Defaults are shown; nothing is required.

# GBIF credentials (only for occurrence download requests)
GBIF_USERNAME=
GBIF_PASSWORD=

# GBIF API
GBIF_BASE_URL=https://api.gbif.org/v1
GBIF_USER_AGENT=GBIF-MCP-Server/1.1.0
GBIF_TIMEOUT=30000

# Rate limiting and caching
RATE_LIMIT_MAX_REQUESTS=100
RATE_LIMIT_CONCURRENT=10
CACHE_ENABLED=true
CACHE_MAX_SIZE=100
CACHE_TTL=3600000

# Response size limits (see below)
RESPONSE_MAX_SIZE_KB=250
RESPONSE_WARN_SIZE_KB=200
RESPONSE_ENABLE_TRUNCATION=true
RESPONSE_ENABLE_SIZE_LOGGING=true

# Logging (stderr; stdout is reserved for the protocol)
LOG_LEVEL=info          # error | warn | info | debug
LOG_FORMAT=json

# MCP protocol: serve (also accept 2025-era `initialize` clients) or reject
MCP_LEGACY_CLIENTS=serve

A .env file in the project root is read during local development.

Available tools

58 tools across seven GBIF API sections. Every parameter carries a description, valid values and a real example value (for instance taxonKey: 212 for family Felidae), so assistants can build correct queries without guessing. Results are paginated with offset/limit and an endOfRecords flag.

Species (14)

Tool Purpose
gbif_species_search Full-text search of the taxonomic backbone with rank, status, habitat, threat and dataset filters
gbif_species_get Full record for a taxon key
gbif_species_match Fuzzy-match a scientific name to the backbone
gbif_species_suggest Autocomplete name suggestions
gbif_species_parse_names Parse scientific names into their components
gbif_species_children Direct taxonomic children
gbif_species_parents Full classification path
gbif_species_related Sibling and related taxa under the same parent
gbif_species_synonyms Synonyms of a taxon
gbif_species_vernacular_names Common names by language
gbif_species_descriptions Textual descriptions
gbif_species_distributions Geographic distributions
gbif_species_media Images, sounds and videos
gbif_species_metrics Occurrence statistics for a species: record, dataset and country counts, basis-of-record breakdown

Occurrence (14)

Tool Purpose
gbif_occurrence_search Search records with 40+ filters (taxon, country, coordinates, dates, basis of record, media, issues…)
gbif_occurrence_get A single interpreted record
gbif_occurrence_verbatim The original, uninterpreted record
gbif_occurrence_count Count records matching a filter
gbif_occurrence_counts_by_basis_of_record Breakdown by basis of record
gbif_occurrence_counts_by_year Breakdown by year
gbif_occurrence_counts_by_country Breakdown by country
gbif_occurrence_counts_by_publishing_country Breakdown by publishing country
gbif_occurrence_counts_by_dataset Breakdown by dataset
gbif_occurrence_counts_by_taxon Breakdown by species within a higher taxon
gbif_occurrence_counts_by_publishing_org Breakdown by publishing organization
gbif_occurrence_download_predicate_builder Build a download predicate from search filters
gbif_occurrence_download_request Request a download (needs credentials)
gbif_occurrence_download_status Check a download's status

The "counts by" tools use GBIF faceted search, so every filter of gbif_occurrence_search applies to them.

Registry (18)

Tool Purpose
gbif_registry_search_datasets, gbif_registry_get_dataset Datasets
gbif_registry_dataset_metrics, gbif_registry_dataset_document Occurrence/quality metrics and the EML metadata document
gbif_registry_search_organizations, gbif_registry_get_organization, gbif_registry_organization_datasets Publishing organizations
gbif_registry_search_networks, gbif_registry_get_network, gbif_registry_network_datasets Networks
gbif_registry_search_installations, gbif_registry_get_installation Technical installations (IPTs etc.)
gbif_registry_list_nodes, gbif_registry_get_node GBIF participant nodes
gbif_registry_search_collections, gbif_registry_get_collection GRSciColl collections
gbif_registry_search_institutions, gbif_registry_get_institution GRSciColl institutions

Maps (4)

gbif_maps_get_tile_url, gbif_maps_get_raster_tile_url, gbif_maps_get_vector_tile_url, gbif_maps_list_styles. These build GBIF map tile URLs (density maps of occurrences for any search filter) rather than returning image bytes.

Literature (2)

gbif_literature_search (papers citing GBIF-mediated data, with topic, year, dataset, peer-review and open-access filters) and gbif_literature_get (one paper by DOI).

Vocabularies (3)

gbif_vocabularies_list, gbif_vocabularies_get, gbif_vocabularies_get_concept for GBIF's controlled vocabularies (LifeStage, Sex, BasisOfRecord, …).

Validator (3)

gbif_validator_validate_dwca, gbif_validator_validate_tabular (submit a Darwin Core archive or a CSV/TSV file for validation) and gbif_validator_get_status.

The full reference with every parameter is in TOOLS.md and under docs/api-reference.

Usage examples

Once a client is connected, ask in plain language:

  • "Search for occurrence records of Panthera tigris in India since 2020."
  • "What is the GBIF backbone key for Quercus robur, and what are its common names in German?"
  • "How many bird observations were recorded in California in 2023, broken down by month?"
  • "Find preserved orchid specimens collected before 1900 that have images."
  • "Which datasets does the Natural History Museum publish, and which is the largest?"
  • "Show me recent papers that used GBIF data on pollinators."
  • "Give me a map tile URL for all Apis mellifera records in Europe."

Response size limits

To fit AI context windows the server limits every tool result to 250 KB by default (RESPONSE_MAX_SIZE_KB). For paginated GBIF responses it keeps as many results as fit and adds pagination guidance; for other responses it returns metadata only. A truncated result looks like:

{
  "truncated": true,
  "originalSize": "1.2MB",
  "returnedSize": "248KB",
  "metadata": { "totalCount": 1000, "returnedCount": 23 },
  "pagination": {
    "suggestion": "Use limit=20 with offset=0, then offset=20, offset=40...",
    "example": { "taxonKey": 212, "limit": 20, "offset": 0 }
  },
  "data": { "...": "..." }
}

Set RESPONSE_ENABLE_TRUNCATION=false to disable it.

Verifying the server

From Claude Code, claude mcp list runs a health check and should show gbif as connected. To exercise the stdio surface directly:

npm run build

# 2026-07-28 client: every request carries the protocol envelope in _meta
echo '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"manual","version":"0"}}}}' \
  | node build/index.js

# 2025-era client: classic initialize handshake, then tools/list
printf '%s\n%s\n%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"manual","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  | node build/index.js

Both commands print JSON-RPC responses on stdout and exit once stdin closes.

Troubleshooting

Server does not connect. Check that build/index.js exists, that the config uses absolute paths, and that node --version reports 20 or newer. Claude Desktop logs live in ~/Library/Logs/Claude/ (macOS) or %APPDATA%\Claude\logs\ (Windows). In Claude Code, claude mcp get gbif shows the connection status and claude mcp remove gbif followed by claude mcp add re-registers it.

node: command not found from a desktop app. Desktop apps do not read your shell profile. Use the full path to node as the command, which is what the install script does.

401 on download requests. Downloads need a GBIF account. Set GBIF_USERNAME and GBIF_PASSWORD in the server's env; everything else works anonymously.

Rate limiting or slow responses. Use the count and "counts by" tools before large searches, keep limit small, and use an occurrence download for anything beyond a few thousand records. The client retries 5xx and 429 answers with backoff and opens a circuit breaker after repeated service failures; 404s for unknown keys do not count.

Docker. Always run with -i (and usually --rm); never -d, since MCP needs the stdio connection. Pass credentials with -e or --env-file.

Build errors. rm -rf build node_modules && npm install && npm run build, then npm run typecheck to see TypeScript diagnostics.

Development

npm run dev                         # run from source with tsx, watch mode
npm run build                       # compile to build/
npm run typecheck                   # tsc --noEmit
npm run test:unit                   # unit tests (GBIF API mocked with MSW)
npm run test:integration:protocol   # stdio conformance: 2026-07-28 + legacy clients, official v2 client
npm run test:integration:api        # adversarial matrix: every tool against the live GBIF API
npm run test:coverage               # coverage report
npm run format                      # Prettier

Project layout:

src/
  index.ts            GBIFMCPServer: McpServer factory, serveStdio, tool dispatch, shutdown
  core/gbif-client.ts HTTP client: queue, rate limit, LRU cache, retries, circuit breaker
  services/           one service per GBIF API section
  tools/              58 tools, one class each, Zod input schemas → JSON Schema
  protocol/           error formatting, correlation IDs
  utils/              response truncation, logging
tests/
  unit/               mirrors src/
  integration/mcp/    protocol tests (stdio-protocol.test.ts spawns the real server)
  integration/api/    live GBIF tests, including all-tools.integration.test.ts
scripts/install.sh    agent registration script

Adding a GBIF endpoint: write the service method, add a BaseTool subclass under src/tools/<section>/, export it from that folder's index.ts, register it in initializeServices() in src/index.ts, and add a case to the adversarial matrix. See CLAUDE.md for conventions.

Resources

Contributing

Issues and pull requests are welcome. Fork the repository, create a branch, add tests for service or tool changes (unit plus a line in the adversarial matrix), and open a pull request.

License

Creative Commons Attribution 4.0 International (CC BY 4.0).

GBIF data accessed through this server is subject to the licence of each dataset; see GBIF's data use terms.