national-parks-mcp-server

v0.1.5 pre-1.0

Plan US National Park Service trips — find parks, check alerts and closures, find campgrounds, browse things to do and events via the NPS Data API. STDIO or Streamable HTTP.

national-parks.caseyjhand.com/mcp
claude mcp add --transport http national-parks-mcp-server https://national-parks.caseyjhand.com/mcp
codex mcp add national-parks-mcp-server --url https://national-parks.caseyjhand.com/mcp
{
  "mcpServers": {
    "national-parks-mcp-server": {
      "url": "https://national-parks.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http national-parks-mcp-server https://national-parks.caseyjhand.com/mcp
{
  "mcpServers": {
    "national-parks-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://national-parks.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "national-parks-mcp-server": {
      "type": "http",
      "url": "https://national-parks.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://national-parks.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

6

nps_find_parks

open-world

Resolve a place name, US state, or free-text query to National Park Service parks — the required first step before the detail tools. Returns each park's parkCode (the key nps_get_park, nps_get_alerts, nps_find_campgrounds, nps_get_activities, and nps_find_events all use) plus a compact trip-planning summary (designation, states, description, coordinates, headline activities, entrance fee, NPS page). Coverage is US NPS sites only — national parks, monuments, historic sites, seashores — not state parks and not Forest Service or BLM land.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_find_parks",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "query": {
      "description": "Free-text search across park names and descriptions (e.g. \"yosemite\", \"civil war\", \"redwood\"). Results are re-ranked locally so an exact parkCode or name match leads: NPS returns matches in alphabetical-by-code order with no relevance ranking, so without this the obvious park can sit behind sites that only mention the term in their description. Omit to browse by state. At least one of query or stateCode is recommended; with neither, returns the first page of all ~470 NPS sites.",
      "type": "string"
    },
    "stateCode": {
      "description": "Two-letter US state/territory code, or comma-separated list (e.g. \"CA\", \"WY,MT,ID\"). Filters to parks located in those states. Combine with query to narrow.",
      "type": "string"
    },
    "activity": {
      "description": "Filter to parks offering an activity, matched against each park's activities list (e.g. \"hiking\", \"camping\", \"stargazing\"). Case-insensitive substring match applied locally (the API has no activity param) across every site matching query/stateCode, then paginated with start/limit — so totalCount is the true count of matching parks, not a per-page tally. Use nps_get_park to see a park's full activity list.",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Maximum parks to return (1–50). The full set is ~470 sites; narrow with query/stateCode rather than paging through everything.",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "start": {
      "default": 0,
      "description": "Zero-based offset for pagination within the matched set. Use with limit to page through results.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "limit",
    "start"
  ],
  "additionalProperties": false
}
view source ↗

nps_get_park

open-world

Full trip-planning detail for one or more parks by parkCode: description, activities and topics, entrance fees and passes, operating hours by area/season, contacts, directions, a free-text weather overview, representative images, and the NPS page for everything else. Get codes from nps_find_parks. Up to ten codes are fetched in a single request. Use the fields parameter to trim the payload when you only need certain sections.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_get_park",
    "arguments": {
      "parkCode": "<parkCode>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "parkCode": {
      "minItems": 1,
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^[a-z]{4}$"
      },
      "description": "One to ten park codes (each a 4-letter lowercase code like \"yose\", \"grca\", \"zion\"). Get codes from nps_find_parks. Multiple codes are fetched in a single request."
    },
    "fields": {
      "description": "Optional detail sections to include beyond the always-present core (name, designation, states, description, coordinates, weather, url). Omit for all sections. Narrow to reduce payload when you only need, say, hours and fees.",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "activities",
          "topics",
          "fees",
          "hours",
          "contacts",
          "directions",
          "images"
        ]
      }
    }
  },
  "required": [
    "parkCode"
  ],
  "additionalProperties": false
}
view source ↗

nps_get_alerts

open-world

Current alerts for a park or a whole state — closures, hazards, caution notices, and information — with category and recency surfaced first so "is anything closed at Glacier right now?" is answered at a glance. Get park codes from nps_find_parks, or pass a stateCode for a statewide "what's closed" sweep. Returns most-recent-first; an empty result with totalCount 0 means the park reports nothing closed or hazardous — good news, not an error. An empty page with a non-zero totalCount only means start ran past the end, so read the notice rather than the empty list. Closures and road conditions change daily — re-check before departure.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_get_alerts",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "parkCode": {
      "description": "Park code, or comma-separated list (e.g. \"glac\", \"yose,zion\") — 4-letter lowercase codes. Get codes from nps_find_parks. Provide parkCode or stateCode; with neither, returns recent alerts service-wide.",
      "type": "string"
    },
    "stateCode": {
      "description": "Two-letter state code, or comma-separated list (e.g. \"MT\", \"WY,MT,ID\"). Returns alerts for all NPS sites in those states — use for a statewide sweep rather than one park.",
      "type": "string"
    },
    "category": {
      "description": "Filter to one alert category. \"Danger\" and \"Park Closure\" are the high-priority ones for trip safety. Applied locally (the API has no category param) across every alert matching parkCode/stateCode/query, then paginated with start/limit — so totalCount is the true count of matching alerts, not a per-page tally. Omit to see all categories (the default — closures and hazards should not be missed).",
      "type": "string",
      "enum": [
        "Danger",
        "Caution",
        "Information",
        "Park Closure"
      ]
    },
    "query": {
      "description": "Free-text search within alert titles/descriptions (e.g. \"road\", \"wildfire\", \"trail\").",
      "type": "string"
    },
    "limit": {
      "default": 20,
      "description": "Maximum alerts to return (1–50), most-recent first.",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "start": {
      "default": 0,
      "description": "Zero-based offset for pagination within the matched set. Use with limit to page through results — when totalCount exceeds what was returned, re-request with start advanced by limit.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "limit",
    "start"
  ],
  "additionalProperties": false
}
view source ↗

nps_find_campgrounds

open-world

Campgrounds at a park or across a state: amenities (potable water, showers, RV dump station, toilets, trash collection, RV access), reservable vs. first-come-first-served site counts, reservation guidance and booking URL, accessibility, and fees — answering "where can I camp at Zion, and can I get an RV hookup?" Get park codes from nps_find_parks. Some parks list lodging or backcountry permits instead of NPS-managed campgrounds; an empty result is not an error.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_find_campgrounds",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "parkCode": {
      "description": "Park code, or comma-separated list (e.g. \"zion\") — 4-letter lowercase codes. Get codes from nps_find_parks. Provide parkCode or stateCode.",
      "type": "string"
    },
    "stateCode": {
      "description": "Two-letter state code, or comma-separated list. Returns campgrounds across all NPS sites in those states.",
      "type": "string"
    },
    "query": {
      "description": "Free-text search across campground names/descriptions (e.g. \"river\", \"group\", \"rv\").",
      "type": "string"
    },
    "limit": {
      "default": 15,
      "description": "Maximum campgrounds to return (1–50).",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "start": {
      "default": 0,
      "description": "Zero-based pagination offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "limit",
    "start"
  ],
  "additionalProperties": false
}
view source ↗

nps_get_activities

open-world

Curated things to do and points of interest at a park — title, description, time commitment, location, accessibility, and fee/pet/reservation flags — answering "what should I do at Acadia?" Covers the NPS editorially-curated activity list (distinct from a park's raw activity tags in nps_get_park). Accepts a single 4-letter park code or a single two-letter state code, and at least one is required. Not every park has a curated list; an empty result is not an error.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_get_activities",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "parkCode": {
      "description": "A single 4-letter lowercase park code (e.g. \"acad\"). Get it from nps_find_parks. Accepts one park code, not a list. Provide parkCode or stateCode.",
      "type": "string",
      "pattern": "^[a-z]{4}$"
    },
    "stateCode": {
      "description": "A single two-letter state code (e.g. \"ME\"). Returns curated activities across NPS sites in that state.",
      "type": "string",
      "pattern": "^[A-Za-z]{2}$"
    },
    "query": {
      "description": "Free-text search across activity titles/descriptions (e.g. \"sunrise\", \"hike\", \"tour\").",
      "type": "string"
    },
    "limit": {
      "default": 15,
      "description": "Maximum activities to return (1–50).",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "start": {
      "default": 0,
      "description": "Zero-based pagination offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "limit",
    "start"
  ],
  "additionalProperties": false
}
view source ↗

nps_find_events

open-world

Scheduled events at a park within a date range — ranger programs, festivals, tours, interpretive events — answering "what's happening at Yellowstone this weekend?" with title, dates and times, location, category, fee, and registration links. Get park codes from nps_find_parks. Paginates by page number, not offset. The events feed is sparser and less consistent than alerts or campgrounds; many parks list few or no events, and an empty result is not an error.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "nps_find_events",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "parkCode": {
      "description": "Park code, or comma-separated list (e.g. \"yell\") — 4-letter lowercase codes. Get codes from nps_find_parks. Provide parkCode or stateCode.",
      "type": "string"
    },
    "stateCode": {
      "description": "Two-letter state code, or comma-separated list (e.g. \"WY\", \"WY,MT,ID\"). Returns events across NPS sites in those states.",
      "type": "string"
    },
    "dateStart": {
      "description": "Start of the date window (YYYY-MM-DD). Combine with dateEnd to bound the search (e.g. a weekend). Omit for upcoming events from today.",
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "dateEnd": {
      "description": "End of the date window (YYYY-MM-DD). Use with dateStart.",
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "query": {
      "description": "Free-text search across event titles/descriptions (e.g. \"ranger\", \"astronomy\", \"guided\").",
      "type": "string"
    },
    "pageSize": {
      "default": 15,
      "description": "Maximum events to return per page (1–50). Paginates by page number, not offset — use with pageNumber to walk through results.",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "pageNumber": {
      "default": 1,
      "description": "1-based page number. Increment to page through results beyond the first page.",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "pageSize",
    "pageNumber"
  ],
  "additionalProperties": false
}
view source ↗