io.github.cyanheads/gbif-biodiversity-mcp-server
Search GBIF species taxonomy, occurrence records, datasets, and publishers.
What can you do with io.github.cyanheads/gbif-biodiversity-mcp-server?
- GBIF API v1 species, occurrence, dataset, and organization endpoints, keyless, with an identifying
User-Agenton every request - Synonym-safe keys:
gbif_match_speciesresolves a synonym to its accepted taxon, and the occurrence tools filter on thattaxonKey - Sightings by default: the search, count, and facet tools default
occurrenceStatustoPRESENT, excluding absence records. DatasetrecordCountspans every status, so it runs higher than agbif_count_occurrencestotal for the same key - Strict country codes: on the occurrence tools and
gbif_search_datasets,country(where a record was observed) andpublishingCountry(the publisher's country) accept only uppercase ISO 3166-1 alpha-2, because other forms silently match nothing there. `... - Blank filters rejected: GBIF reads an empty parameter as no filter, so an optional filter sent blank or whitespace-only fails as
invalid_filterinstead of widening the query. Omit a field to leave it off - Scope echo: enrichment reports
totalCount,endOfRecords, theoccurrenceStatusapplied, and the resolvedtaxonScope, with notices on empty results, over-cap totals, and astateProvincethat matched nothing - Graceful partial failure:
gbif_bulk_match_speciesreturns aNONEorERRORrow per name instead of failing the batch - Typed errors:
invalid_filter,not_found,no_match,unresolved_taxon_scope,conflicting_taxon_scope, andpagination_cap_exceeded, each with a recovery hint
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
claude mcp add --transport http gbif-biodiversity-mcp-server 'https://gbif-biodiversity.caseyjhand.com/mcp'
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"type": "http",
"url": "https://gbif-biodiversity.caseyjhand.com/mcp"
}
}
}
@cyanheads/gbif-biodiversity-mcp-serverclaude mcp add gbif-biodiversity-mcp-server -e 'GBIF_CLAMP_READ_LIMITS=true' -e 'MCP_LOG_LEVEL=info' -e 'GBIF_BASE_URL=https://api.gbif.org/v1' -e 'GBIF_REQUEST_TIMEOUT_MS=10000' -e 'GBIF_USER_AGENT=<GBIF_USER_AGENT>' -- npx -y @cyanheads/gbif-biodiversity-mcp-server@0.7.7
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/gbif-biodiversity-mcp-server@0.7.7"
],
"env": {
"GBIF_CLAMP_READ_LIMITS": "true",
"MCP_LOG_LEVEL": "info",
"GBIF_BASE_URL": "https://api.gbif.org/v1",
"GBIF_REQUEST_TIMEOUT_MS": "10000",
"GBIF_USER_AGENT": "<GBIF_USER_AGENT>"
}
}
}
}
Environment variables
GBIF_CLAMP_READ_LIMITSClamp oversized read requests to their documented caps; false restores rejecting maxima.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').GBIF_BASE_URLBase URL every GBIF API request is built from. Override to route through a proxy or a mirror of the GBIF v1 API.GBIF_REQUEST_TIMEOUT_MSMilliseconds a single GBIF API request may take before it is aborted. Aborted attempts fall to the service's retry policy.GBIF_USER_AGENTSent as the User-Agent header on every GBIF API request. GBIF asks integrators to identify themselves with a contact URL or email. Unset or blank sends the server name, version, and repository URL.
@cyanheads/gbif-biodiversity-mcp-serverclaude mcp add gbif-biodiversity-mcp-server -e 'GBIF_CLAMP_READ_LIMITS=true' -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -e 'GBIF_BASE_URL=https://api.gbif.org/v1' -e 'GBIF_REQUEST_TIMEOUT_MS=10000' -e 'GBIF_USER_AGENT=<GBIF_USER_AGENT>' -- npx -y @cyanheads/gbif-biodiversity-mcp-server@0.7.7
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/gbif-biodiversity-mcp-server@0.7.7"
],
"env": {
"GBIF_CLAMP_READ_LIMITS": "true",
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info",
"GBIF_BASE_URL": "https://api.gbif.org/v1",
"GBIF_REQUEST_TIMEOUT_MS": "10000",
"GBIF_USER_AGENT": "<GBIF_USER_AGENT>"
}
}
}
}
Environment variables
GBIF_CLAMP_READ_LIMITSClamp oversized read requests to their documented caps; false restores rejecting maxima.MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').GBIF_BASE_URLBase URL every GBIF API request is built from. Override to route through a proxy or a mirror of the GBIF v1 API.GBIF_REQUEST_TIMEOUT_MSMilliseconds a single GBIF API request may take before it is aborted. Aborted attempts fall to the service's retry policy.GBIF_USER_AGENTSent as the User-Agent header on every GBIF API request. GBIF asks integrators to identify themselves with a contact URL or email. Unset or blank sends the server name, version, and repository URL.
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
@cyanheads/gbif-biodiversity-mcp-server
Search GBIF species taxonomy, occurrence records, datasets, and publishers via MCP. STDIO or Streamable HTTP.
13 Tools • 2 Resources
Public Hosted Server: https://gbif-biodiversity.caseyjhand.com/mcp
Overview
Species taxonomy, occurrence records, datasets, and publishers from the Global Biodiversity Information Facility (GBIF). Match names to the backbone taxonomy, search and aggregate 3.9B+ occurrence records with Darwin Core filters, and trace records back to their datasets and publishers.
Tools
| Tool | Description |
|---|---|
gbif_match_species | Match a scientific name to the GBIF backbone, returning its taxon key, confidence, and classification |
gbif_bulk_match_species | Match up to 50 scientific names in one call, one result per name in input order |
gbif_get_species | Fetch a backbone taxon by key: classification, authorship, synonymy, vernacular name, counts |
gbif_search_species | Search or browse the backbone by name fragment, rank, or a kingdom, family, or genus name |
gbif_get_species_classification | Return a taxon's parent chain, root-first from kingdom to its immediate parent |
gbif_get_species_children | List a taxon's direct children, such as the genera in a family or the species in a genus |
gbif_search_occurrences | Search 3.9B+ occurrence records by taxon, place, date, basis of record, presence/absence, and IUCN category |
gbif_count_occurrences | Count occurrences matching a filter without fetching records |
gbif_get_occurrence | Fetch one full Darwin Core occurrence record by key |
gbif_occurrence_facets | Aggregate occurrence counts by country, year, dataset, taxon, status, and other dimensions |
gbif_search_datasets | Search datasets by keyword, type, publishing country, or publishing or hosting organization |
gbif_get_dataset | Fetch full dataset metadata by UUID: citation, contacts, license, DOI, coverage |
gbif_search_publishers | Search GBIF-registered publishing organizations by name or country |
Resources
| Resource | Description |
|---|---|
gbif://species/{taxonKey} | Taxon record from the GBIF backbone: classification, authorship, synonymy status, vernacular name |
gbif://dataset/{datasetKey} | Dataset metadata: title, description, citation, license, contacts, coverage |
Both resources are also reachable via gbif_get_species and gbif_get_dataset; many MCP clients are tool-only and never surface resources.
Capability reference
gbif_match_species tool
- One scientific
name(common names go togbif_search_species), with optionalstrict, akingdomto disambiguate, and an expectedrank - Returns
taxonKey, the accepted taxon to pass to the occurrence tools, plusmatchedTaxonKeywhen a synonym was resolved,matchType(EXACT,FUZZY,HIGHERRANK),confidence0–100 (review below 80), and the classification with a key at each rank matchTypeNONEfails asno_match; a blankkingdomfails asinvalid_filter
gbif_bulk_match_species tool
- Scientific
nameswithstrict; the first 50 are processed in input order. With read-limit clamping enabled (default), extra names are returned inunprocessedNames, preserving order and duplicates for the next call - Each result carries
nameandmatchType, and on a matchtaxonKey,matchedTaxonKey(synonyms), andconfidence; an unmatched name isNONE, a failed lookup isERRORwitherrorand, when classified,reason, and neither fails the batch
gbif_get_species tool
- One backbone
taxonKey; a key not in the backbone fails asnot_found, one GBIF cannot parse (a fraction, or past the 32-bit range) asinvalid_filter - Returns the classification with rank keys,
authorship,vernacularName,numDescendants,numOccurrences,publishedIn, andparentKey; ataxonomicStatusofSYNONYMcomes withacceptedKeyandaccepted
gbif_search_species tool
qname fragment (scientific and vernacular),rank,isExtinct, and a checklistdatasetKey(omit for the backbone); up to 1,000 per page withoffset- Taxa carry the checklist usage
key, optional sourcedatasetKeyand mapped backbonenubKey,rank,taxonomicStatus, classification names,numOccurrences, andnumDescendants; enrichment reportstotalCount,endOfRecords, and thetaxonScopeapplied. Occurrence queries usenubKeywhen supplied; otherwise resolve the name withgbif_match_species. OmitteddatasetKeyselects GBIF Backbone Taxonomyd7dddbf4-2cf0-4f39-9b2a-bb099caae36c kingdom,family, andgenustake names, matched exactly as GBIF capitalizes them; the narrowest one scopes, andkingdombeside a narrower one disambiguates it. An unknown name fails asunresolved_taxon_scope, a genus outside the named family asconflicting_taxon_scope, and a scope paired with a non-backbonedatasetKeymatches nothing. A blank filter or a malformeddatasetKeyfails asinvalid_filter
gbif_get_species_classification tool
- One
taxonKey; returnsclassificationroot-first from kingdom to the immediate parent, each entry withkey,rank,name, andscientificName - The queried taxon is not included (use
gbif_get_species); a root taxon returns an empty chain with a notice, an unknown key fails asnot_found, and one GBIF cannot parse asinvalid_filter
gbif_get_species_children tool
- One
taxonKey, up to 1,000 children per page withoffset; no filters. An unknown key fails asnot_found, one GBIF cannot parse asinvalid_filter - Each child carries
key,canonicalName,rank,taxonomicStatus,vernacularName,numOccurrences, andnumDescendants; GBIF reports no total, soendOfRecords(withtruncatedwhile more remain) is the continuation signal - An empty later page gives offset-reset guidance; only an empty first page for an existing taxon means no direct children
gbif_search_occurrences tool
- Filters:
taxonKey(preferred;scientificNamedoes not match synonyms),country,publishingCountry,stateProvince, adecimalLatitude/decimalLongitudebox or WKTgeometry,year,month,basisOfRecord,hasCoordinate,isInCluster,coordinateUncertaintyInMeters,datasetKey,occurrenceStatus,iucnRedListCategory; up to 300 per page - All supplied spatial filters intersect: combining
geometrywith latitude or longitude ranges restricts results to their overlap - Records carry
key,taxonKey,taxonomicStatus, coordinates,eventDateandeventTime,basisOfRecord,occurrenceStatus,iucnRedListCategory,datasetKey, andissues; enrichment reportstotalCount,endOfRecords, and theoccurrenceStatusapplied - Search, count and facets echo the same
scope: effective supplied biological filters, withoccurrenceStatusalways included and pagination controls excluded.ANYis echoed but omitted upstream.taxonKeyandscientificNamecombine with OR. All 11 GBIF basis-of-record values are accepted, includingFOSSIL_SPECIMEN,OBSERVATION, andUNKNOWN - Latitude, longitude and coordinate uncertainty are independent optional facts; text renders each supplied value, including zero, in decimal degrees or meters
offset + limitcaps at 100,001 and GBIF has no cursor; a deeper request fails aspagination_cap_exceeded, and a larger match is reached by partitioning on aDATASET_KEYfacet fromgbif_occurrence_facets. A rejected filter value fails asinvalid_filter
gbif_count_occurrences tool
- Accepts every biological filter listed for
gbif_search_occurrences, with the same constraints and spatial intersection.isGeoreferencedremains an alias forhasCoordinate; either alone or both equal works, conflicting values fail asinvalid_filter - Returns
count, with theoccurrenceStatusapplied in the enrichment; a count above 100,001 carries a notice naming the partition route, and a rejected filter value fails asinvalid_filter
gbif_get_occurrence tool
- One
occurrenceKeyfrom a search result; an unknown key fails asnot_found, one GBIF cannot parse asinvalid_filter - The full Darwin Core record:
occurrenceStatus(ABSENTis a survey that found nothing, not a sighting), coordinates, GADM levels 0–3 undergadm, dates witheventTime,taxonomicStatus,iucnRedListCategory, institution, collection, and catalog codes,recordedByandidentifiedBy,media,identifiers, andissues
gbif_occurrence_facets tool
facetis one ofCOUNTRY,STATE_PROVINCE,YEAR,MONTH,BASIS_OF_RECORD,DATASET_KEY,PUBLISHING_COUNTRY,KINGDOM_KEY,PHYLUM_KEY,CLASS_KEY,ORDER_KEY,FAMILY_KEY,GENUS_KEY,SPECIES_KEY,OCCURRENCE_STATUS,IUCN_RED_LIST_CATEGORY; up to 100 values per page (facetLimit, default 10), paged withfacetOffset- Accepts every biological filter listed for
gbif_search_occurrences, with the same constraints and spatial intersection. Repeat them on the facet call and each partition search to preserve the population. ReturnstotalOccurrencesandcountsranked by count; a rejected scope value fails asinvalid_filter - Each facet request fetches one extra bucket to prove continuation.
truncated,shown, andcapappear only when that bucket exists; advancefacetOffsetby the exposed page size. An exactly full final page carries no truncation flag. Empty later pages give offset-reset guidance; an empty first page distinguishes zero matching occurrences from a dimension with no data DATASET_KEYbuckets sum to the scope's full total, so it is the facet for partitioning a search too large to page;YEAR,MONTH,STATE_PROVINCE, andSPECIES_KEYdrop records that lack the field. Passfacet: OCCURRENCE_STATUSwithoccurrenceStatus: ANYfor the presence/absence split
gbif_search_datasets tool
- Filters:
q,type(OCCURRENCE,CHECKLIST,METADATA,SAMPLING_EVENT),publishingCountry,publishingOrg,hostingOrg; up to 1,000 per page - Returns
key,title,type,license,doi,recordCount, and a 300-characterdescriptionpreview, withdescriptionTruncatedflagging a cut (gbif_get_datasethas the full text) publishingOrgmatches the organization whose data it is and is the usual chain fromgbif_search_publishers;hostingOrgmatches the organization whose installation serves it, and the two together intersect. Both take the lowercase UUID form; anything else, like any rejected filter value, fails asinvalid_filter
gbif_get_dataset tool
- One
datasetKeyUUID andcontactLimit(default 10, max 100;0drops contact detail but keepscontactsTotal); a malformed key fails asinvalid_filter, an unknown one asnot_found - Returns
description,citationText,license,doi,recordCount,numConstituents,contactswithcontactsTotalandcontactsReturned,temporalCoverages, andgeographicCoverages
gbif_search_publishers tool
qname fragment andcountry(alpha-2 or alpha-3, any case); up to 1,000 per page- Returns organization
key,title,country, andcity; the key chains intogbif_search_datasetsaspublishingOrg - A blank
q, an emptycountry, or a country GBIF cannot parse fails asinvalid_filter
gbif://species/{taxonKey} resource
- Taxon record as
application/json: classification names,authorship,vernacularName,taxonomicStatuswithacceptedKeyandaccepted,numDescendants taxonKeyis a whole signed decimal integer within the signed 32-bit range. The segment is URI-decoded once and surrounding whitespace is trimmed; leading+, zero padding and their percent-encoded equivalents are accepted. An unknown key fails asnot_found; malformed escapes, suffixes, fractions, exponents, hexadecimal forms, embedded whitespace and out-of-range values fail asinvalid_filterbefore a request. Use a backbone key fromgbif_match_speciesor a search result'snubKey, resolving its name when that mapping is absent
gbif://dataset/{datasetKey} resource
- The
gbif_get_datasetrecord asapplication/json, with contacts fixed at 10 datasetKeycomes fromgbif_search_datasetsor an occurrence record; an unknown key fails asnot_found, a malformed one asinvalid_filter
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.
GBIF-specific:
- GBIF API v1 species, occurrence, dataset, and organization endpoints, keyless, with an identifying
User-Agenton every request - Synonym-safe keys:
gbif_match_speciesresolves a synonym to its accepted taxon, and the occurrence tools filter on thattaxonKey - Sightings by default: the search, count, and facet tools default
occurrenceStatustoPRESENT, excluding absence records. DatasetrecordCountspans every status, so it runs higher than agbif_count_occurrencestotal for the same key - Strict country codes: on the occurrence tools and
gbif_search_datasets,country(where a record was observed) andpublishingCountry(the publisher's country) accept only uppercase ISO 3166-1 alpha-2, because other forms silently match nothing there.stateProvincematches verbatim and case-sensitively, so take values from aSTATE_PROVINCEfacet - Blank filters rejected: GBIF reads an empty parameter as no filter, so an optional filter sent blank or whitespace-only fails as
invalid_filterinstead of widening the query. Omit a field to leave it off
Agent-friendly output:
- Scope echo: enrichment reports
totalCount,endOfRecords, theoccurrenceStatusapplied, and the resolvedtaxonScope, with notices on empty results, over-cap totals, and astateProvincethat matched nothing - Graceful partial failure:
gbif_bulk_match_speciesreturns aNONEorERRORrow per name instead of failing the batch - Typed errors:
invalid_filter,not_found,no_match,unresolved_taxon_scope,conflicting_taxon_scope, andpagination_cap_exceeded, each with a recovery hint - Sparse fields omitted rather than null-filled:
extinctappears only on taxa GBIF explicitly flags - Dataset metadata preserves temporal ranges, single dates, and verbatim periods such as
1975-current; unsupported coverage entries are disclosed. An unavailable supplementary record count carriesrecordCountNoticewhile retaining metadata - Publisher descriptions retain paragraph breaks and decode numeric character references once; Markdown output renders publisher text literally
Getting started
Public Hosted Instance
A public instance is available at https://gbif-biodiversity.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"type": "streamable-http",
"url": "https://gbif-biodiversity.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/gbif-biodiversity-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/gbif-biodiversity-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"gbif-biodiversity-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/gbif-biodiversity-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 credentials: the GBIF endpoints this server calls are public.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/gbif-biodiversity-mcp-server.git
- Navigate into the directory:
cd gbif-biodiversity-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# optionally set GBIF_USER_AGENT to a contact URL or email
Configuration
| Variable | Description | Default |
|---|---|---|
GBIF_BASE_URL | GBIF API base URL. | https://api.gbif.org/v1 |
GBIF_CLAMP_READ_LIMITS | Clamp oversized read limits to the documented caps and disclose requested/applied values. Bulk matching processes the first 50 names and returns the remainder in unprocessedNames. Set false to advertise and enforce rejecting maxima instead. Strict boolean parsing rejects malformed values. | true |
GBIF_REQUEST_TIMEOUT_MS | Per-request HTTP timeout, in ms. | 10000 |
GBIF_USER_AGENT | User-Agent sent on every GBIF request. GBIF asks integrators to identify themselves with a contact URL or email. | server name, version, and repository URL |
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. src/index.ts declares stateless; set this to override it. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted. | false |
LOGS_DIR | Directory for log files (Node.js only). | <project-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 full list of optional 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
Docker
docker build -t gbif-biodiversity-mcp-server .
docker run --rm -p 3010:3010 gbif-biodiversity-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/gbif-biodiversity-mcp-server. OpenTelemetry peer dependencies are installed by default; build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts) and shared tool utilities. Thirteen tools across species taxonomy, occurrences, datasets, and publishers. |
src/mcp-server/resources | Resource definitions. Species and dataset resources. |
src/services/gbif | GBIF API service layer: HTTP client with retry, timeouts, and error mapping, plus raw response types. |
src/config | Server-specific environment variable parsing and validation with Zod. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register new tools and resources in the
createApp()arrays insrc/index.ts - 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.
Frequently asked questions
What is io.github.cyanheads/gbif-biodiversity-mcp-server?
Search GBIF species taxonomy, occurrence records, datasets, and publishers.
How do I install io.github.cyanheads/gbif-biodiversity-mcp-server?
It runs as a remote server. In Claude Code: claude mcp add --transport http gbif-biodiversity-mcp-server 'https://gbif-biodiversity.caseyjhand.com/mcp'. For other clients, paste the JSON configuration from this page into their MCP settings.
Does io.github.cyanheads/gbif-biodiversity-mcp-server need an API key?
Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.
Is io.github.cyanheads/gbif-biodiversity-mcp-server open source?
Yes. Its code is on GitHub under the Apache-2.0 license.
Who maintains io.github.cyanheads/gbif-biodiversity-mcp-server?
It is published by cyanheads. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.