Trafikverket 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., "@Trafikverket MCP ServerShow me the next departures from Stockholm Central"
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.
Trafikverket MCP Server
MCP server for Trafikverket (the Swedish Transport Administration) open traffic data: live train departures and arrivals, railway disruptions, road incidents and measured road weather. Built on Trafikverket's open Trafikinfo API.
Features
search_stations - Find train stations by name or location signature
get_train_announcements - Live departures or arrivals at a station, with delays, platforms and cancellations
get_train_messages - Current railway traffic messages (track work, faults, disruptions), optionally per county
get_road_situations - Current road incidents: accidents, road works, obstacles and restrictions, by county and/or around a point
get_road_weather - Measured road weather (air and road surface temperature, wind, grip, precipitation) from the nearest roadside stations
Related MCP server: DB Timetable MCP Server
Coverage
Sweden only (Trafikverket's state road and railway network).
Requirements
A free Trafikverket API key. Create one in the Trafikverket data portal and provide it to the server in the TRAFIKVERKET_API_KEY environment variable. The server starts without a key, but every tool returns an error until one is set.
Installation
Claude Code
Add to your Claude Code settings (~/.claude/settings.json):
{
"mcpServers": {
"trafikverket": {
"command": "node",
"args": ["/path/to/trafikverket-mcp-server/dist/index.js"],
"env": {
"TRAFIKVERKET_API_KEY": "your-api-key"
}
}
}
}Claude Desktop
Add the same trafikverket entry under mcpServers in claude_desktop_config.json.
Build from source
npm install
npm run buildUsage Examples
Next departures from Stockholm Central
Tool: get_train_announcements
Input: { "station": "Stockholm", "hoursAhead": 2 }Arrivals in Göteborg, including trains that arrived 30 minutes ago
Tool: get_train_announcements
Input: { "station": "Göteborg C", "direction": "arrivals", "minutesBack": 30 }Find the exact station before querying
Tool: search_stations
Input: { "query": "Hässleholm" }Railway disruptions in Skåne
Tool: get_train_messages
Input: { "county": "Skåne" }Accidents within 30 km of Gothenburg
Tool: get_road_situations
Input: { "latitude": 57.7089, "longitude": 11.9746, "radiusKm": 30, "messageType": "Olycka" }Road weather near Skövde
Tool: get_road_weather
Input: { "latitude": 58.3912, "longitude": 13.8453 }API Reference
search_stations
Find train stations by name (diacritics and case are ignored) or location signature.
Parameter | Type | Required | Default | Description |
query | string | Yes | - | Station name, part of a name, or signature |
limit | number | No | 10 | 1-25 |
latitude | number | No | - | With longitude: include distance to each match |
longitude | number | No | - | With latitude: include distance to each match |
Returns name, signature, shortName, counties, coordinates and optionally distanceKm per station.
get_train_announcements
Live departures or arrivals at one station. Accepts a station name or a location signature; an ambiguous name returns an error listing the candidates (a bare city name such as "Stockholm" resolves to the central station "Stockholm C").
Parameter | Type | Required | Default | Description |
station | string | Yes | - | Station name or location signature |
direction | string | No |
|
|
minutesBack | number | No | 15 | 0-120, minutes before now to include |
hoursAhead | number | No | 2 | 0.25-12, hours after now to include |
limit | number | No | 25 | 1-100 |
Returns per train: train number, operator, product, origin and destination names, track, advertised/estimated/actual time, delayMinutes (positive = late), canceled, deviation notes and other information.
get_train_messages
Current railway traffic messages (Trafikverket operative events): track work, faults and other disruptions.
Parameter | Type | Required | Default | Description |
county | string / number | No | - | County name (e.g. |
activeOnly | boolean | No | true | Only ongoing events |
limit | number | No | 20 | 1-100 |
Returns event type, header, description (when a public message has been published), start/end/expected end, and the affected stations and sections.
get_road_situations
Current incidents on the state road network.
Parameter | Type | Required | Default | Description |
county | string / number | No | - | County name or code |
latitude | number | No | - | Center of a radius search (requires longitude) |
longitude | number | No | - | Center of a radius search (requires latitude) |
radiusKm | number | No | 25 | 0.5-200 |
messageType | string | No | - | Swedish message type as used by Trafikverket, e.g. |
limit | number | No | 25 | 1-100 |
Results are ordered by severity (code 1-5, higher is more severe), then distance. Each entry has message, type, severity, road number and name, location, start/end time, restrictions and coordinates.
get_road_weather
Observations from the nearest roadside weather stations (not a forecast).
Parameter | Type | Required | Default | Description |
latitude | number | Yes | - | -90 to 90 |
longitude | number | Yes | - | -180 to 180 |
radiusKm | number | No | 25 | 1-100 |
limit | number | No | 3 | 1-20 nearest stations |
Returns per station: name, distance, sample time, air temperature (°C), humidity (%), dew point (°C), visibility (m), wind (m/s, degrees), road surface temperature (°C), grip, ice/snow/water flags, and precipitation and wind over the last 10 minutes.
Development
npm install
npm run typecheck
npm test
npm run buildTests mock fetch and run against JSON fixtures, so no API key is needed.
Data Source
Data from Trafikverket's open Trafikinfo API, published as open data (CC0 according to the API documentation). Please check Trafikverket's current terms before redistributing data at scale.
License
MIT
Available Tools
5 toolsget_road_situationsARead-onlyIdempotent
Get current road incidents and disruptions on the Swedish state road network: accidents, road works, obstacles, restrictions and traffic messages, each with severity (code 1-5, higher is more severe), road number, location, start/end time and coordinates. Filter by county and/or by a point plus radius (latitude, longitude, radiusKm); results are ordered by severity, then distance. Message types are Swedish, e.g. "Olycka" (accident) and "Vägarbete" (road work). Use get_road_weather for measured road conditions instead. Returns an error result (isError: true) if TRAFIKVERKET_API_KEY is missing/invalid or the Trafikverket API is unreachable. Coverage: Sweden only (Trafikverket data).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of situations to return (1-100) | |
| county | No | Optional county filter: Swedish county name (e.g. "Stockholm", "Västra Götaland") or code (e.g. 14) | |
| latitude | No | Optional latitude of a point to search around (use together with longitude) | |
| radiusKm | No | Search radius in kilometres around latitude/longitude (0.5-200, default 25) | |
| longitude | No | Optional longitude of a point to search around (use together with latitude) | |
| messageType | No | Optional message type filter, in Swedish as used by Trafikverket, e.g. "Olycka" (accident) or "Vägarbete" (road work) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/open-world, and the description adds real value beyond them: severity scale 1-5 with direction, result ordering, Swedish-language message types, and a failure mode (isError: true when TRAFIKVERKET_API_KEY is missing/invalid or the API is unreachable). Missing only pagination/truncation behavior for the limit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then filters, ordering, language note, sibling routing, error behavior, and coverage in a logical order. It is dense but nearly every sentence adds information; the Swedish example types slightly repeat the schema's messageType description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still lists the returned fields (severity, road number, location, start/end time, coordinates) and explains the error shape, so an agent knows both what comes back and how failures surface. Nothing material is missing for a 6-optional-param read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds semantics the schema does not: the county and point filters can be combined, and results are ordered by severity then distance, which tells the agent what `limit` actually truncates. The Swedish message-type examples duplicate the schema field slightly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Get current road incidents and disruptions on the Swedish state road network') and enumerates the exact content types covered. It explicitly separates itself from the sibling get_road_weather and states geographic coverage, so an agent can identify it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative ('Use get_road_weather for measured road conditions instead') and the condition that selects it, and states the geographic exclusion ('Sweden only'). Filter combinations (county and/or point+radius) are described as usage guidance rather than left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_road_weatherARead-onlyIdempotent
Get measured road weather from Trafikverket's roadside stations nearest to a point: air temperature (°C), humidity (%), dew point (°C), visibility (m), wind speed (m/s) and direction (degrees), road surface temperature (°C), grip, ice/snow/water on the road, and precipitation and wind over the last 10 minutes. These are actual observations, not a forecast; use a forecast source such as SMHI for future weather. Returns an error result (isError: true) if TRAFIKVERKET_API_KEY is missing/invalid or the Trafikverket API is unreachable. Coverage: Sweden only (Trafikverket data).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of nearest stations to return (1-20, default 3) | |
| latitude | Yes | Latitude of the point to find road weather stations near | |
| radiusKm | No | Search radius in kilometres (1-100, default 25) | |
| longitude | Yes | Longitude of the point to find road weather stations near |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, open-world semantics, and the description adds context the annotations cannot convey: an error result (isError: true) when TRAFIKVERKET_API_KEY is missing/invalid or the upstream API is unreachable, plus Sweden-only coverage and a 10-minute observation window. This is exactly the operational detail an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences with zero filler: what it returns, the observations-vs-forecast distinction, then failure modes and coverage. The core capability is front-loaded before the caveats.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description effectively enumerates the returned fields and their units, and it documents error behavior and geographic coverage. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with min/max bounds and defaults documented for latitude, longitude, radiusKm and limit. The description only restates the point-anchored nature of the query and adds no format or tuning guidance beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Get measured road weather'), the data source (Trafikverket roadside stations), and the anchoring parameter ('nearest to a point'). It then enumerates the exact measurements returned, so an agent knows precisely what it gets without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames when NOT to use it: 'These are actual observations, not a forecast; use a forecast source such as SMHI for future weather.' That is a real routing rule. It does not reference the sibling tools (search_stations, get_road_situations), so a small amount of alternative-selection guidance is missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_train_announcementsARead-onlyIdempotent
Get live train departures or arrivals at a Swedish station: train number, operator, product (e.g. "Pendeltåg"), origin/destination, platform (track), advertised vs. estimated/actual time, delay in minutes, cancellation and deviation notes. Accepts a station name (e.g. "Göteborg C", "Stockholm") or a location signature; an ambiguous name returns an error listing the candidates. Covers a window from minutesBack before now to hoursAhead after now. Use get_train_messages for broader disruption notices (track work, faults) instead of per-train data. Times are ISO 8601, delays in minutes (positive = late). Returns an error result (isError: true) if TRAFIKVERKET_API_KEY is missing/invalid or the Trafikverket API is unreachable. Coverage: Sweden only (Trafikverket data).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of trains to return (1-100) | |
| station | Yes | Station name (e.g. "Göteborg C", "Stockholm") or location signature (e.g. "G", "Cst") | |
| direction | No | "departures" (default) or "arrivals" at the station | departures |
| hoursAhead | No | How many hours ahead of now to include (0.25-12) | |
| minutesBack | No | How many minutes back from now to include, so just-left or delayed trains show up (0-120) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent/openWorld annotations, it discloses error semantics (isError: true when TRAFIKVERKET_API_KEY is missing/invalid or the API is unreachable), ambiguity handling, data-source coverage, and output conventions (ISO 8601 times, positive delays = late). This is the kind of operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then scope, alternative, formats, and error behavior. Dense and mostly waste-free, though the long field enumeration in the first sentence is the least essential part of the definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, no-output-schema query tool, it covers everything an agent needs: what it returns, input flexibility, ambiguity failure mode, time window semantics, format conventions, auth failure behavior, and geographic coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description adds real value by restating that 'station' accepts a name or location signature and that ambiguous names fail rather than guess, and by framing minutesBack/hoursAhead as the overall query window. It does not add format details for limit or direction, which the schema already covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource + scope: 'Get live train departures or arrivals at a Swedish station', followed by an enumerated set of returned fields (train number, operator, product, platform, delay, cancellations). It is clearly distinguishable from siblings because it names get_train_messages as the different tool for disruption notices.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'Use get_train_messages for broader disruption notices (track work, faults) instead of per-train data', and states the coverage boundary 'Sweden only'. It also tells the agent what happens with an ambiguous station name (error listing candidates), which pre-empts a common misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_train_messagesARead-onlyIdempotent
Get current railway traffic messages from Trafikverket: track work, technical faults and other disruptions, with event type, header, description, start/expected end time, and the affected stations/sections. Optionally filter by county. Use this for "is there a disruption on the railway" questions; use get_train_announcements for per-train timetable and delay data. Returns an error result (isError: true) if TRAFIKVERKET_API_KEY is missing/invalid or the Trafikverket API is unreachable. Coverage: Sweden only (Trafikverket data).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of messages to return (1-100) | |
| county | No | Optional county filter: Swedish county name (e.g. "Skåne", "Västra Götaland") or county code (e.g. 14) | |
| activeOnly | No | Only include messages that have not ended yet (default true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safe read-only profile, but the description adds valuable behavioral context: the required TRAFIKVERKET_API_KEY error condition and Sweden-only coverage. It does not discuss rate limits or ordering, which keeps it from a 5, but it meaningfully exceeds the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, then usage guidance, error behavior, and coverage. Every sentence contributes useful information, and the return field list is warranted because no output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, optional-parameter listing tool with no output schema, the description covers purpose, return contents, alternative tools, auth failure behavior, and geographic coverage. Nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all parameters are already documented. The description only mentions the optional county filter, adding little beyond what the schema provides, which makes the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get current railway traffic messages from Trafikverket') and enumerates the disruption types and returned fields. It explicitly contrasts itself with get_train_announcements, so an agent can distinguish it from a sibling without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit use case ('is there a disruption on the railway') and names the alternative tool for per-train timetable and delay data. The geographic scope and county filter are also clearly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_stationsARead-onlyIdempotent
Find Swedish train stations by name or location signature. Returns each station's display name, location signature (the short code used by the other train tools, e.g. "Cst" for Stockholm Central), county codes and coordinates; pass latitude/longitude to also get the distance to each match. Use this to look up the exact station before calling get_train_announcements when a name is ambiguous. Returns an error result (isError: true) if TRAFIKVERKET_API_KEY is missing/invalid or the Trafikverket API is unreachable. Coverage: Sweden only (Trafikverket data).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of stations to return (1-25) | |
| query | Yes | Station name or part of it (e.g. "Göteborg", "Lund"), or a location signature (e.g. "Cst") | |
| latitude | No | Optional: latitude, to include distance to each match | |
| longitude | No | Optional: longitude, to include distance to each match |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent safety, but the description adds what the annotations cannot: the returned fields, that passing latitude/longitude adds distance to each match, and that failures surface as isError: true for a missing/invalid TRAFIKVERKET_API_KEY or an unreachable API. That is substantial context beyond structured data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, and each subsequent clause carries real information (return shape, distance option, error behavior, coverage). It is dense but slightly long; the return-field enumeration could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still explains the result shape, the optional distance enrichment, error semantics, and the auth prerequisite. Nothing an agent needs to call it correctly and interpret failures is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented. The description explains the latitude/longitude distance behavior but only repeats what the schema says and never addresses `limit`, so it adds little over the schema — baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Find Swedish train stations') plus the two lookup keys (name or location signature) and the geographic scope. An agent can distinguish it from the announcement/message/road siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use rule — 'look up the exact station before calling get_train_announcements when a name is ambiguous' — naming the downstream sibling. The 'Coverage: Sweden only' line and the API-key error note act as clear boundary conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
get_road_situations - First observed
get_road_weather - First observed
get_train_announcements - First observed
get_train_messages - First observed
search_stations
TDQS
Scored across 5 tools
Each tool targets a distinct resource: station lookup, per-train departures/arrivals, railway disruption messages, road incidents, and road weather observations. Descriptions explicitly disambiguate the closest pairs (train announcements vs. train messages, road situations vs. road weather) with 'use X instead' guidance.
All five tools use snake_case verb_noun form with a clear resource suffix (search_stations, get_train_announcements, get_train_messages, get_road_situations, get_road_weather). The single 'search_' prefix is appropriate for a name-matching lookup rather than a minor inconsistency.
Five tools is a tight, well-scoped surface that mirrors the Trafikverket domains it exposes (stations, trains, rail messages, roads, road weather). No redundant or filler tools; each covers a distinct query type.
Core live-traffic coverage is solid, but there are minor gaps: no station-to-station journey/timetable search, no filtering of rail messages by station or train, and no other Trafikverket data types (e.g. road cameras, ferries). Agents can work around these using announcements plus messages.
Maintenance
Related MCP Connectors
Riksdagen (Swedish Parliament) open data MCP.
Experimental MCP exploring Statistics Finland PxWeb statistical datasets.
Swiss Transport MCP — wraps Transport Open Data API (free, no auth)
Finland Open Data (www.avoindata.fi/data/en) CKAN MCP.
Related MCP Servers
- AlicenseAqualityCmaintenanceProvides real-time access to Swedish road weather, traffic cameras, road conditions, and traffic flow data from Trafikverket (Swedish Transport Administration). Enables users to query weather stations, cameras, traffic situations, and flow data through natural language.10MIT
- AlicenseAqualityDmaintenanceProvides access to Deutsche Bahn's timetable data through MCP, enabling real-time train schedules, station search, and change tracking for German railway stations.460 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables querying Swiss public transport data (stations, departures, connections) from the Transport Open Data API via natural language through an MCP gateway.9 npmMIT
- AlicenseAqualityAmaintenanceEnables AI assistants to access Swiss public transport data including journey planning, real-time departures, disruptions, occupancy forecasts, ticket prices, and train formations via a standardized MCP interface.1146 PyPI8MIT