Search / io.github.cyanheads/inaturalist-mcp-server
inaturalist-mcp-server
R0· no sign-inSearch iNaturalist sightings, identification threads, phenology, and look-alike species.
v0.2.2 · active · repository · descriptor JSON · versions
Search / io.github.cyanheads/inaturalist-mcp-server
R0· no sign-inSearch iNaturalist sightings, identification threads, phenology, and look-alike species.
v0.2.2 · active · repository · descriptor JSON · versions
{
"mcpServers": {
"inaturalist-mcp-server": {
"type": "http",
"url": "https://inaturalist.caseyjhand.com/mcp"
}
}
}claude mcp add --transport http inaturalist-mcp-server https://inaturalist.caseyjhand.com/mcp[mcp_servers.inaturalist-mcp-server]
url = "https://inaturalist.caseyjhand.com/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"inaturalist-mcp-server": {
"type": "remote",
"url": "https://inaturalist.caseyjhand.com/mcp",
"enabled": true
}
}
}{
"mcpServers": {
"inaturalist-mcp-server": {
"type": "http",
"url": "https://inaturalist.caseyjhand.com/mcp"
}
},
"deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=inaturalist-mcp-server&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vaW5hdHVyYWxpc3QuY2FzZXlqaGFuZC5jb20vbWNwIn0%3D"
}{
"servers": {
"inaturalist-mcp-server": {
"type": "http",
"url": "https://inaturalist.caseyjhand.com/mcp"
}
}
}{
"mcpServers": {
"inaturalist-mcp-server": {
"httpUrl": "https://inaturalist.caseyjhand.com/mcp"
}
}
}extensions:
"inaturalist-mcp-server":
enabled: true
name: "inaturalist-mcp-server"
type: streamable_http
uri: "https://inaturalist.caseyjhand.com/mcp"
timeout: 300
protocol.modernsupports 2026-07-28 (server/discover)protocol.statelessanswers without a sessionprotocol.transportstreamable HTTPprotocol.list_ttltools/list declares ttlMs 0, so clients re-fetch it on every useauth.prm, auth.as_metadata, auth.cimdno remote uses OAuthauth.secret_in_urlno templated URLtools.descriptionsevery tool has a descriptiontools.description_lengthdescriptions are concisetools.schemasevery tool has an object input schematools.annotations10 of 10 tools declare readOnlyHint or destructiveHinttools.directory_hintsno tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: inaturalist_resolve_name (destructiveHint, idempotentHint); inaturalist_search_observations (destructiveHint, idempotentHint); inaturalist_list_reference (destructiveHint, idempotentHint); …tools.token_costabout 8,749 tokens to load every tooltools.api_dumptools are not a one-to-one API dumpstability.changes7 tool changes in 30 daysstability.rug_pullno tool changed its meaning under the same namedeps.known_vulns, deps.mcp_sdk_version, deps.resolvabledeps.dev does not know @cyanheads/[email protected], @cyanheads/[email protected]inaturalist_get_similar_specieschangeddescription, input schema, output schemaList the taxa this one is most often misidentified as, ranked by how many times identifiers made the correction — the field-identification check before committing to a look-alike. Scope it to an area in exactly one form (place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box) to see the confusion set a specific region actually produces, or leave the area off for the global set. Resolve the organism name to a taxon id with inaturalist_resolve_name first.
List the taxa this one is most often misidentified as, ranked by how many times identifiers made the correction — the field-identification check before committing to a look-alike. Scope it to an area in exactly one form (place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box) to see the confusion set a specific region actually produces, or leave the area off for the global set. The taxon must be a genus or finer (genus, species, or below) — upstream keeps no confusion set for a family, order, or anything coarser. Resolve the organism name to a taxon id with inaturalist_resolve_name first.
inaturalist_get_leaderboardchangedoutput schemainaturalist_get_histogramchangeddescription, input schema, output schemaBuild a phenology histogram for a taxon in an area — which months, weeks, or years it is recorded in. The default month_of_year interval answers "when does this bloom or appear here" in twelve buckets; the absolute intervals (year, month, week, day, hour) bucket real dates and upstream applies a default start date to them. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Omit taxon_id to chart every taxon in the area. Defaults to research-grade, wild-only records and echoes those defaults back.
Build a phenology histogram for a taxon in an area — which months, weeks, or years it is recorded in. The default month_of_year interval answers "when does this bloom or appear here" in twelve buckets; the absolute intervals (year, month, week, day, hour) bucket real dates and upstream applies a default start date to them. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Omit taxon_id to chart every taxon in the area. Narrow to one life stage or reproductive state with an annotation pair (term_id and term_value_id, e.g. Life Stage = Larva, or Flowers and Fruits = Flowers), or to broad groups with iconic_taxa. Defaults to research-grade, wild-only records and echoes those defaults back.
inaturalist_get_species_countschangeddescription, input schema, output schemaRank the distinct species recorded in an area and period, most-observed first — the "what lives here" answer, without paging through individual sightings. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Narrow to a clade by passing taxon_id, e.g. the birds of a park. Defaults to research-grade, wild-only records and echoes those defaults back. For the most active people rather than the most recorded species, use inaturalist_get_leaderboard.
Rank the distinct species recorded in an area and period, most-observed first — the "what lives here" answer, without paging through individual sightings. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Narrow to a clade by passing taxon_id, e.g. the birds of a park, or to one observer or one project by user_id, user_login, or project_id. Defaults to research-grade, wild-only records and echoes those defaults back. For the most active people rather than the most recorded species, use inaturalist_get_leaderboard.
inaturalist_get_observationchangeddescription, input schema, output schemaFetch up to 10 observations by id with their community identification thread — who identified what, whether each identification agrees, and the consensus taxon the community landed on. The whole batch costs one upstream request, so resolving ten ids here is far cheaper than ten separate lookups. A missing id is reported per id in unresolved rather than failing the batch; the call fails only when nothing resolved.
Fetch up to 10 observations by id with their community identification thread — who identified what, whether each identification agrees, and the consensus taxon the community landed on. The whole batch costs one upstream request, so resolving ten ids here is far cheaper than ten separate lookups. Records come back in the requested order. A missing id is reported per id in unresolved rather than failing the batch; the call fails only when nothing resolved. Long threads and long observation-field lists are cut to fit one response budget shared across the batch — up to 40 identifications, 40 comments, and 40 filled fields for a single id, 4 of each per record for ten — and every record reports the size of each array beside what it kept.
inaturalist_search_observationschangeddescription, input schema, output schemaSearch georeferenced wildlife sightings by area, date, taxon, quality grade, annotation, and conservation status. Returns a projected record per sighting with coordinates, licence, first photo, and identification counts. An area is given in exactly one form — place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box — and defaults to research-grade, wild-only records, which are echoed back on every call. Identifications and comments are deliberately not expandable here (one thread is 28 KB); fetch them for specific records with inaturalist_get_observation. Results past 10,000 need the cursor from the previous page rather than a higher page number.
Search georeferenced wildlife sightings by area, date, taxon, quality grade, annotation, conservation status, observer, project, and licence. Returns a projected record per sighting with coordinates, licence, first photo, and identification counts. An area is given in exactly one form — place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box — and defaults to research-grade, wild-only records, which are echoed back on every call. Identifications and comments are deliberately not expandable here (one thread is 28 KB); fetch them for specific records with inaturalist_get_observation. page walks the first 10,000 results under any ordering; past 10,000, order by id descending (order_by "id", order "desc") and pass each page’s next_cursor as cursor.
inaturalist_list_referencechangedoutput schemaFull history: list_changes · trend: quality JSON.
Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.
+repository +namespace-matches-repo +reachable +uptime-100% +updated-12d-ago
Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.
@cyanheads/[email protected] npmthis version is not known to the dependency resolver
@cyanheads/[email protected] npmthis version is not known to the dependency resolver
Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0. The graph is what a clean install of this version resolves today; nothing was installed or run. How it is checked.
| remote | auth | reachable | uptime 30d | p50 | protocol | last ok |
|---|---|---|---|---|---|---|
https://inaturalist.caseyjhand.com/mcp streamable-http | none | yes | 100% | 191 ms | 2026-07-28 | 2026-10-20 |
| package | registry | version | runtime | secrets |
|---|---|---|---|---|
@cyanheads/inaturalist-mcp-server | npm | 0.2.2 | npx | |
@cyanheads/inaturalist-mcp-server | npm | 0.2.2 | npx |
inaturalist_find_placesread-only | Resolve a place name to a place id, or list the places containing a map area. Pass q to match a place-name PREFIX, or all four of nelat, nelng, swlat and swlng to list every place covering that box — exactly one of the two, never both. Each result carries the bounding box, place type, and containment chain an area search needs. Place geometry is stripped: a single nearby response carries 247 KB of boundary polygons upstream, none of which reaches the caller. |
inaturalist_get_histogramread-only | Build a phenology histogram for a taxon in an area — which months, weeks, or years it is recorded in. The default month_of_year interval answers "when does this bloom or appear here" in twelve buckets; the absolute intervals (year, month, week, day, hour) bucket real dates and upstream applies a default start date to them. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Omit taxon_id to chart every taxon in the area. Narrow to one life stage or reproductive state with an annotation pair (term_id and term_value_id, e.g. Life Stage = Larva, or Flowers and Fruits = Flowers), or to broad groups with iconic_taxa. Defaults to research-grade, wild-only records and echoes those defaults back. |
inaturalist_get_leaderboardread-only | Rank the most active observers or identifiers for an area, period, and taxon — who knows this place or this group. kind selects which: observers are ranked by how many observations they recorded, identifiers by how many identifications they made. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Both endpoints rank only the top 500 entries, so page multiplied by per_page must stay at or below 500 — narrow the area, period, or taxon to bring someone further down into reach. For the most-recorded species rather than the most active people, use inaturalist_get_species_counts. |
inaturalist_get_observationread-only | Fetch up to 10 observations by id with their community identification thread — who identified what, whether each identification agrees, and the consensus taxon the community landed on. The whole batch costs one upstream request, so resolving ten ids here is far cheaper than ten separate lookups. Records come back in the requested order. A missing id is reported per id in unresolved rather than failing the batch; the call fails only when nothing resolved. Long threads and long observation-field lists are cut to fit one response budget shared across the batch — up to 40 identifications, 40 comments, and 40 filled fields for a single id, 4 of each per record for ten — and every record reports the size of each array beside what it kept. |
inaturalist_get_similar_speciesread-only | List the taxa this one is most often misidentified as, ranked by how many times identifiers made the correction — the field-identification check before committing to a look-alike. Scope it to an area in exactly one form (place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box) to see the confusion set a specific region actually produces, or leave the area off for the global set. The taxon must be a genus or finer (genus, species, or below) — upstream keeps no confusion set for a family, order, or anything coarser. Resolve the organism name to a taxon id with inaturalist_resolve_name first. |
inaturalist_get_species_countsread-only | Rank the distinct species recorded in an area and period, most-observed first — the "what lives here" answer, without paging through individual sightings. An area is given in exactly one form: place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box. Narrow to a clade by passing taxon_id, e.g. the birds of a park, or to one observer or one project by user_id, user_login, or project_id. Defaults to research-grade, wild-only records and echoes those defaults back. For the most active people rather than the most recorded species, use inaturalist_get_leaderboard. |
inaturalist_get_taxonread-only | Fetch a taxon profile: the taxonomic path, per-authority conservation listings, the encyclopedia summary, the photo gallery, immediate children, and observation counts. Resolve a name to a taxon id with inaturalist_resolve_name first. The upstream record is 95 KB for a common species, so it is projected before anything else happens; a taxon that still overflows comes back as an outline of its sections with their byte sizes, and naming those sections in a re-call returns only those. The valid section names are summary, taxonomy, children, conservation, photos, and encyclopedia. |
inaturalist_list_referenceread-only | Decode the vocabularies the other iNaturalist tools take as input: annotation attributes and values, quality grades, license codes, taxonomic ranks, iconic taxa, and IUCN conservation-status codes. An unrecognized filter value is not rejected upstream — it silently returns nothing — so read the codes here before filtering. Note that the conservation codes are the normalised csi search filter; a taxon record’s own conservation_statuses[].status is authority-specific free text and reads differently. With topic controlled_terms and a taxon_id, the response also carries which annotations identifiers have actually recorded for that taxon, with counts. |
inaturalist_resolve_nameread-only | Resolve a common or scientific name to a taxon id, or a place, project, or observer name to its id. Returns ranked candidates carrying the identifiers every other tool takes. A miss is a result rather than a failure: found comes back false with guidance naming why. Taxon lookup matches a name PREFIX, not words inside a name, so "monarch butterfly" misses where "monarch" hits. |
inaturalist_search_observationsread-only | Search georeferenced wildlife sightings by area, date, taxon, quality grade, annotation, conservation status, observer, project, and licence. Returns a projected record per sighting with coordinates, licence, first photo, and identification counts. An area is given in exactly one form — place_id, the lat/lng/radius triple in kilometres, or a four-corner bounding box — and defaults to research-grade, wild-only records, which are echoed back on every call. Identifications and comments are deliberately not expandable here (one thread is 28 KB); fetch them for specific records with inaturalist_get_observation. page walks the first 10,000 results under any ordering; past 10,000, order by id descending (order_by "id", order "desc") and pass each page’s next_cursor as cursor. |
Schemas: list_tools.
And 140 more from this publisher.
{
"name": "io.github.cyanheads/inaturalist-mcp-server",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"remotes": [
{
"url": "https://inaturalist.caseyjhand.com/mcp",
"type": "streamable-http"
}
],
"version": "0.2.2",
"packages": [
{
"version": "0.2.2",
"transport": {
"type": "stdio"
},
"identifier": "@cyanheads/inaturalist-mcp-server",
"runtimeHint": "npx",
"registryType": "npm",
"registryBaseUrl": "https://registry.npmjs.org",
"environmentVariables": [
{
"name": "MCP_LOG_LEVEL",
"format": "string",
"default": "info",
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
},
{
"name": "INATURALIST_USER_AGENT",
"format": "string",
"description": "User-Agent sent on every request to api.inaturalist.org. Defaults to the package name, its version, and the repository URL. Keep a contact URL in any override — the published terms ask for identifiable clients."
},
{
"name": "INATURALIST_MIN_REQUEST_INTERVAL_MS",
"format": "number",
"default": "1100",
"description": "Minimum spacing between outbound request starts, in milliseconds. The default holds the sustained rate near 54 requests per minute, under the 60 the upstream asks for and well under its 100 ceiling."
},
{
"name": "INATURALIST_MAX_CONCURRENT_REQUESTS",
"format": "number",
"default": "4",
"description": "Maximum outbound requests in flight. Separate from the start interval: spacing bounds the sustained rate, this bounds the burst so one slow call does not stall the lane."
},
{
"name": "INATURALIST_DAILY_REQUEST_BUDGET",
"format": "number",
"default": "9000",
"description": "Outbound requests allowed per UTC day, counted in-process. The default sits under the 10,000 per day the upstream asks for, and exhaustion fails loudly rather than degrading silently. The counter is per process and resets on restart."
}
]
},
{
"version": "0.2.2",
"transport": {
"url": "http://localhost:3010/mcp",
"type": "streamable-http"
},
"identifier": "@cyanheads/inaturalist-mcp-server",
"runtimeHint": "npx",
"registryType": "npm",
"registryBaseUrl": "https://registry.npmjs.org",
"environmentVariables": [
{
"name": "MCP_TRANSPORT_TYPE",
"value": "http",
"format": "string",
"description": "Selects the HTTP transport."
},
{
"name": "MCP_HTTP_HOST",
"format": "string",
"default": "127.0.0.1",
"description": "The hostname for the HTTP server."
},
{
"name": "MCP_HTTP_PORT",
"format": "string",
"default": "3010",
"description": "The port to run the HTTP server on."
},
{
"name": "MCP_HTTP_ENDPOINT_PATH",
"format": "string",
"default": "/mcp",
"description": "The endpoint path for the MCP server."
},
{
"name": "MCP_AUTH_MODE",
"format": "string",
"default": "none",
"description": "Authentication mode to use: 'none', 'jwt', or 'oauth'."
},
{
"name": "MCP_LOG_LEVEL",
"format": "string",
"default": "info",
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
},
{
"name": "INATURALIST_USER_AGENT",
"format": "string",
"description": "User-Agent sent on every request to api.inaturalist.org. Defaults to the package name, its version, and the repository URL. Keep a contact URL in any override — the published terms ask for identifiable clients."
},
{
"name": "INATURALIST_MIN_REQUEST_INTERVAL_MS",
"format": "number",
"default": "1100",
"description": "Minimum spacing between outbound request starts, in milliseconds. The default holds the sustained rate near 54 requests per minute, under the 60 the upstream asks for and well under its 100 ceiling."
},
{
"name": "INATURALIST_MAX_CONCURRENT_REQUESTS",
"format": "number",
"default": "4",
"description": "Maximum outbound requests in flight. Separate from the start interval: spacing bounds the sustained rate, this bounds the burst so one slow call does not stall the lane."
},
{
"name": "INATURALIST_DAILY_REQUEST_BUDGET",
"format": "number",
"default": "9000",
"description": "Outbound requests allowed per UTC day, counted in-process. The default sits under the 10,000 per day the upstream asks for, and exhaustion fails loudly rather than degrading silently. The counter is per process and resets on restart."
}
]
}
],
"repository": {
"url": "https://github.com/cyanheads/inaturalist-mcp-server",
"source": "github"
},
"description": "Search iNaturalist sightings, identification threads, phenology, and look-alike species."
}