Using the MCP Server
This guide walks through the nps-hikes MCP server from setup to first queries. It shows how to run the server locally, connect with MCP Inspector, inspect the available tools and resources, and test both structured and topic-based trail search.
The server is designed for MCP-compatible clients. This guide uses MCP Inspector for the walkthrough because it lets you inspect tools and resources directly, but the same local server can also be used with clients such as Claude Desktop.
The tutorial assumes you've completed the Getting Started guide and run the full data collection pipeline. The MCP server reads from the same local project database as the API.
The server supports two local connection styles:
stdio, where an MCP client launches the server as a subprocess- local
Streamable HTTP, where you start the server first, and then connect tohttp://127.0.0.1:8002/mcp
Tip: Both modes expose the same MCP capabilities. The only difference is how the client and server exchange MCP messages.
What the MCP server exposes
Tools:
search_trailssearch_by_topicsearch_parkssearch_statssearch_park_summary
Resources:
dataset_overviewpark_lookupsearch_methodology
Prerequisites
This guide assumes:
- Your local
nps-hikesPython environment is installed and activated. - The local project database is running and contains the expected park and trail data.
- Node.js and
npxare available so you can run theMCP Inspector.
For search_by_topic, your semantic search dependencies must also be ready:
- Query embeddings can be generated locally.
- Semantic embeddings already exist in the database.
content_trail_mappinghas already been built.
Choose a connection style
Use stdio when you want MCP Inspector to launch the server for you.
Use local Streamable HTTP when you want to run the MCP server as its own local service and connect by URL.
The make targets below are convenience shortcuts. The underlying Python entrypoints are included too so you can see exactly what is running.
Option 1: Run over stdio
The underlying server command is:
python -m nps_hikes_mcp.server
The convenience shortcut is:
make mcp
To validate this mode with MCP Inspector, let Inspector launch the server directly:
npx @modelcontextprotocol/inspector python -m nps_hikes_mcp.server
When the command starts, the Inspector prints a local URL for its web UI. Open the exact URL shown in the terminal output.
In this mode, the Inspector launches the MCP server as a child process. You do not need to run make mcp separately.
Option 2: Run over local Streamable HTTP
The underlying server command is:
python -m nps_hikes_mcp.http_server --host 127.0.0.1 --port 8002 --path /mcp
The convenience shortcut is:
make mcp-http
By default, the server listens at:
http://127.0.0.1:8002/mcp
Start that server in one terminal. Then start the Inspector in a second terminal:
npx @modelcontextprotocol/inspector
Open the Inspector URL printed in that terminal.
In the Inspector UI:
- Set the transport to
streamable-http. - Enter
http://127.0.0.1:8002/mcpas the server URL. - Connect to the running server.
Verify the MCP surface
Once the Inspector is connected, start by listing the available tools and resources:
- Run
tools/list. - Confirm the tools include
search_trails,search_by_topic,search_parks,search_stats, andsearch_park_summary. - Run
resources/list. - Confirm the resources include
dataset_overview,park_lookup, andsearch_methodology.
Next, read each resource once so you can see the static context the server provides:
- Read
dataset_overview. - Read
park_lookup. - Read
search_methodology.
Then make a few tool calls:
- Call
search_stats. - Call
search_parks. - Call
search_trails. - Call
search_by_topic. - Call
search_park_summary.
If those steps succeed, the MCP server is working correctly in that transport mode.
Understand the resources
The resources are useful background context for an MCP client before it starts calling tools.
dataset_overviewexplains what data the project contains, what the MCP server is designed to expose, and the main constraints of the local dataset.park_lookupreturns a structured mapping of park names to canonical 4-letter park codes. A client can use it to turn a name like "Yosemite" intoyose.search_methodologyexplains trail provenance, deduplication, status fields such asvisitedandhiked, and how to interpret topic-search fallback results.
Start with a simple stats query
The easiest first tool call is search_stats with no arguments.
This returns aggregate trail statistics across the full local dataset, including:
total_trailsparks_countstates_counttotal_milessource_breakdown
If you want to scope the stats to hikes you have completed or not completed, set hiked to true or false.
Browse parks
Use search_parks to filter parks by visit status or metadata.
A few good starter queries are:
visited=truevisit_month="Oct"visit_year=2024state="CA"park_code="yose"
The response includes:
summarypark_countvisited_countapplied_filtersparks
Each park entry includes the park code, park name, full name, states, visit information, and URL.
Search trails with structured filters
Use search_trails when the request is purely structured, such as:
- trails in one park
- trails in one state
- hiked or unhiked trails
- minimum or maximum mileage
- source-specific filtering with
TNMorOSM - whether a 3D visualization is available
Common inputs include:
park_code="acad"state="UT"hiked=falsemin_length=3.0max_length=8.0source="TNM"viz_3d=true
The response includes a compact result set with:
summarytrail_counttotal_milesapplied_filterstrails
Each trail includes the trail name, park, state, source, mileage, hiked status, and 3D visualization metadata.
Search trails by topic
Use search_by_topic when the request has a descriptive or semantic component rather than only structured filters.
Good examples include:
query="waterfalls"query="slot canyons"query="scenic viewpoints"query="kid-friendly hikes"
You can combine a topic query with structured filters such as:
park_codestatehikedmin_lengthmax_lengthsource
The response may include:
summarytrail_counttotal_milesapplied_filterstrailstopic_contextfallback_chunks
When semantic matches resolve to trails, trails contains the structured trail results and topic_context includes the matched content snippets that led to those results.
When semantic matches do not resolve to trail rows, the tool still succeeds and returns trail_count: 0 along with fallback_chunks.
Get a park summary
Use search_park_summary when you want a single overview for one park.
For example, call it with:
park_code="yose"
The response groups the data into:
summaryparktrail_statssource_breakdownvisit_info
Use this when you want a concise park overview instead of a longer trail or park listing.
Inspector input tips
MCP Inspector does not always render tool inputs the same way.
- For tools with multiple fields such as
search_trailsandsearch_parks, enter raw field values in each input box. search_by_topic.queryis required and should be a plain-text topic string such aswaterfalls.- For single-scalar inputs such as
search_park_summary, enter the raw value such asyose. - For optional booleans such as
hiked, leave the field blank to omit the parameter, or usetrue/falsefor real boolean values.
If the input form behaves unexpectedly, first check whether Inspector is treating the tool input as individual scalar fields or as a raw JSON payload.
Browser behavior on the HTTP endpoint
If you open http://127.0.0.1:8002/mcp directly in a normal browser tab, you may see a response like:
{"jsonrpc":"2.0","id":"server-error","error":{"code":-32600,"message":"Not Acceptable: Client must accept text/event-stream"}}
That is expected. The MCP endpoint is not a normal web page. It expects an MCP client that can negotiate the correct HTTP transport behavior.
MCP library requirement
This repository expects an MCP server library to be installed in your environment. The entrypoint supports either:
fastmcp- a compatible package exposing
mcp.server.fastmcp.FastMCP
If the MCP library is missing, the server entrypoint exits with a clear error.