Skip to main content
Glama

sl-mcp

MCP server that lets AI assistants (Claude, Cursor, VS Code) answer questions about Stockholm public transport, using SL's open APIs.

Work in progress.

Tools

Tool

Description

find_stop

TODO

get_departures

TODO

get_disruptions

TODO

Related MCP server: TFL MCP Server for Poke

Getting started

Requires Node.js 20 or later.

npm install
npm run build
npm test
npm run inspect   # opens the MCP Inspector against the built server

Project structure

src/
  index.ts          entry point: serves the server over stdio
  server.ts         createServer(): builds the server and registers the tools
  tools/            one file per tool (schema, description, handler)
    result.ts       helpers for text and error results
  sl/
    client.ts       SlClient: calls SL's APIs and maps responses to our types
    types.ts        Stop, Departure, Disruption
  lib/
    cache.ts        TtlCache
test/
  harness.ts        connects a real MCP client to the server in memory
  fixtures/         recorded API responses

The entry point only wires up stdio. Everything else is built by createServer(), so tests can connect a real MCP client over an in-memory transport without touching stdin/stdout. The tools depend on SlClient, which takes a fetch function, so tests run on recorded responses instead of the live API.

Design decisions

TODO

Data

Data from SL's open APIs via Trafiklab.

Available Tools

3 tools
find_stopFind stopD
Read-only

TODO

NameRequiredDescriptionDefault
limitNoTODO
queryYesTODO: describe for the model, e.g. part of a stop name

TDQS

D1.2/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is partly covered structurally, but the description adds nothing beyond that — no note on matching behavior, ambiguity handling, or result ordering. The placeholder text contributes zero behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The single word "TODO" is a placeholder rather than a concise description. It is not merely terse — it conveys no information and leaves the definition unfinished.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter open-world search tool with no output schema, the description should explain what is searched, what is returned, and how limit affects results. None of that is present; the definition is incomplete at every level.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema declares two parameters with types, a default of 5, and a 1-10 bound for limit, but both parameter descriptions are themselves "TODO" placeholders, including the required query. The tool description adds no meaning on top, so an agent learns nothing about what query accepts (substring, exact name, ID?).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description is the literal placeholder "TODO", so it states no verb, resource, or scope. The only signal of purpose comes from the tool name and the sibling names get_departures/get_disruptions, not from the description itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no mention of alternatives such as get_departures, and no indication of what a valid query looks like. An agent must guess entirely from the name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_departuresGet departuresD
Read-only

TODO

NameRequiredDescriptionDefault
limitNoTODO
siteIdYesTODO: the id returned by find_stop
transportModeNoTODO

TDQS

D1.2/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true and openWorldHint=true, but the description adds zero behavioral context beyond them — no mention of real-time data sourcing, rate limits, freshness, or failure modes when a stop has no service. Since the description is a placeholder, it contributes nothing to the already-thin annotation set.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

"TODO" is a placeholder, not a concise description. Brevity here reflects missing content rather than disciplined editing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter, open-world query tool with no output schema, the description should explain what a departure record contains and how results are ordered or truncated by limit. None of that is present, leaving the definition unusable for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is nominally 100%, but every parameter description is itself "TODO" except the bare hint that siteId is "the id returned by find_stop". The description adds no semantics for limit, transportMode, or siteId, so an agent gets only structural cues (enum values, default 10, max 20) without meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description is the literal string "TODO", so it states nothing about what the tool does. Only the name and title hint at fetching departures, and no scope, format, or distinction from siblings like get_disruptions is given.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no exclusions, and no mention of the sibling tools find_stop or get_disruptions. An agent must infer the entire usage context from the tool name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_disruptionsGet disruptionsD
Read-only

TODO

NameRequiredDescriptionDefault
lineNoTODO: e.g. a line number like 14
transportModeNoTODO

TDQS

D1.2/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is known, but the description adds nothing beyond that — no indication of data freshness, coverage area, pagination, or what a disruption record contains. A placeholder string contributes zero behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

"TODO" is short but not concise — there is no content to be front-loaded or structured. It is an unfilled template rather than a description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter query tool with no output schema, the description must carry the full explanatory burden, and it carries none. An agent has no basis for supplying `line`, choosing a `transportMode`, or interpreting results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description provides no parameter meaning at all. Although the coverage metric reports 100%, both schema descriptions are themselves "TODO" placeholders, so an agent still learns nothing about the expected format of `line` or what filtering by `transportMode` does. Nothing compensates for the effectively empty schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description is the literal placeholder string "TODO", which conveys no verb, resource, or scope. An agent cannot tell from this text what get_disruptions returns or how it differs from siblings like get_departures.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool, when not to, or how it relates to find_stop and get_departures. The placeholder text offers no conditions or alternatives.

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. 3 tool updatesv0.1.0
    • First observedfind_stop
    • First observedget_departures
    • First observedget_disruptions

TDQS

D1.8/5.0

Scored across 3 tools

Disambiguation3/5

The three names imply fairly different targets (a stop lookup, departure boards, and disruption feeds), but all descriptions are literally 'TODO', so an agent has no guidance on parameters or the relationship between them. In particular, whether get_departures takes a stop id from find_stop or accepts free-text is undefined, which invites misselection.

Naming Consistency4/5

All names use a consistent snake_case verb_noun pattern (find_stop, get_departures, get_disruptions). Minor deviation between 'find' and 'get' verbs is the only inconsistency, and it still reads naturally.

Tool Count3/5

Three tools is thin for a public-transport server; a stop lookup, departures, and disruptions are a reasonable minimal core, but the surface feels under-scoped for real transit queries. It is borderline rather than clearly wrong.

Completeness3/5

The set covers the basics of locating a stop, seeing departures, and checking disruptions, but there is no journey/route planning, no nearby-stop search, and no way to resolve a line or destination — all likely gaps for transit workflows. Without descriptions it is impossible to confirm the existing three are sufficient.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that exposes the Deutsche Bahn public transport API to any MCP-compatible client (Claude Desktop, Cursor, Cline, Continue, etc.). Five tools cover station search, departures, journey planning, trip details, and nearby stations.
    6
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to search for stops and stations across all Norwegian public transport and to fetch real-time departure data — planned versus expected times, delays, platform, operator, and disruption messages — with no API key required. Covers bus, tram, metro, train, and ferry nationwide through Entur's open APIs, with filtering by line, destination, and future departure time.
    2
    MIT