wsdot-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@wsdot-mcp-servercheck the Snoqualmie Pass conditions"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://wsdot.caseyjhand.com/mcp
Overview
Washington State transportation data from the WSDOT Traveler API and the WSF Ferry API. Query mountain pass and highway conditions, search alerts and cameras, and track ferry schedules, vessel locations, and terminal space from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| Current conditions for all WA mountain passes: status, road condition, traction laws, temperature, elevation. |
| Active highway alerts — incidents, construction, closures — filterable by state route, WSDOT region, and milepost range. |
| Current vs. average travel times for named WA highway corridors (I-5, I-90, SR 520, etc.) with congestion delay. |
| Dynamic toll rates for WA express lanes and tolled facilities — SR 99, SR 167 HOT, I-405 Express, SR 509, SR 520 — filterable by route. |
| Current vehicle wait times at all WA/Canada land border crossings. |
| Highway camera metadata and image URLs, filterable by state route, region, milepost range, and title words. |
| All WSF ferry terminals with numeric IDs needed for schedule and space lookups, plus coordinates. |
| WSF routes operating on a given date — route ID, abbreviation, description, and the terminal pairs each serves, for route discovery, schedule lookups, and ferry-alert cross-reference. |
| Departure times for a specific WSF route — today-remaining or full-day future mode — with each sailing's vessel, loading rule, and notes. |
| Real-time AIS positions, speed, heading, ETA, and dock status for all active WSF vessels. |
| Drive-up and reservable vehicle space available at WSF terminals for upcoming sailings. |
| Active WSF service disruptions and bulletins with impacted route IDs. |
Related MCP server: @cyanheads/onebusaway-mcp-server
Capability reference
wsdot_get_mountain_passes tool
No input — current conditions for all 16 WA mountain passes (Snoqualmie, Stevens, White, Blewett, Cayuse, and others) in one call
Each pass carries road condition, weather, temperature, elevation, and up to two directional traction/travel restrictions
wsdot_search_alerts tool
Optional
stateRoute,region(Northwest, Olympic, Southwest, South Central, North Central, Eastern), andstartMilepost/endMilepost— an alert matches when its extent overlaps the range; omit all for every statewide alert. Ordered byalertId, paged (default 20, max 500)An unknown region fails as
invalid_regionand a start above the end asinvalid_milepost_range, each with a recovery hint
wsdot_get_travel_times tool
Optional
route— a route ("I-5","SR 520") returns every corridor measured on it, any other text matches corridor names ("Everett"); paged (default 50, max 500)Each corridor reports current and average minutes — current above average means congestion, and the delta is the delay. A reversible express-lane corridor closed in the queried direction omits its figures rather than reporting zero
wsdot_get_toll_rates tool
Covers SR 99 (WSDOT Tunnel), SR 167 HOT Lanes, I-405 Express Lanes, the SR 509 tolled segment, and the SR 520 Bridge. Optional
stateRoutematches the posted designation ("I-405","SR 520"); a route with no tolled facility returns an empty page whose notice names the tolled routes. Paged (default 50, max 500)Each row leads with its
startLocationName → endLocationNamesegment.stateRouteis the feed's bare zero-padded number ("099") andtravelDirectionthe feed's code, which SR 99, SR 509, and SR 520 fix per facility — read direction from the segment's ends
wsdot_get_border_waits tool
No input — eleven lane entries in
crossings[]across I-5 (Peace Arch), SR 543 (Pacific Highway), SR 539 (Lynden), and SR 9 (Sumas): a general-purpose and a Nexus lane at each, plus truck lanes at SR 539 and SR 543crossingNameis a route code (I5,SR543Trucks) andlocation.descriptionthe readable name; a lane with no current data omitswaitTimeInMinutes
wsdot_search_cameras tool
Optional
stateRoute,regioncode (NW,SW,OL,ER,SC,NC,OSfor the Oregon TripCheck cameras,WAfor airport cameras),startMilepost/endMilepost, andtitleContains(every word, any order). Ordered bycameraId, paged (default 50, max 500)Returns metadata and image URLs, not image bytes (camera images are copyright WSDOT). An unknown region fails as
invalid_regionand a reversed range asinvalid_milepost_range
wsdot_get_ferry_terminals tool
No input — all 20 WSF terminals, each with its numeric ID, abbreviation, and latitude/longitude
Resolves names ("Bainbridge Island", "Seattle") to the IDs
wsdot_get_ferry_scheduleandwsdot_get_terminal_spacetake
wsdot_get_ferry_routes tool
Optional
tripDate(YYYY-MM-DD, default today); a date outside the range WSF has published fails asinvalid_datestating that rangeEach route carries its ID (the
impactedRouteIdsofwsdot_get_ferry_alerts), abbreviation, description, andterminalPairs— the departing → arriving pairswsdot_get_ferry_scheduleaccepts that day
wsdot_get_ferry_schedule tool
Requires
departingTerminalIdandarrivingTerminalId(a pair fromterminalPairsonwsdot_get_ferry_routes); optionaltripDate(default today) andremainingOnly(future departures only, today only)Each sailing carries
departureTime/arrivalTimein ISO 8601 UTC (tripDateis the Pacific service day),vesselId,loadingRule, and indexes into the pair'sannotations. There is no cancellation flag — WSF drops a cancelled sailing, so checkwsdot_get_ferry_alertsA pair with no schedule that day fails as
invalid_terminal_pairand a date with none asinvalid_date, never as an empty schedule
wsdot_get_vessel_locations tool
No input — position, speed, heading, ETA, and dock status for every active WSF vessel
Positions may lag 30–60 seconds; many fields are absent for a vessel not in service, and one between assignments reports
opRouteAbbrevasnone reported
wsdot_get_terminal_space tool
Optional
departingTerminalId(fromwsdot_get_ferry_terminals), else every terminal; paged by terminal (default 5, max 20), with every sailing of a returned terminal includeddriveUpSpaceCountis the key field — zero means the drive-up lane is full, and an oversubscribed sailing's negative upstream count floors to zero.arrivingTerminalIdschains intowsdot_get_ferry_schedule
wsdot_get_ferry_alerts tool
No input — active WSF disruptions, delays, and bulletins, each with
alertTitle, a one-linealertDescription, and the fullbulletinText(detail such as a replacement sailing appears only in the body)impactedRouteIdsmap towsdot_get_ferry_routes;affectsAllRoutes: truemarks a fleet-wide alert, whose empty route list then means every route
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
WSDOT-specific:
Dual API integration — WSDOT Traffic API and WSF Ferry API share a single
WSDOT_ACCESS_CODECross-tool linking built into tool descriptions — ferry tools point to
wsdot_get_ferry_terminals/wsdot_get_ferry_routesfor ID resolution before a lookupNormalized response shapes across both APIs — sparse upstream fields surface as optional rather than omitted or defaulted
Stable pagination — the alert and camera feeds return the same set in more than one row order upstream, so results are sorted by ID to keep a given offset reproducible
Paged list tools take
offset/limit, and a page also ends early at a 24,000-byte response budget, with the notice naming the next offsetRoute filters take the forms people write —
"I-90","90","090","SR 520"— and every text filter accepts at most 200 characters
Agent-friendly output:
Typed failure —
invalid_access_codeandapi_unavailableerrors carry an explicit recovery hint distinguishing configuration faults from transient upstream onesdriveUpSpaceCount: 0and congestion delta fields (delayInMinutes) give agents actionable signal without string parsingPlain text from HTML — alert descriptions, sailing notes, and bulletins arrive from upstream as HTML and are returned as text, with links inline as
link text (url)Partial data preserved — sparse upstream payloads surface
null/undefinedrather than synthetic defaults (e.g. an omittedwaitTimeInMinutes, an absentarrivalTime)content[]andstructuredContentcarry the same values, not just the same fields — afalseflag, an empty list, and one populated half of a coordinate pair all render rather than dropping out of the markdown surface that some clients read; a blank or whitespace-only upstream string is absent from both, and a populated one arrives trimmed
Getting started
Public Hosted Instance
A public instance is available at https://wsdot.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"wsdot-mcp-server": {
"type": "streamable-http",
"url": "https://wsdot.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file. You'll need a WSDOT Traveler API access code — register at wsdot.wa.gov/Traffic/api/.
{
"mcpServers": {
"wsdot-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/wsdot-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"WSDOT_ACCESS_CODE": "your-access-code"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"wsdot-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/wsdot-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"WSDOT_ACCESS_CODE": "your-access-code"
}
}
}
}Or with Docker:
{
"mcpServers": {
"wsdot-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "WSDOT_ACCESS_CODE=your-access-code",
"ghcr.io/cyanheads/wsdot-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 WSDOT_ACCESS_CODE=your-access-code bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
A WSDOT Traveler API access code. Register at wsdot.wa.gov/Traffic/api/ — registration is free.
Installation
Clone the repository:
git clone https://github.com/cyanheads/wsdot-mcp-server.gitNavigate into the directory:
cd wsdot-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set WSDOT_ACCESS_CODEConfiguration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
Variable | Description | Default |
| Required. WSDOT Traveler API access code. Register at wsdot.wa.gov/Traffic/api/. | — |
| Transport: |
|
| HTTP server port. |
|
| HTTP server hostname. |
|
| HTTP endpoint path. |
|
| Public origin for TLS-terminating reverse-proxy deployments. | — |
| Session handling: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Log each failed tool call's arguments and result (key-name redaction only). |
|
| Enable OpenTelemetry instrumentation (spans, metrics, completion logs). |
|
| OTLP base URL; traces go to | — |
| Opt-in OTLP log export; the base endpoint never enables it. | — |
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t wsdot-mcp-server .
docker run --rm -e WSDOT_ACCESS_CODE=your-access-code -p 3010:3010 wsdot-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/wsdot-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| WSDOT Traffic API service (mountain passes, alerts, travel times, toll rates, border waits, cameras). |
| WSF Ferry API service (terminals, routes, schedule, vessel locations, space, alerts). |
| Unit and integration tests, mirroring the |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools in the
createApp()arrays insrc/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Transport for NSW MCP — journey planning, live departures, service alerts
Real-time transit stops, routes, arrivals, vehicle positions, and schedules via OneBusAway APIs.
Query U.S. Census Bureau data, variables, and geography via MCP.
Query US Treasury national debt, interest rates, exchange rates, and fiscal datasets via MCP.
Related MCP Servers
- AlicenseBqualityDmaintenanceProvides real-time access to BC highway conditions, road closures, weather alerts, and traffic incidents through the Open511-DriveBC API with smart caching.4MIT
- AlicenseNot gradedqualityAmaintenanceEnables querying stops, routes, real-time arrivals, vehicle positions, and schedules from OneBusAway transit APIs via MCP, supporting STDIO or Streamable HTTP.330 npm1Apache 2.0
- AlicenseAqualityAmaintenanceProvides live California road conditions, route planning, and an AI assistant over MCP, enabling natural-language queries about traffic, closures, chain controls, and more.104MIT
- AlicenseNot gradedqualityDmaintenanceEnables querying real-time BART and SF Muni transit data, including departures, trip planning, fares, advisories, routes, alerts, vehicle positions, and schedules, from any MCP-compatible client.1MIT