Koskamo

SL – Stockholm public transport MCP

An open-source MCP server that provides real-time Stockholm public transport data via SL's open APIs. It allows AI assistants to search for stops, retrieve live departures with platform and delay info, check for announced disruptions, and plan trips between stops or street addresses, supporting queries in Swedish or English.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

SL – Stockholm public transport MCP logo, by HashtagsmileCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-06Published by Hashtagsmile
MCP endpoint (Streamable HTTP)
https://sl-mcp.miltonlindblad.workers.dev/mcp
Vendor documentation

What its tools do

4 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

4 of 4 have a description · 4 of 4 declare behavior hints · 4 of 4 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search for a public transport stop by name
  • Get live departures from a specific stop
  • Check for announced disruptions on lines
  • Plan a trip between two locations

Source and maintenance

Community listingRegistry 0.2.0
Maintenance checked

Protocol and capabilities

Server
sl-mcp 0.3.0
MCP protocol negotiated in check
2025-11-25
Tools
4 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
2 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "prompts": {
    "listChanged": true
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Answer travel questions like a friend who knows SL, in the user's language. 1. First line: the direct answer. "When must I leave?" -> the time to leave. "How do I get to X?" -> leave HH:MM, arrive HH:MM. 2. Then the best trip as numbered steps, one per leg: time, line and direction, platform or track, where to get on and off, walks with minutes and which exit (uppgång) to use. 3. At most one alternative, in one line, e.g. the next trip if you miss it. The best trip arrives in time with the fewest changes. Use only times and places the tools returned: never guess a walk or a time. For a street address, pass it to plan_trip instead of planning to a nearby stop. Mention delays, disruptions and crowding (few seats, standing only) only if they affect the trip.

Tools

4 advertised

find_stop — Find stop
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Find Stockholm public transport (SL) stops by name and return their ids, names and transport modes. Use it to get the siteId for get_departures, or a stop id for plan_trip. Not for street addresses: pass those to plan_trip as text instead. A name can match several stops ('Arlanda' gives the train station and bus stops): pick by name and modes, or ask the user. Typos are fine, abbreviations are not: write 'Tekniska högskolan', not 'KTH'. Returns one line per stop: '<id>: <town>, <name> (<modes>)'.

find_stop input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "query"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "default": 5,
      "maximum": 10,
      "minimum": 1,
      "description": "Maximum number of stops to return"
    },
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Stop or station name, e.g. 'Slussen' or 'Arlanda'. Typos are fine, abbreviations are not."
    }
  }
}
find_stop annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
get_departures — Get departures
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List live departures from one SL stop, soonest first: line, mode, final destination, direction (1 or 2), platform or bus stop letter, minutes or clock time, delay, cancellation and SL's notes. Use it for 'when does the next X leave from Y'. To get from A to B, use plan_trip; for announced track work or broken lifts, use get_disruptions. Real-time data from SL: at most 3 departures per line and direction, up to 3 hours ahead. `towards` matches the final destination only: for a station on the way (e.g. 'mot T-Centralen' from Slussen), leave it out and pick the direction from the results. An unknown siteId gives no departures, not an error.

get_departures input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "siteId"
  ],
  "properties": {
    "line": {
      "type": "string",
      "description": "Only this line number, e.g. '14' or '43X'"
    },
    "limit": {
      "type": "integer",
      "default": 10,
      "maximum": 30,
      "minimum": 1,
      "description": "Maximum number of departures"
    },
    "siteId": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991,
      "description": "Stop id from find_stop"
    },
    "minutes": {
      "type": "integer",
      "default": 60,
      "maximum": 180,
      "minimum": 1,
      "description": "How many minutes ahead to look, at most 180"
    },
    "towards": {
      "type": "string",
      "description": "Only departures whose final destination contains this, e.g. 'Ropsten'"
    },
    "transportMode": {
      "enum": [
        "METRO",
        "BUS",
        "TRAIN",
        "TRAM",
        "SHIP",
        "FERRY"
      ],
      "type": "string",
      "description": "Only this mode"
    }
  }
}
get_departures annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
get_disruptions — Get disruptions
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List disruptions SL has announced: track work, closed entrances, broken lifts and replacement buses, with the lines affected and until when. Use it to check a line or the stops of a trip before travelling, e.g. lifts for a wheelchair. For live delays and cancelled departures, use get_departures instead. The text is in Swedish, so translate it if needed, and is cut at 800 characters. Results are cached for 1 minute, as SL asks. Leave both filters out to list everything.

get_disruptions input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "lines": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Only these line numbers, e.g. ['13', '14'], or metro colours, e.g. ['grön linje']"
    },
    "transportMode": {
      "enum": [
        "METRO",
        "BUS",
        "TRAIN",
        "TRAM",
        "SHIP",
        "FERRY"
      ],
      "type": "string",
      "description": "Only this mode"
    }
  }
}
get_disruptions annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
plan_trip — Plan trip
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Plan trips by SL public transport between two stops or street addresses, leaving or arriving at a given time. Returns up to 3 trips, plus walking all the way when that takes at most 30 min. Each ride lists line, direction, platform, stops, crowding and delay; each walk lists minutes and the station exit (uppgång). Use it for 'how do I get to X' and 'when must I leave'; for departures from one stop, use get_departures. Addresses are fuzzy matched, so the result starts with what each one matched. Times are Stockholm time. Unknown stops, the same stop twice and times outside the timetable give a clear error. SL cannot plan step-free trips: for a wheelchair or pram, use prefer 'least walking' and check get_disruptions for broken lifts at the stops.

plan_trip input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "from",
    "to"
  ],
  "properties": {
    "to": {
      "anyOf": [
        {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        {
          "type": "string",
          "minLength": 1
        }
      ],
      "description": "Destination: a stop id from find_stop, or a street address"
    },
    "from": {
      "anyOf": [
        {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        {
          "type": "string",
          "minLength": 1
        }
      ],
      "description": "Start: a stop id from find_stop, or a street address like 'Götgatan 76, Stockholm'"
    },
    "time": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$",
      "description": "Stockholm time as YYYY-MM-DDTHH:MM. Leave out to leave now."
    },
    "modes": {
      "type": "array",
      "items": {
        "enum": [
          "commuter train",
          "metro",
          "tram",
          "bus",
          "boat",
          "train"
        ],
        "type": "string"
      },
      "minItems": 1,
      "description": "Only these modes, e.g. ['boat'] for 'by boat'. Leave out for all."
    },
    "prefer": {
      "enum": [
        "fastest",
        "fewest changes",
        "least walking"
      ],
      "type": "string",
      "default": "fastest",
      "description": "What to optimise for: fastest (default), fewest changes or least walking"
    },
    "arriveBy": {
      "type": "boolean",
      "default": false,
      "description": "true: arrive by `time`. false: leave at `time`."
    }
  }
}
plan_trip annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}

Prompts

2 advertised

trip — Plan a trip

Advertised by the server during the last successful anonymous check.

How to get from one place to another by SL, optionally arriving by a given time

from
Start: a stop, station or street address, e.g. 'Sundbyberg' (required)
to
Destination: a stop, station or street address, e.g. 'Götgatan 76' (required)
arriveBy
Arrive by this time, e.g. '09:00' or 'tomorrow 08:30'
departures — Next departures

Advertised by the server during the last successful anonymous check.

The next departures from one SL stop or station

stop
Stop or station, e.g. 'Slussen' (required)

Resources

Not advertised

No resource definitions available.

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (2 of 2 answered).

  1. 2026-11-07: 2 of 2 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
338 ms
95th percentile latency
338 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 338 ms · metadata changed · 4 tool(s), 2 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http sl-stockholm-public-transport-mcp https://sl-mcp.miltonlindblad.workers.dev/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add sl-stockholm-public-transport-mcp --url https://sl-mcp.miltonlindblad.workers.dev/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable sl-stockholm-public-transport-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "sl-stockholm-public-transport-mcp": {
      "url": "https://sl-mcp.miltonlindblad.workers.dev/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "sl-stockholm-public-transport-mcp": {
      "type": "streamableHttp",
      "url": "https://sl-mcp.miltonlindblad.workers.dev/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start sl-stockholm-public-transport-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "sl-stockholm-public-transport-mcp": {
      "type": "http",
      "url": "https://sl-mcp.miltonlindblad.workers.dev/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http sl-stockholm-public-transport-mcp https://sl-mcp.miltonlindblad.workers.dev/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://sl-mcp.miltonlindblad.workers.dev/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "sl-stockholm-public-transport-mcp": {
      "serverUrl": "https://sl-mcp.miltonlindblad.workers.dev/mcp"
    }
  }
}

Let your agent find its tools

Find servers like SL – Stockholm public transport MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.