Skip to main content
Glama

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 build

Usage 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

departures

departures or arrivals

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. "Skåne") or code (e.g. 12)

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. "Olycka", "Vägarbete"

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 build

Tests 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 tools
get_road_situationsA
Read-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).

NameRequiredDescriptionDefault
limitNoMaximum number of situations to return (1-100)
countyNoOptional county filter: Swedish county name (e.g. "Stockholm", "Västra Götaland") or code (e.g. 14)
latitudeNoOptional latitude of a point to search around (use together with longitude)
radiusKmNoSearch radius in kilometres around latitude/longitude (0.5-200, default 25)
longitudeNoOptional longitude of a point to search around (use together with latitude)
messageTypeNoOptional message type filter, in Swedish as used by Trafikverket, e.g. "Olycka" (accident) or "Vägarbete" (road work)

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_weatherA
Read-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).

NameRequiredDescriptionDefault
limitNoNumber of nearest stations to return (1-20, default 3)
latitudeYesLatitude of the point to find road weather stations near
radiusKmNoSearch radius in kilometres (1-100, default 25)
longitudeYesLongitude of the point to find road weather stations near

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_announcementsA
Read-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).

NameRequiredDescriptionDefault
limitNoMaximum number of trains to return (1-100)
stationYesStation name (e.g. "Göteborg C", "Stockholm") or location signature (e.g. "G", "Cst")
directionNo"departures" (default) or "arrivals" at the stationdepartures
hoursAheadNoHow many hours ahead of now to include (0.25-12)
minutesBackNoHow many minutes back from now to include, so just-left or delayed trains show up (0-120)

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_messagesA
Read-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).

NameRequiredDescriptionDefault
limitNoMaximum number of messages to return (1-100)
countyNoOptional county filter: Swedish county name (e.g. "Skåne", "Västra Götaland") or county code (e.g. 14)
activeOnlyNoOnly include messages that have not ended yet (default true)

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_stationsA
Read-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).

NameRequiredDescriptionDefault
limitNoMaximum number of stations to return (1-25)
queryYesStation name or part of it (e.g. "Göteborg", "Lund"), or a location signature (e.g. "Cst")
latitudeNoOptional: latitude, to include distance to each match
longitudeNoOptional: longitude, to include distance to each match

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 5 tool updatesv0.1.0
    • First observedget_road_situations
    • First observedget_road_weather
    • First observedget_train_announcements
    • First observedget_train_messages
    • First observedsearch_stations

TDQS

A4.7/5.0

Scored across 5 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Provides 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.
    10
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Provides access to Deutsche Bahn's timetable data through MCP, enabling real-time train schedules, station search, and change tracking for German railway stations.
    4
    60 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying Swiss public transport data (stations, departures, connections) from the Transport Open Data API via natural language through an MCP gateway.
    9 npm
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables 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.
    11
    46 PyPI
    8
    MIT