Skip to main content
Glama

gbif-biodiversity-mcp-server

Search Occurrences

gbif_search_occurrences
Read-onlyIdempotent

Search 3.9B+ GBIF occurrence records with Darwin Core filters. Use taxonKey from gbif_match_species for reliable results — it resolves synonyms automatically. Accepts country (uppercase ISO 3166-1 alpha-2, where the record was observed), publishingCountry (the publishing organization's country — a different question), stateProvince, bounding box (decimalLatitude/decimalLongitude ranges), WKT polygon geometry, year range, month, basis of record, coordinate filter, and dataset key. Returns sightings only by default — GBIF also indexes absence records (surveys that looked and found nothing), and occurrenceStatus controls whether they are included. Pagination is capped at offset+limit=100,001 and GBIF offers no cursor or scroll, so a larger result set is covered only by partitioning it — facet it by DATASET_KEY with gbif_occurrence_facets and search each datasetKey separately. This server cannot download a result set in bulk; that needs the GBIF Download API with a GBIF.org account, or the GBIF snapshot on AWS Open Data.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearNoYear or year range. Single year: "2024". Range: "2020,2024". Filters by observation year. Both endpoints inclusive. Omit the field to search every year — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.
limitNoNumber of records to return (default 20, max 300).
monthNoCalendar month (1–12). Useful for seasonal distribution queries.
offsetNoPagination offset. GBIF serves offset+limit up to 100,001 and rejects anything past it, with no cursor or scroll to continue from. To reach a result set larger than that, split it into per-datasetKey searches using a DATASET_KEY facet from gbif_occurrence_facets — gap-free and high-cardinality, unlike YEAR, which leaves undated records in no bucket — rather than paging deeper.
countryNoISO 3166-1 alpha-2 code, uppercase, of where the occurrence was recorded (e.g., "GB", "US", "DE", "SE"). Not the publisher's country — that is publishingCountry, and the two disagree on most records. Lowercase and alpha-3 forms ("gb", "USA") match nothing upstream, which is why only the uppercase two-letter form is accepted here. Take a value from a COUNTRY facet on gbif_occurrence_facets; an uppercase pair GBIF does not know ("XX") is rejected upstream by name.
geometryNoWKT polygon for geographic filtering (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. Takes precedence over decimalLatitude/decimalLongitude. Omit the field to search everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.
taxonKeyNoGBIF backbone taxon key from gbif_match_species. Preferred over scientificName — matches all synonyms automatically. Matches the given taxon and all descendant taxa (subspecies, varieties, etc.).
datasetKeyNoRestrict results to a single dataset by its GBIF dataset UUID (8-4-4-4-12 hex). Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record. Omit the field to search every dataset — an empty string is rejected rather than read as no filter, because GBIF answers a blank datasetKey with the unfiltered result set.
isInClusterNoFilter to records flagged as likely duplicates (true) or exclude them (false). Omit to include all. Note: GBIF does not expose a cluster identifier — only the membership flag. To de-duplicate, set isInCluster: false to exclude all clustered records.
basisOfRecordNoFilter by how the occurrence was recorded. HUMAN_OBSERVATION covers citizen science. PRESERVED_SPECIMEN covers natural history collections.
hasCoordinateNoWhen true, return only georeferenced records (those with coordinates). When false, return ONLY records without coordinates. Omit the parameter entirely to include all records regardless of coordinate presence.
stateProvinceNoState, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. GBIF stores what each dataset recorded without normalizing it, so there is no vocabulary to guess from: "England", "England - Greater London", and "Greater London" are three distinct values, and "england" is none of them. Take one from a STATE_PROVINCE facet on gbif_occurrence_facets scoped the same way and pass it back unchanged — an unmatched value returns zero records rather than an error. Omit the field to search every state or province — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set. Records carrying no stateProvince match no value, so this cannot partition a scope.
scientificNameNoScientific name filter. Less precise than taxonKey — does not match synonyms. Use taxonKey from gbif_match_species for reliable results. Supplying both does not narrow the search: GBIF combines the two taxon filters with OR, so the result is the union of the two, not their intersection. Omit the field to search every name — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.
decimalLatitudeNoLatitude range as "min,max" (e.g., "47.0,48.5"). Decimal degrees, WGS84. Combine with decimalLongitude for a bounding box. Omit the field to leave latitude unbounded — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.
decimalLongitudeNoLongitude range as "min,max" (e.g., "8.0,9.5"). Decimal degrees, WGS84. Combine with decimalLatitude for a bounding box. Omit the field to leave longitude unbounded — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.
occurrenceStatusNoPresence/absence filter. Defaults to PRESENT: an ABSENT record documents a survey that looked for the taxon and did not find it, so including one would read as a sighting of the opposite. Use ANY for both (GBIF's own default), or ABSENT for non-observations alone.PRESENT
publishingCountryNoISO 3166-1 alpha-2 code, uppercase, of the organization that published the record — not where the occurrence was observed, which is country. The two differ constantly: of 60,290,950 records observed in GB, 1,548,928 were published by US organizations. Take a value from a PUBLISHING_COUNTRY facet on gbif_occurrence_facets. Lowercase and alpha-3 forms ("us", "USA") match nothing upstream, which is why only the uppercase two-letter form is accepted here.
iucnRedListCategoryNoRestrict to records whose taxon carries this IUCN Red List category: CR Critically Endangered, EN Endangered, VU Vulnerable, NT Near Threatened, LC Least Concern, DD Data Deficient, EX Extinct, EW Extinct in the Wild, CD Conservation Dependent. Records with no category are excluded when this is set.
coordinateUncertaintyInMetersNoFilter by coordinate uncertainty radius in meters. Range format: "min,max" (e.g., "0,1000" for sub-kilometer precision). Both endpoints inclusive. Omit the field to accept any uncertainty — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
limitNoRecords returned in this page.
noticeNoGuidance when results are empty, paging overshot, the match is larger than the pagination cap can reach, or a presence/absence filter narrowed the result. Absent only when none applies.
offsetNoCurrent pagination offset.
totalCountNoTotal matching occurrences before pagination.
occurrencesNoOccurrence records matching the filters.
endOfRecordsNoTrue when there are no more results after this page.
occurrenceStatusNoThe presence/absence filter applied upstream — PRESENT, ABSENT, or ANY when no filter was sent. Says what totalCount and the returned records cover.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "occurrences",
      +      "totalCount",
      +      "offset",
      +      "limit",
      +      "endOfRecords",
      +      "occurrenceStatus"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `pagination_cap_exceeded`: offset + limit exceeds 100,001, the deepest page GBIF serves. `invalid_filter`: A filter value is unusable — any filter supplied blank or whitespace-only, a datasetKey that is not an 8-4-4-4-12 hex UUID, a two-letter country or publishingCountry code GBIF does not know, or a WKT geometry or range GBIF rejects. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "pagination_cap_exceeded",
      +            "invalid_filter"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "occurrences",
      -  "totalCount",
      -  "offset",
      -  "limit",
      -  "endOfRecords",
      -  "occurrenceStatus"
      -]
  2. Changed8 schema fields changed
    • changedInput schema / properties / coordinateUncertaintyInMeters / description
      Previous value: -"Filter by coordinate uncertainty radius in meters. Range format: \"min,max\" (e.g., \"0,1000\" for sub-kilometer precision). Both endpoints inclusive."New value: +"Filter by coordinate uncertainty radius in meters. Range format: \"min,max\" (e.g., \"0,1000\" for sub-kilometer precision). Both endpoints inclusive. Omit the field to accept any uncertainty — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
    • changedInput schema / properties / datasetKey / description
      Previous value: -"Restrict results to a single dataset by its GBIF dataset UUID (8-4-4-4-12 hex). Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record."New value: +"Restrict results to a single dataset by its GBIF dataset UUID (8-4-4-4-12 hex). Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record. Omit the field to search every dataset — an empty string is rejected rather than read as no filter, because GBIF answers a blank datasetKey with the unfiltered result set."
    • changedInput schema / properties / decimalLatitude / description
      Previous value: -"Latitude range as \"min,max\" (e.g., \"47.0,48.5\"). Decimal degrees, WGS84. Combine with decimalLongitude for a bounding box."New value: +"Latitude range as \"min,max\" (e.g., \"47.0,48.5\"). Decimal degrees, WGS84. Combine with decimalLongitude for a bounding box. Omit the field to leave latitude unbounded — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
    • changedInput schema / properties / decimalLongitude / description
      Previous value: -"Longitude range as \"min,max\" (e.g., \"8.0,9.5\"). Decimal degrees, WGS84. Combine with decimalLatitude for a bounding box."New value: +"Longitude range as \"min,max\" (e.g., \"8.0,9.5\"). Decimal degrees, WGS84. Combine with decimalLatitude for a bounding box. Omit the field to leave longitude unbounded — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
    • changedInput schema / properties / geometry / description
      Previous value: -"WKT polygon for geographic filtering (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. Takes precedence over decimalLatitude/decimalLongitude."New value: +"WKT polygon for geographic filtering (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. Takes precedence over decimalLatitude/decimalLongitude. Omit the field to search everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
    • changedInput schema / properties / scientificName / description
      Previous value: -"Scientific name filter. Less precise than taxonKey — does not match synonyms. Use taxonKey from gbif_match_species for reliable results. Supplying both does not narrow the search: GBIF combines the two taxon filters with OR, so the result is the union of the two, not their intersection."New value: +"Scientific name filter. Less precise than taxonKey — does not match synonyms. Use taxonKey from gbif_match_species for reliable results. Supplying both does not narrow the search: GBIF combines the two taxon filters with OR, so the result is the union of the two, not their intersection. Omit the field to search every name — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
    • changedInput schema / properties / stateProvince / description
      Previous value: -"State, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. GBIF stores what each dataset recorded without normalizing it, so there is no vocabulary to guess from: \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, and \"england\" is none of them. Take one from a STATE_PROVINCE facet on gbif_occurrence_facets scoped the same way and pass it back unchanged — an unmatched value returns zero records rather than an error. Records carrying no stateProvince match no value, so this cannot partition a scope."New value: +"State, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. GBIF stores what each dataset recorded without normalizing it, so there is no vocabulary to guess from: \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, and \"england\" is none of them. Take one from a STATE_PROVINCE facet on gbif_occurrence_facets scoped the same way and pass it back unchanged — an unmatched value returns zero records rather than an error. Omit the field to search every state or province — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set. Records carrying no stateProvince match no value, so this cannot partition a scope."
    • changedInput schema / properties / year / description
      Previous value: -"Year or year range. Single year: \"2024\". Range: \"2020,2024\". Filters by observation year. Both endpoints inclusive."New value: +"Year or year range. Single year: \"2024\". Range: \"2020,2024\". Filters by observation year. Both endpoints inclusive. Omit the field to search every year — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered result set."
  3. Changed2 schema fields changed
    • changedInput schema / properties / country / description
      Previous value: -"ISO 3166-1 alpha-2 code of where the occurrence was recorded (e.g., \"GB\", \"US\", \"DE\", \"SE\"). Not the publisher's country — that is publishingCountry, and the two disagree on most records."New value: +"ISO 3166-1 alpha-2 code, uppercase, of where the occurrence was recorded (e.g., \"GB\", \"US\", \"DE\", \"SE\"). Not the publisher's country — that is publishingCountry, and the two disagree on most records. Lowercase and alpha-3 forms (\"gb\", \"USA\") match nothing upstream, which is why only the uppercase two-letter form is accepted here. Take a value from a COUNTRY facet on gbif_occurrence_facets; an uppercase pair GBIF does not know (\"XX\") is rejected upstream by name."
    • addedInput schema / properties / country / pattern
      Added value: +"^[A-Z]{2}$"
  4. Changed5 schema fields changed
    • changedInput schema / properties / country / description
      Previous value: -"ISO 3166-1 alpha-2 country code (e.g., \"GB\", \"US\", \"DE\", \"SE\")."New value: +"ISO 3166-1 alpha-2 code of where the occurrence was recorded (e.g., \"GB\", \"US\", \"DE\", \"SE\"). Not the publisher's country — that is publishingCountry, and the two disagree on most records."
    • changedInput schema / properties / offset / description
      Previous value: -"Pagination offset. GBIF serves offset+limit up to 100,001 and rejects anything past it — use gbif_occurrence_facets for aggregate analysis beyond that."New value: +"Pagination offset. GBIF serves offset+limit up to 100,001 and rejects anything past it, with no cursor or scroll to continue from. To reach a result set larger than that, split it into per-datasetKey searches using a DATASET_KEY facet from gbif_occurrence_facets — gap-free and high-cardinality, unlike YEAR, which leaves undated records in no bucket — rather than paging deeper."
    • addedInput schema / properties / publishingCountry
      Added value: +{
      +  "description": "ISO 3166-1 alpha-2 code, uppercase, of the organization that published the record — not where the occurrence was observed, which is country. The two differ constantly: of 60,290,950 records observed in GB, 1,548,928 were published by US organizations. Take a value from a PUBLISHING_COUNTRY facet on gbif_occurrence_facets. Lowercase and alpha-3 forms (\"us\", \"USA\") match nothing upstream, which is why only the uppercase two-letter form is accepted here.",
      +  "pattern": "^[A-Z]{2}$",
      +  "type": "string"
      +}
    • addedInput schema / properties / stateProvince
      Added value: +{
      +  "description": "State, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. GBIF stores what each dataset recorded without normalizing it, so there is no vocabulary to guess from: \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, and \"england\" is none of them. Take one from a STATE_PROVINCE facet on gbif_occurrence_facets scoped the same way and pass it back unchanged — an unmatched value returns zero records rather than an error. Records carrying no stateProvince match no value, so this cannot partition a scope.",
      +  "type": "string"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when results are empty, paging overshot, or a presence/absence filter narrowed the result. Absent only when none applies."New value: +"Guidance when results are empty, paging overshot, the match is larger than the pagination cap can reach, or a presence/absence filter narrowed the result. Absent only when none applies."
  5. Changed10 schema fields changed
    • addedInput schema / properties / iucnRedListCategory
      Added value: +{
      +  "description": "Restrict to records whose taxon carries this IUCN Red List category: CR Critically Endangered, EN Endangered, VU Vulnerable, NT Near Threatened, LC Least Concern, DD Data Deficient, EX Extinct, EW Extinct in the Wild, CD Conservation Dependent. Records with no category are excluded when this is set.",
      +  "enum": [
      +    "CR",
      +    "EN",
      +    "VU",
      +    "NT",
      +    "LC",
      +    "DD",
      +    "EX",
      +    "EW",
      +    "CD"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / occurrenceStatus
      Added value: +{
      +  "default": "PRESENT",
      +  "description": "Presence/absence filter. Defaults to PRESENT: an ABSENT record documents a survey that looked for the taxon and did not find it, so including one would read as a sighting of the opposite. Use ANY for both (GBIF's own default), or ABSENT for non-observations alone.",
      +  "enum": [
      +    "PRESENT",
      +    "ABSENT",
      +    "ANY"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / scientificName / description
      Previous value: -"Scientific name filter. Less precise than taxonKey — does not match synonyms. Use taxonKey from gbif_match_species for reliable results."New value: +"Scientific name filter. Less precise than taxonKey — does not match synonyms. Use taxonKey from gbif_match_species for reliable results. Supplying both does not narrow the search: GBIF combines the two taxon filters with OR, so the result is the union of the two, not their intersection."
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when results are empty or paging overshot. Absent on successful result pages."New value: +"Guidance when results are empty, paging overshot, or a presence/absence filter narrowed the result. Absent only when none applies."
    • addedOutput schema / properties / occurrenceStatus
      Added value: +{
      +  "description": "The presence/absence filter applied upstream — PRESENT, ABSENT, or ANY when no filter was sent. Says what totalCount and the returned records cover.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / occurrences / items / properties / eventTime
      Added value: +{
      +  "description": "Time of day of the observation, with seconds and UTC offset (e.g. 20:15:00+01:00) — the offset eventDate omits when it carries a local time. May be absent.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / occurrences / items / properties / iucnRedListCategory
      Added value: +{
      +  "description": "IUCN Red List category of the taxon — CR, EN, VU, NT, LC, DD, EX, EW, or CD. May be absent.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / occurrences / items / properties / occurrenceStatus
      Added value: +{
      +  "description": "PRESENT when the record asserts the taxon was there, ABSENT when it documents a survey that looked and did not find it. An ABSENT record is not a sighting. May be absent.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / occurrences / items / properties / taxonomicStatus
      Added value: +{
      +  "description": "Status of the identification carried on this record — ACCEPTED, PROVISIONALLY_ACCEPTED, SYNONYM, DOUBTFUL, and so on. Says whether the occurrence was filed under an accepted name or a synonym. May be absent.",
      +  "type": "string"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "occurrences",
      -  "totalCount",
      -  "offset",
      -  "limit",
      -  "endOfRecords"
      -]New value: +[
      +  "occurrences",
      +  "totalCount",
      +  "offset",
      +  "limit",
      +  "endOfRecords",
      +  "occurrenceStatus"
      +]
  6. Changed2 schema fields changed
    • changedInput schema / properties / datasetKey / description
      Previous value: -"Restrict results to a single dataset by its GBIF dataset UUID. Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record."New value: +"Restrict results to a single dataset by its GBIF dataset UUID (8-4-4-4-12 hex). Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record."
    • changedInput schema / properties / offset / description
      Previous value: -"Pagination offset. GBIF caps offset+limit at approximately 100,000 — use gbif_occurrence_facets for aggregate analysis beyond this."New value: +"Pagination offset. GBIF serves offset+limit up to 100,001 and rejects anything past it — use gbif_occurrence_facets for aggregate analysis beyond that."
  7. Changed2 schema fields changed
    • addedInput schema / properties / datasetKey
      Added value: +{
      +  "description": "Restrict results to a single dataset by its GBIF dataset UUID. Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet (gbif_occurrence_facets), or the datasetKey field on an occurrence record.",
      +  "type": "string"
      +}
    • changedInput schema / properties / hasCoordinate / description
      Previous value: -"When true, return only georeferenced records. When false, include records without coordinates."New value: +"When true, return only georeferenced records (those with coordinates). When false, return ONLY records without coordinates. Omit the parameter entirely to include all records regardless of coordinate presence."
  8. Changed1 schema field changed
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance when results are empty or paging overshot. Absent on successful result pages.",
      +  "type": "string"
      +}
  9. Changed4 schema fields changed
    • addedInput schema / properties / coordinateUncertaintyInMeters
      Added value: +{
      +  "description": "Filter by coordinate uncertainty radius in meters. Range format: \"min,max\" (e.g., \"0,1000\" for sub-kilometer precision). Both endpoints inclusive.",
      +  "type": "string"
      +}
    • changedInput schema / properties / isInCluster / description
      Previous value: -"Filter to records flagged as likely duplicates (true) or exclude them (false). Omit to include all."New value: +"Filter to records flagged as likely duplicates (true) or exclude them (false). Omit to include all. Note: GBIF does not expose a cluster identifier — only the membership flag. To de-duplicate, set isInCluster: false to exclude all clustered records."
    • changedInput schema / properties / taxonKey / description
      Previous value: -"GBIF backbone taxon key from gbif_match_species. Preferred over scientificName — matches all synonyms automatically."New value: +"GBIF backbone taxon key from gbif_match_species. Preferred over scientificName — matches all synonyms automatically. Matches the given taxon and all descendant taxa (subspecies, varieties, etc.)."
    • changedInput schema / properties / year / description
      Previous value: -"Year or year range. Single year: \"2024\". Range: \"2020,2024\". Filters by observation year."New value: +"Year or year range. Single year: \"2024\". Range: \"2020,2024\". Filters by observation year. Both endpoints inclusive."
  10. First observed

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already carry readOnlyHint, openWorldHint, and idempotentHint, so the description rightly spends no time re-declaring safety. It adds genuinely new behavioral value: the sightings-only-by-default behavior with occurrenceStatus controlling absence records, the hard 100,001 offset+limit cap with no cursor/scroll, and the no-bulk-download limitation — all critical facts an agent needs and none derivable from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five dense sentences front-loaded with purpose, then filters, default behavior, pagination, and the bulk-download limitation in logical order. The length is earned by the tool's 19-parameter complexity and the real gotchas it must convey; it is heavy but not padded with repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema covering return values and 100% schema coverage, nearly everything an agent needs is present. The description closes the remaining gaps: presence-only default, pagination ceiling and partitioning remedy, and bulk-download alternatives. For a tool of this complexity, no material calling concern is left unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with exceptionally rich per-parameter descriptions, so baseline 3 applies. The description adds strategic semantic value on top: recommending taxonKey over scientificName, the DATASET_KEY partitioning strategy for pagination, and the country-vs-publishingCountry distinction. The marginal addition is real but largely synthetic, with most param detail correctly living in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (Search), a precise resource (3.9B+ GBIF occurrence records), and a scope (Darwin Core filters). This clearly distinguishes it from siblings like gbif_count_occurrences (counting), gbif_occurrence_facets (facet aggregation), and gbif_get_occurrence (single-record retrieval), so an agent can pick it without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description routes to gbif_match_species for taxonKey, gbif_occurrence_facets for partitioning large result sets, and the GBIF Download API / AWS Open Data for bulk download, with clear when-not guidance ('This server cannot download a result set in bulk'). It could have explicitly pointed to gbif_count_occurrences for count-only needs or gbif_get_occurrence for a single record, but the exclusions and alternatives given are strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.