Skip to main content
Glama

gbif-biodiversity-mcp-server

Occurrence Facet Aggregation

gbif_occurrence_facets
Read-onlyIdempotent

Aggregate occurrence counts across a dimension (COUNTRY, STATE_PROVINCE, YEAR, BASIS_OF_RECORD, DATASET_KEY, KINGDOM_KEY, etc.). Returns one page of facet values ranked by count descending — the top facetLimit at facetOffset 0, a later slice of the same ranking past that. No record payloads returned. Core tool for distribution analysis and trend queries: "which countries have the most records for this species?", "how has observation volume changed since 2010?". Key dimensions (KINGDOM_KEY through SPECIES_KEY, DATASET_KEY) return bare keys; includeLabels names the taxon or dataset behind each one on the page. Scope the aggregation with taxonKey, country (uppercase ISO 3166-1 alpha-2), publishingCountry, stateProvince, gadmGid, year, scientificName, latitude/longitude ranges, month, hasCoordinate, isInCluster, coordinateUncertaintyInMeters, geometry (all spatial filters intersect), basisOfRecord, datasetKey, catalogNumber, institutionCode, recordedBy, mediaType, occurrenceStatus, or iucnRedListCategory filters. Also the way to split a result set too large for gbif_search_occurrences to page (offset+limit caps at 100,001): facet by DATASET_KEY, then search each datasetKey on its own. Aggregates sightings only by default, matching gbif_search_occurrences and gbif_count_occurrences; to measure the presence/absence split itself, pass facet OCCURRENCE_STATUS with occurrenceStatus ANY.

Input Schema

NameRequiredDescriptionDefault
yearNoYear or year range (e.g., "2020,2024") to scope the aggregation. Both endpoints inclusive. Omit the field to aggregate across every year — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation.
facetYesDimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the first cut when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets cover totalOccurrences with no gap or overlap. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free second cuts for a dataset bucket still too large; both have a matching filter on the occurrence tools. A dimension a record can lack drops that record from every bucket: YEAR loses undated records; MONTH, STATE_PROVINCE, SPECIES_KEY, INSTITUTION_CODE, MEDIA_TYPE, and RECORDED_BY lose records lacking that dimension; GADM_LEVEL_0_GID, GADM_LEVEL_1_GID, GADM_LEVEL_2_GID, and GADM_LEVEL_3_GID lose records without coordinates or outside every GADM unit at that level — each even where the occurrence tools can filter on it. MEDIA_TYPE and RECORDED_BY buckets also overlap: a record with two media types or two collectors counts in each, so their sums can exceed totalOccurrences. GADM buckets are GIDs to pass back as gadmGid; INSTITUTION_CODE buckets come back lowercased and institutionCode takes them unchanged; RECORDED_BY buckets are the exact spellings recordedBy matches. Sums are comparable only across the same occurrenceStatus scope.
monthNoCalendar month (1–12), matching the occurrence search filter.
countryNoISO 3166-1 alpha-2 code, uppercase, of where the occurrence was recorded, to scope to one country. Not the publisher's country — that is publishingCountry, and the two disagree on most records. Scope to one country, or pass back a value this tool returned under facet COUNTRY to drill into that bucket. Lowercase and alpha-3 forms ("gb", "USA") match nothing upstream, which is why only the uppercase two-letter form is accepted here.
gadmGidNoGADM administrative-area GID at any level: country (ESP), state or province (ESP.1_1), county or district (ESP.1.5_1), or municipality (ESP.1.6.3_1). GBIF derives a record's GIDs from its coordinates, so records without coordinates match none, and the unit can differ from the verbatim stateProvince the record carries. Matched exactly and case-sensitively, and a GID holds only uppercase letters, digits, dots, and underscores — any other character is rejected. Take one from a GADM_LEVEL_0_GID, GADM_LEVEL_1_GID, GADM_LEVEL_2_GID, or GADM_LEVEL_3_GID facet on gbif_occurrence_facets, or from the gadm field of gbif_get_occurrence; a well-formed GID GBIF does not hold matches zero records rather than erroring. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.
geometryNoWKT polygon to scope the aggregation to a geographic area (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. All supplied spatial filters intersect: decimalLatitude and decimalLongitude remain active and restrict results to the overlap. Omit the field to aggregate everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation.
taxonKeyNoBackbone taxon key to scope the aggregation. Matches the given taxon and all descendant taxa (subspecies, varieties, etc.).
mediaTypeNoOnly records carrying at least one media item of this type: StillImage (photographs, scans), MovingImage (video), Sound (audio), or InteractiveResource. Records without media are excluded when this is set.
datasetKeyNoScope the aggregation 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, or the datasetKey field on an occurrence record. Omit the field to aggregate across every dataset — an empty string is rejected rather than read as no scope, because GBIF answers a blank datasetKey with the unfiltered aggregation.
facetLimitNoMaximum number of facet values to return (default 10, max 100).
recordedByNoCollector or observer, matched against each name in the record's recordedBy list (GBIF splits it on "|") exactly and case-sensitively: "Charles Darwin" and "charles darwin" differ, and one person written two ways ("Charles Darwin", "Darwin, C.") is two values. Take a value from a RECORDED_BY facet on gbif_occurrence_facets scoped the same way and pass it back unchanged; an unmatched value matches zero records rather than erroring. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.
facetOffsetNoZero-based offset into the ranked facet values, for paging past the first facetLimit values on high-cardinality dimensions like DATASET_KEY. Advance by facetLimit to fetch the next page (0, then facetLimit, then 2×facetLimit, …).
isInClusterNoTrue includes likely duplicates; false excludes them. Omit to include all records. GBIF exposes membership only, with no cluster identifier.
basisOfRecordNoScope to a specific basis of record.
catalogNumberNoCatalog number a collection assigned to the specimen or record (e.g. "L.1592880"), matched as the whole value, case-insensitively. Not unique across collections — one number can name records in several datasets, so pair it with institutionCode or datasetKey to single one out. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.
hasCoordinateNoTrue includes records with coordinates; false only records without coordinates. Omit for both.
includeLabelsNoTrue names the taxon or dataset behind each bucket on the returned page with a label: the canonicalName for a KINGDOM_KEY, PHYLUM_KEY, CLASS_KEY, ORDER_KEY, FAMILY_KEY, GENUS_KEY, or SPECIES_KEY bucket, the dataset title for a DATASET_KEY bucket. Costs one extra GBIF request per bucket, up to facetLimit, all bounded by one 10 s deadline; a bucket whose lookup fails or misses it comes back without a label and is counted in notice. Every other dimension ignores it. Leave it false when keys are enough, as when partitioning by DATASET_KEY.
stateProvinceNoState, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. Pass back a value this tool returned under facet STATE_PROVINCE rather than a guessed one: GBIF stores what each dataset recorded without normalizing it, so "England", "England - Greater London", and "Greater London" are three distinct values, "england" is none of them, and an unmatched value aggregates zero records rather than erroring. Omit the field to aggregate across every state or province — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation.
scientificNameNoScientific name; does not match synonyms. With taxonKey GBIF takes their union (OR), not their intersection. Omit to leave names unfiltered; blank or whitespace-only is rejected.
decimalLatitudeNoLatitude or latitude range "min,max" in decimal degrees (WGS84). All supplied spatial filters intersect, including geometry. Omit to leave latitude unbounded; blank or whitespace-only is rejected.
institutionCodeNoCode of the institution holding the record (e.g. "K", "CLO"), matched as the whole value, case-insensitively — part of a code or of a multi-word code matches nothing. An INSTITUTION_CODE facet on gbif_occurrence_facets lists the codes in a scope, lowercased, and this filter takes them unchanged. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.
decimalLongitudeNoLongitude or longitude range "min,max" in decimal degrees (WGS84). All supplied spatial filters intersect, including geometry. Omit to leave longitude unbounded; blank or whitespace-only is rejected.
occurrenceStatusNoPresence/absence scope. Defaults to PRESENT so the aggregation counts sightings, not the surveys that looked and found nothing, and agrees with gbif_count_occurrences on the same filters. Use ANY for both — required to see both buckets when facet is OCCURRENCE_STATUS — 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. Scope to one publisher country, or pass back a value this tool returned under facet PUBLISHING_COUNTRY to drill into that bucket. Lowercase and alpha-3 forms ("us", "USA") match nothing upstream, which is why only the uppercase two-letter form is accepted here.
iucnRedListCategoryNoScope 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. Leave unset and facet on IUCN_RED_LIST_CATEGORY to see the whole distribution instead.
coordinateUncertaintyInMetersNoCoordinate uncertainty radius in meters, e.g. "0,1000"; range endpoints inclusive. Omit for any uncertainty; blank or whitespace-only is rejected.

Output Schema

NameRequiredDescriptionDefault
capNofacetLimit applied when the page was capped. Re-call with facetOffset advanced by this value to page on. Absent otherwise.
errorNoPresent when the call failed. Absent on success.
facetNoThe facet dimension aggregated.
scopeNoEffective supplied biological filters, with occurrenceStatus always included; excludes pagination and facet controls.
shownNoFacet values returned in this page when the page was capped. Absent otherwise.
countsNoFacet values ranked by count descending — one page of up to facetLimit entries starting at facetOffset, not necessarily the top ones.
noticeNoGuidance when no facet values were returned, a read limit was clamped, a lookahead bucket proves more remain, includeLabels left buckets without a label, an exact-match stateProvince, gadmGid, or recordedBy filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies.
truncatedNoPresent and true only when an extra upstream bucket proves another page exists. Absent on the final page, including an exactly full final page.
facetLimitNoMaximum facet values requested.
facetOffsetNoZero-based offset applied to the ranked facet values.
occurrenceStatusNoThe presence/absence filter applied upstream — PRESENT, ABSENT, or ANY when no filter was sent. Says what totalOccurrences and every bucket cover.
totalOccurrencesNoTotal matching occurrences across all facet values.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed19 schema fields changed
    • addedInput schema / properties / catalogNumber
      Added value: +{
      +  "description": "Catalog number a collection assigned to the specimen or record (e.g. \"L.1592880\"), matched as the whole value, case-insensitively. Not unique across collections — one number can name records in several datasets, so pair it with institutionCode or datasetKey to single one out. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.",
      +  "type": "string"
      +}
    • changedInput schema / properties / facet / description
      Previous value: -"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the first cut when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets cover totalOccurrences with no gap or overlap. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free second cuts for a dataset bucket still too large; both have a matching filter on the occurrence tools. A dimension a record can lack drops that record from every bucket: YEAR loses undated records; MONTH, STATE_PROVINCE, and SPECIES_KEY lose records lacking that dimension, even where the occurrence tools can filter on it. Sums are comparable only across the same occurrenceStatus scope."New value: +"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the first cut when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets cover totalOccurrences with no gap or overlap. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free second cuts for a dataset bucket still too large; both have a matching filter on the occurrence tools. A dimension a record can lack drops that record from every bucket: YEAR loses undated records; MONTH, STATE_PROVINCE, SPECIES_KEY, INSTITUTION_CODE, MEDIA_TYPE, and RECORDED_BY lose records lacking that dimension; GADM_LEVEL_0_GID, GADM_LEVEL_1_GID, GADM_LEVEL_2_GID, and GADM_LEVEL_3_GID lose records without coordinates or outside every GADM unit at that level — each even where the occurrence tools can filter on it. MEDIA_TYPE and RECORDED_BY buckets also overlap: a record with two media types or two collectors counts in each, so their sums can exceed totalOccurrences. GADM buckets are GIDs to pass back as gadmGid; INSTITUTION_CODE buckets come back lowercased and institutionCode takes them unchanged; RECORDED_BY buckets are the exact spellings recordedBy matches. Sums are comparable only across the same occurrenceStatus scope."
    • changedInput schema / properties / facet / enum
      Previous value: -[
      -  "BASIS_OF_RECORD",
      -  "COUNTRY",
      -  "STATE_PROVINCE",
      -  "YEAR",
      -  "DATASET_KEY",
      -  "KINGDOM_KEY",
      -  "PHYLUM_KEY",
      -  "CLASS_KEY",
      -  "ORDER_KEY",
      -  "FAMILY_KEY",
      -  "GENUS_KEY",
      -  "SPECIES_KEY",
      -  "PUBLISHING_COUNTRY",
      -  "MONTH",
      -  "OCCURRENCE_STATUS",
      -  "IUCN_RED_LIST_CATEGORY"
      -]New value: +[
      +  "BASIS_OF_RECORD",
      +  "COUNTRY",
      +  "STATE_PROVINCE",
      +  "YEAR",
      +  "DATASET_KEY",
      +  "KINGDOM_KEY",
      +  "PHYLUM_KEY",
      +  "CLASS_KEY",
      +  "ORDER_KEY",
      +  "FAMILY_KEY",
      +  "GENUS_KEY",
      +  "SPECIES_KEY",
      +  "PUBLISHING_COUNTRY",
      +  "MONTH",
      +  "OCCURRENCE_STATUS",
      +  "IUCN_RED_LIST_CATEGORY",
      +  "GADM_LEVEL_0_GID",
      +  "GADM_LEVEL_1_GID",
      +  "GADM_LEVEL_2_GID",
      +  "GADM_LEVEL_3_GID",
      +  "INSTITUTION_CODE",
      +  "MEDIA_TYPE",
      +  "RECORDED_BY"
      +]
    • addedInput schema / properties / facetLimit / maximum
      Added value: +9007199254740991
    • changedInput schema / properties / facetLimit / type
      Previous value: -"number"New value: +"integer"
    • addedInput schema / properties / facetOffset / maximum
      Added value: +9007199254740991
    • changedInput schema / properties / facetOffset / type
      Previous value: -"number"New value: +"integer"
    • addedInput schema / properties / gadmGid
      Added value: +{
      +  "description": "GADM administrative-area GID at any level: country (ESP), state or province (ESP.1_1), county or district (ESP.1.5_1), or municipality (ESP.1.6.3_1). GBIF derives a record's GIDs from its coordinates, so records without coordinates match none, and the unit can differ from the verbatim stateProvince the record carries. Matched exactly and case-sensitively, and a GID holds only uppercase letters, digits, dots, and underscores — any other character is rejected. Take one from a GADM_LEVEL_0_GID, GADM_LEVEL_1_GID, GADM_LEVEL_2_GID, or GADM_LEVEL_3_GID facet on gbif_occurrence_facets, or from the gadm field of gbif_get_occurrence; a well-formed GID GBIF does not hold matches zero records rather than erroring. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.",
      +  "type": "string"
      +}
    • addedInput schema / properties / includeLabels
      Added value: +{
      +  "default": false,
      +  "description": "True names the taxon or dataset behind each bucket on the returned page with a label: the canonicalName for a KINGDOM_KEY, PHYLUM_KEY, CLASS_KEY, ORDER_KEY, FAMILY_KEY, GENUS_KEY, or SPECIES_KEY bucket, the dataset title for a DATASET_KEY bucket. Costs one extra GBIF request per bucket, up to facetLimit, all bounded by one 10 s deadline; a bucket whose lookup fails or misses it comes back without a label and is counted in notice. Every other dimension ignores it. Leave it false when keys are enough, as when partitioning by DATASET_KEY.",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / institutionCode
      Added value: +{
      +  "description": "Code of the institution holding the record (e.g. \"K\", \"CLO\"), matched as the whole value, case-insensitively — part of a code or of a multi-word code matches nothing. An INSTITUTION_CODE facet on gbif_occurrence_facets lists the codes in a scope, lowercased, and this filter takes them unchanged. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.",
      +  "type": "string"
      +}
    • addedInput schema / properties / mediaType
      Added value: +{
      +  "description": "Only records carrying at least one media item of this type: StillImage (photographs, scans), MovingImage (video), Sound (audio), or InteractiveResource. Records without media are excluded when this is set.",
      +  "enum": [
      +    "StillImage",
      +    "MovingImage",
      +    "Sound",
      +    "InteractiveResource"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / month / type
      Previous value: -"number"New value: +"integer"
    • addedInput schema / properties / recordedBy
      Added value: +{
      +  "description": "Collector or observer, matched against each name in the record's recordedBy list (GBIF splits it on \"|\") exactly and case-sensitively: \"Charles Darwin\" and \"charles darwin\" differ, and one person written two ways (\"Charles Darwin\", \"Darwin, C.\") is two values. Take a value from a RECORDED_BY facet on gbif_occurrence_facets scoped the same way and pass it back unchanged; an unmatched value matches zero records rather than erroring. Omit the field to leave it unfiltered — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered scope.",
      +  "type": "string"
      +}
    • addedInput schema / properties / taxonKey / maximum
      Added value: +9007199254740991
    • addedInput schema / properties / taxonKey / minimum
      Added value: +0
    • changedInput schema / properties / taxonKey / type
      Previous value: -"number"New value: +"integer"
    • addedOutput schema / properties / counts / items / properties / label
      Added value: +{
      +  "description": "Name of the taxon (its canonicalName) or dataset (its title) the key identifies. Present only with includeLabels on a KINGDOM_KEY through SPECIES_KEY or DATASET_KEY facet, and only when the lookup for this bucket succeeded.",
      +  "type": "string"
      +}
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_filter`: A scope filter was supplied blank or whitespace-only, datasetKey is not an 8-4-4-4-12 hex UUID, a two-letter country or publishingCountry code is one GBIF does not know, or GBIF rejected another filter as malformed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_filter`: A string scope filter other than country and publishingCountry was supplied blank or whitespace-only (a blank country or publishingCountry fails earlier, at its uppercase pattern, as -32602 invalid_arguments), datasetKey is not an 8-4-4-4-12 hex UUID, gadmGid holds a character other than an uppercase letter, digit, dot, or underscore, a two-letter country or publishingCountry code is one GBIF does not know, or GBIF rejected another filter as malformed. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned, a read limit was clamped, a lookahead bucket proves more remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."New value: +"Guidance when no facet values were returned, a read limit was clamped, a lookahead bucket proves more remain, includeLabels left buckets without a label, an exact-match stateProvince, gadmGid, or recordedBy filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."
  2. Changed3 schema fields changed
    • changedInput schema / properties / facet / description
      Previous value: -"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the dimension to split on when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets sum to totalOccurrences with no gap and no overlap, and it has the cardinality to cut a large scope into pageable pieces. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free too and both have a matching filter on the occurrence tools, so either can drive a further split of a bucket still too large — but on that same scope they return 9 and 41 buckets against DATASET_KEY's 550, so neither replaces it as the first cut. A dimension a record can lack silently drops that record: faceting one 60,290,950-record scope by YEAR returned 224 buckets summing to 59,407,400, leaving 883,550 undated records in no bucket at all, and MONTH, STATE_PROVINCE, and SPECIES_KEY lose records the same way — stateProvince included, even though the occurrence tools can now filter on it. Sums are comparable only across the same occurrenceStatus scope."New value: +"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the first cut when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets cover totalOccurrences with no gap or overlap. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free second cuts for a dataset bucket still too large; both have a matching filter on the occurrence tools. A dimension a record can lack drops that record from every bucket: YEAR loses undated records; MONTH, STATE_PROVINCE, and SPECIES_KEY lose records lacking that dimension, even where the occurrence tools can filter on it. Sums are comparable only across the same occurrenceStatus scope."
    • removedInput schema / properties / facetLimit / maximum
      Removed value: -100
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned, a lookahead bucket proves more remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."New value: +"Guidance when no facet values were returned, a read limit was clamped, a lookahead bucket proves more remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."
  3. Changed14 schema fields changed
    • changedInput schema / properties / basisOfRecord / enum
      Previous value: -[
      -  "HUMAN_OBSERVATION",
      -  "MACHINE_OBSERVATION",
      -  "PRESERVED_SPECIMEN",
      -  "LIVING_SPECIMEN",
      -  "MATERIAL_SAMPLE",
      -  "MATERIAL_CITATION",
      -  "OCCURRENCE",
      -  "LITERATURE"
      -]New value: +[
      +  "HUMAN_OBSERVATION",
      +  "MACHINE_OBSERVATION",
      +  "PRESERVED_SPECIMEN",
      +  "LIVING_SPECIMEN",
      +  "MATERIAL_SAMPLE",
      +  "MATERIAL_CITATION",
      +  "OCCURRENCE",
      +  "LITERATURE",
      +  "FOSSIL_SPECIMEN",
      +  "OBSERVATION",
      +  "UNKNOWN"
      +]
    • addedInput schema / properties / coordinateUncertaintyInMeters
      Added value: +{
      +  "description": "Coordinate uncertainty radius in meters, e.g. \"0,1000\"; range endpoints inclusive. Omit for any uncertainty; blank or whitespace-only is rejected.",
      +  "type": "string"
      +}
    • addedInput schema / properties / decimalLatitude
      Added value: +{
      +  "description": "Latitude or latitude range \"min,max\" in decimal degrees (WGS84). All supplied spatial filters intersect, including geometry. Omit to leave latitude unbounded; blank or whitespace-only is rejected.",
      +  "type": "string"
      +}
    • addedInput schema / properties / decimalLongitude
      Added value: +{
      +  "description": "Longitude or longitude range \"min,max\" in decimal degrees (WGS84). All supplied spatial filters intersect, including geometry. Omit to leave longitude unbounded; blank or whitespace-only is rejected.",
      +  "type": "string"
      +}
    • changedInput schema / properties / geometry / description
      Previous value: -"WKT polygon to scope the aggregation to a geographic area (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. Omit the field to aggregate everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation."New value: +"WKT polygon to scope the aggregation to a geographic area (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. All supplied spatial filters intersect: decimalLatitude and decimalLongitude remain active and restrict results to the overlap. Omit the field to aggregate everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation."
    • addedInput schema / properties / hasCoordinate
      Added value: +{
      +  "description": "True includes records with coordinates; false only records without coordinates. Omit for both.",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / isInCluster
      Added value: +{
      +  "description": "True includes likely duplicates; false excludes them. Omit to include all records. GBIF exposes membership only, with no cluster identifier.",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / month
      Added value: +{
      +  "description": "Calendar month (1–12), matching the occurrence search filter.",
      +  "maximum": 12,
      +  "minimum": 1,
      +  "type": "number"
      +}
    • addedInput schema / properties / scientificName
      Added value: +{
      +  "description": "Scientific name; does not match synonyms. With taxonKey GBIF takes their union (OR), not their intersection. Omit to leave names unfiltered; blank or whitespace-only is rejected.",
      +  "type": "string"
      +}
    • changedOutput schema / anyOf
      Previous value: -[
      -  {
      -    "not": {
      -      "required": [
      -        "error"
      -      ]
      -    },
      -    "required": [
      -      "facet",
      -      "totalOccurrences",
      -      "counts",
      -      "facetLimit",
      -      "facetOffset",
      -      "occurrenceStatus"
      -    ]
      -  },
      -  {
      -    "required": [
      -      "error"
      -    ]
      -  }
      -]New value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "facet",
      +      "totalOccurrences",
      +      "counts",
      +      "scope",
      +      "facetLimit",
      +      "facetOffset",
      +      "occurrenceStatus"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_filter`: A scope filter was supplied blank or whitespace-only, datasetKey is not an 8-4-4-4-12 hex UUID, a two-letter country or publishingCountry code is one GBIF does not know, or GBIF rejected the geometry or year scope as malformed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_filter`: A scope filter was supplied blank or whitespace-only, datasetKey is not an 8-4-4-4-12 hex UUID, a two-letter country or publishingCountry code is one GBIF does not know, or GBIF rejected another filter as malformed. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned, the page came back full and more values may remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."New value: +"Guidance when no facet values were returned, a lookahead bucket proves more remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."
    • addedOutput schema / properties / scope
      Added value: +{
      +  "additionalProperties": {
      +    "type": [
      +      "string",
      +      "number",
      +      "boolean"
      +    ]
      +  },
      +  "description": "Effective supplied biological filters, with occurrenceStatus always included; excludes pagination and facet controls.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • changedOutput schema / properties / truncated / description
      Previous value: -"Heuristic continuation flag: present and true when this page returned a full facetLimit of values, so more distinct values may exist past facetOffset + facetLimit. GBIF exposes no total distinct-value count, so this is an estimate, not exact. Absent when the page came back short, which is the only proof the ranking is exhausted."New value: +"Present and true only when an extra upstream bucket proves another page exists. Absent on the final page, including an exactly full final page."
  4. Changed11 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": [
      +      "facet",
      +      "totalOccurrences",
      +      "counts",
      +      "facetLimit",
      +      "facetOffset",
      +      "occurrenceStatus"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / cap
      Added value: +{
      +  "description": "facetLimit applied when the page was capped. Re-call with facetOffset advanced by this value to page on. Absent otherwise.",
      +  "type": "number"
      +}
    • 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: `invalid_filter`: A scope filter was supplied blank or whitespace-only, datasetKey is not an 8-4-4-4-12 hex UUID, a two-letter country or publishingCountry code is one GBIF does not know, or GBIF rejected the geometry or year scope as malformed. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "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 / properties / moreValuesLikely
      Removed value: -{
      -  "description": "Heuristic continuation flag: true when this page returned a full facetLimit of values, so more distinct values may exist past facetOffset + facetLimit (re-call with facetOffset advanced by facetLimit). GBIF exposes no total distinct-value count, so this is an estimate, not exact.",
      -  "type": "boolean"
      -}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."New value: +"Guidance when no facet values were returned, the page came back full and more values may remain, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."
    • addedOutput schema / properties / shown
      Added value: +{
      +  "description": "Facet values returned in this page when the page was capped. Absent otherwise.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "Heuristic continuation flag: present and true when this page returned a full facetLimit of values, so more distinct values may exist past facetOffset + facetLimit. GBIF exposes no total distinct-value count, so this is an estimate, not exact. Absent when the page came back short, which is the only proof the ranking is exhausted.",
      +  "type": "boolean"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "facet",
      -  "totalOccurrences",
      -  "counts",
      -  "facetLimit",
      -  "facetOffset",
      -  "moreValuesLikely",
      -  "occurrenceStatus"
      -]
  5. Changed4 schema fields changed
    • changedInput schema / properties / datasetKey / description
      Previous value: -"Scope the aggregation 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, or the datasetKey field on an occurrence record."New value: +"Scope the aggregation 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, or the datasetKey field on an occurrence record. Omit the field to aggregate across every dataset — an empty string is rejected rather than read as no scope, because GBIF answers a blank datasetKey with the unfiltered aggregation."
    • changedInput schema / properties / geometry / description
      Previous value: -"WKT polygon to scope the aggregation to a geographic area (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude."New value: +"WKT polygon to scope the aggregation to a geographic area (e.g., POLYGON((8 47, 9 47, 9 48, 8 48, 8 47))). Coordinates are longitude latitude. Omit the field to aggregate everywhere — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation."
    • changedInput schema / properties / stateProvince / description
      Previous value: -"State, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. Pass back a value this tool returned under facet STATE_PROVINCE rather than a guessed one: GBIF stores what each dataset recorded without normalizing it, so \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, \"england\" is none of them, and an unmatched value aggregates zero records rather than erroring."New value: +"State, province, or first-level administrative division, matched as a verbatim string — exact and case-sensitive. Pass back a value this tool returned under facet STATE_PROVINCE rather than a guessed one: GBIF stores what each dataset recorded without normalizing it, so \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, \"england\" is none of them, and an unmatched value aggregates zero records rather than erroring. Omit the field to aggregate across every state or province — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation."
    • changedInput schema / properties / year / description
      Previous value: -"Year or year range (e.g., \"2020,2024\") to scope the aggregation. Both endpoints inclusive."New value: +"Year or year range (e.g., \"2020,2024\") to scope the aggregation. Both endpoints inclusive. Omit the field to aggregate across every year — a blank or whitespace-only value is rejected rather than dropped, because GBIF answers one with the unfiltered aggregation."
  6. Changed2 schema fields changed
    • changedInput schema / properties / country / description
      Previous value: -"ISO 3166-1 alpha-2 code of where the occurrence was recorded, to scope to one country. 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, to scope to one country. Not the publisher's country — that is publishingCountry, and the two disagree on most records. Scope to one country, or pass back a value this tool returned under facet COUNTRY to drill into that bucket. Lowercase and alpha-3 forms (\"gb\", \"USA\") match nothing upstream, which is why only the uppercase two-letter form is accepted here."
    • addedInput schema / properties / country / pattern
      Added value: +"^[A-Z]{2}$"
  7. Changed5 schema fields changed
    • changedInput schema / properties / country / description
      Previous value: -"ISO 3166-1 alpha-2 country code to scope to one country."New value: +"ISO 3166-1 alpha-2 code of where the occurrence was recorded, to scope to one country. Not the publisher's country — that is publishingCountry, and the two disagree on most records."
    • changedInput schema / properties / facet / description
      Previous value: -"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY)."New value: +"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY). DATASET_KEY is the dimension to split on when a result set is too large to page: every occurrence carries exactly one datasetKey, so its buckets sum to totalOccurrences with no gap and no overlap, and it has the cardinality to cut a large scope into pageable pieces. BASIS_OF_RECORD and PUBLISHING_COUNTRY are gap-free too and both have a matching filter on the occurrence tools, so either can drive a further split of a bucket still too large — but on that same scope they return 9 and 41 buckets against DATASET_KEY's 550, so neither replaces it as the first cut. A dimension a record can lack silently drops that record: faceting one 60,290,950-record scope by YEAR returned 224 buckets summing to 59,407,400, leaving 883,550 undated records in no bucket at all, and MONTH, STATE_PROVINCE, and SPECIES_KEY lose records the same way — stateProvince included, even though the occurrence tools can now filter on it. Sums are comparable only across the same occurrenceStatus scope."
    • 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. Scope to one publisher country, or pass back a value this tool returned under facet PUBLISHING_COUNTRY to drill into that bucket. 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. Pass back a value this tool returned under facet STATE_PROVINCE rather than a guessed one: GBIF stores what each dataset recorded without normalizing it, so \"England\", \"England - Greater London\", and \"Greater London\" are three distinct values, \"england\" is none of them, and an unmatched value aggregates zero records rather than erroring.",
      +  "type": "string"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned or a presence/absence filter narrowed the aggregation. Absent only when neither applies."New value: +"Guidance when no facet values were returned, a verbatim stateProvince filter matched nothing, or a presence/absence filter narrowed the aggregation. Absent only when none applies."
  8. Changed7 schema fields changed
    • changedInput schema / properties / facet / description
      Previous value: -"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY)."New value: +"Dimension to aggregate by (e.g., COUNTRY, YEAR, BASIS_OF_RECORD, SPECIES_KEY, OCCURRENCE_STATUS, IUCN_RED_LIST_CATEGORY)."
    • changedInput schema / properties / facet / enum
      Previous value: -[
      -  "BASIS_OF_RECORD",
      -  "COUNTRY",
      -  "STATE_PROVINCE",
      -  "YEAR",
      -  "DATASET_KEY",
      -  "KINGDOM_KEY",
      -  "PHYLUM_KEY",
      -  "CLASS_KEY",
      -  "ORDER_KEY",
      -  "FAMILY_KEY",
      -  "GENUS_KEY",
      -  "SPECIES_KEY",
      -  "PUBLISHING_COUNTRY",
      -  "MONTH"
      -]New value: +[
      +  "BASIS_OF_RECORD",
      +  "COUNTRY",
      +  "STATE_PROVINCE",
      +  "YEAR",
      +  "DATASET_KEY",
      +  "KINGDOM_KEY",
      +  "PHYLUM_KEY",
      +  "CLASS_KEY",
      +  "ORDER_KEY",
      +  "FAMILY_KEY",
      +  "GENUS_KEY",
      +  "SPECIES_KEY",
      +  "PUBLISHING_COUNTRY",
      +  "MONTH",
      +  "OCCURRENCE_STATUS",
      +  "IUCN_RED_LIST_CATEGORY"
      +]
    • addedInput schema / properties / iucnRedListCategory
      Added value: +{
      +  "description": "Scope 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. Leave unset and facet on IUCN_RED_LIST_CATEGORY to see the whole distribution instead.",
      +  "enum": [
      +    "CR",
      +    "EN",
      +    "VU",
      +    "NT",
      +    "LC",
      +    "DD",
      +    "EX",
      +    "EW",
      +    "CD"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / occurrenceStatus
      Added value: +{
      +  "default": "PRESENT",
      +  "description": "Presence/absence scope. Defaults to PRESENT so the aggregation counts sightings, not the surveys that looked and found nothing, and agrees with gbif_count_occurrences on the same filters. Use ANY for both — required to see both buckets when facet is OCCURRENCE_STATUS — or ABSENT for non-observations alone.",
      +  "enum": [
      +    "PRESENT",
      +    "ABSENT",
      +    "ANY"
      +  ],
      +  "type": "string"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when no facet values were returned. Absent when counts are non-empty."New value: +"Guidance when no facet values were returned or a presence/absence filter narrowed the aggregation. Absent only when neither 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 totalOccurrences and every bucket cover.",
      +  "type": "string"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "facet",
      -  "totalOccurrences",
      -  "counts",
      -  "facetLimit",
      -  "facetOffset",
      -  "moreValuesLikely"
      -]New value: +[
      +  "facet",
      +  "totalOccurrences",
      +  "counts",
      +  "facetLimit",
      +  "facetOffset",
      +  "moreValuesLikely",
      +  "occurrenceStatus"
      +]
  9. Changed1 schema field changed
    • changedOutput schema / properties / counts / description
      Previous value: -"Facet values ranked by count descending (top facetLimit entries)."New value: +"Facet values ranked by count descending — one page of up to facetLimit entries starting at facetOffset, not necessarily the top ones."
  10. Changed1 schema field changed
    • changedInput schema / properties / datasetKey / description
      Previous value: -"Scope the aggregation to a single dataset by its GBIF dataset UUID. Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet, or the datasetKey field on an occurrence record."New value: +"Scope the aggregation 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, or the datasetKey field on an occurrence record."
  11. Changed4 schema fields changed
    • addedInput schema / properties / facetOffset
      Added value: +{
      +  "default": 0,
      +  "description": "Zero-based offset into the ranked facet values, for paging past the first facetLimit values on high-cardinality dimensions like DATASET_KEY. Advance by facetLimit to fetch the next page (0, then facetLimit, then 2×facetLimit, …).",
      +  "minimum": 0,
      +  "type": "number"
      +}
    • addedOutput schema / properties / facetOffset
      Added value: +{
      +  "description": "Zero-based offset applied to the ranked facet values.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / moreValuesLikely
      Added value: +{
      +  "description": "Heuristic continuation flag: true when this page returned a full facetLimit of values, so more distinct values may exist past facetOffset + facetLimit (re-call with facetOffset advanced by facetLimit). GBIF exposes no total distinct-value count, so this is an estimate, not exact.",
      +  "type": "boolean"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "facet",
      -  "totalOccurrences",
      -  "counts",
      -  "facetLimit"
      -]New value: +[
      +  "facet",
      +  "totalOccurrences",
      +  "counts",
      +  "facetLimit",
      +  "facetOffset",
      +  "moreValuesLikely"
      +]
  12. Changed1 schema field changed
    • addedInput schema / properties / datasetKey
      Added value: +{
      +  "description": "Scope the aggregation to a single dataset by its GBIF dataset UUID. Obtain one from gbif_search_datasets, gbif_get_dataset, a DATASET_KEY facet, or the datasetKey field on an occurrence record.",
      +  "type": "string"
      +}
  13. Changed3 schema fields changed
    • addedOutput schema / properties / facetLimit
      Added value: +{
      +  "description": "Maximum facet values requested.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance when no facet values were returned. Absent when counts are non-empty.",
      +  "type": "string"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "facet",
      -  "totalOccurrences",
      -  "counts"
      -]New value: +[
      +  "facet",
      +  "totalOccurrences",
      +  "counts",
      +  "facetLimit"
      +]
  14. Changed3 schema fields changed
    • changedInput schema / properties / facet / enum
      Previous value: -[
      -  "BASIS_OF_RECORD",
      -  "COUNTRY",
      -  "YEAR",
      -  "DATASET_KEY",
      -  "KINGDOM_KEY",
      -  "PHYLUM_KEY",
      -  "CLASS_KEY",
      -  "ORDER_KEY",
      -  "FAMILY_KEY",
      -  "GENUS_KEY",
      -  "SPECIES_KEY",
      -  "PUBLISHING_COUNTRY",
      -  "MONTH"
      -]New value: +[
      +  "BASIS_OF_RECORD",
      +  "COUNTRY",
      +  "STATE_PROVINCE",
      +  "YEAR",
      +  "DATASET_KEY",
      +  "KINGDOM_KEY",
      +  "PHYLUM_KEY",
      +  "CLASS_KEY",
      +  "ORDER_KEY",
      +  "FAMILY_KEY",
      +  "GENUS_KEY",
      +  "SPECIES_KEY",
      +  "PUBLISHING_COUNTRY",
      +  "MONTH"
      +]
    • changedInput schema / properties / taxonKey / description
      Previous value: -"Backbone taxon key to scope the aggregation."New value: +"Backbone taxon key to scope the aggregation. Matches the given taxon and all descendant taxa (subspecies, varieties, etc.)."
    • changedInput schema / properties / year / description
      Previous value: -"Year or year range (e.g., \"2020,2024\") to scope the aggregation."New value: +"Year or year range (e.g., \"2020,2024\") to scope the aggregation. Both endpoints inclusive."
  15. First observed

TDQS

A4.6/5.0
Behavior5/5

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

Adds substantial behavior beyond annotations: ranked facet values, pagination via facetLimit/facetOffset, no record payloads, includeLabels cost and deadline, missing-dimension gaps, overlapping buckets for MEDIA_TYPE and RECORDED_BY, and comparability only within the same occurrenceStatus scope.

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?

The purpose and return behavior are front-loaded, and the description is organized logically. It is long, with a filter-list sentence that duplicates the schema, but that length is partly justified by the tool's 26 parameters and complex facet semantics.

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?

Given the complex aggregation behavior, rich schema, output schema, and annotations, the description covers what the tool returns, how paging works, when to use it, how to scope it, and important caveats about gaps and overlaps. Nothing essential for correct invocation appears missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all 26 parameters in detail. The description summarizes scoping filters and highlights a few cross-parameter interactions, but most of its parameter guidance repeats what the schema already says.

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?

States a specific verb (aggregate), resource (occurrence counts), and dimension-based behavior. It distinguishes the tool from gbif_search_occurrences and gbif_count_occurrences by describing facet aggregation and the oversized-result workaround.

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

Usage Guidelines5/5

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

Explicitly names core use cases such as distribution and trend queries, and explains when to use this instead of paging through gbif_search_occurrences. It also clarifies the default occurrenceStatus scope and how to see presence/absence via facet OCCURRENCE_STATUS with occurrenceStatus ANY.

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.