Search Swedish parliamentary documents, speeches, votes, members, and statutes.
One address for any MCP client. No sign-in needed on this server.
7 read
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Search Swedish parliamentary documents, speeches, votes, members, and statutes via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://sweden-parliament.caseyjhand.com/mcp
Swedish parliamentary records from Riksdagen Open Data. Find proposals and committee reports, follow published decisions and main votes, read speeches, explore member assignments, and retrieve consolidated SFS statutes. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above; no API key required.
Source: The Swedish Parliament. This independent service is not operated or endorsed by Sveriges riksdag. Swedish titles, labels, decisions, and text retain their source wording; English labels appear only where the source supplies them.
| Tool | Description |
|---|---|
riksdag_list_reference | Browse official document types, committees, parties, constituencies, sessions, and identifier and coverage guidance |
riksdag_search_documents | Search parliamentary documents and consolidated SFS statutes by words, type, session, committee, party, member, or dates |
riksdag_get_document | Read publication metadata, decisions, reservations, activities, links, and paginated text |
riksdag_search_speeches | Find speeches within a session by debate heading, member, or party; retrieve full text through get mode |
riksdag_get_votes | Read report decisions, party main-vote totals, individual ballots for a point, or one member's session main votes |
riksdag_search_members | Find register entries by name, party, constituency, and source service classification |
riksdag_get_member | Read an exact member IID and its published assignment history |
riksdag_list_reference tooltopic: document_types, committees, parties, constituencies, speech_types, sessions, identifiers, or coveragereferenceVerifiedAt) with Swedish labels and source-supplied English labels; the session catalog can lag current sessions, and newer well-formed sessions are still acceptedYYYY/YY, consecutive YYYY/YYYY, or a historical calendar year; 1999/00 retains the published 1999/2000 formoffset pagination; limit defaults to 20, clamped to 100, with totalCount and nextCallriksdag_search_documents toolquery, documentType, session, committee, party, memberId, dateFrom, and dateTo; dates use YYYY-MM-DD, and codes or exact reference labels are accepted. memberId selects source-linked participants, without inferring authorshipsort is relevance for a nonblank query and date otherwise; either can be selected explicitly. Source subtitles include available author and SFS consolidation labelspage starts at 1; pageSize defaults to 10 and is clamped to 50. Large pages split into whole-row responses with offset and revision; follow nextCall to finish that remote page before advancing, keeping pageSize fixeddocumentType: "sfs" for consolidated statutes; narrow slow full-text searches with session or documentTyperiksdag_get_document tooldocumentId from search, or an SFS identifier (1974:152, SFS 1974:152, sfs-1974-152); misses return found: false. Omit sections for metadata, the outline, and the first text page, or select from metadata, decisions, reservations, activities, properties, attachments, references, stakeholders, text, source_htmltextOffset / textLength, htmlOffset / htmlLength), starting at 8,000 by default and fitting the complete response. Explicit lengths are honored. Array sections use sectionOffset / sectionLimit (default 20, clamped to 100). Follow nextTextCall, nextHtmlCall, or sectionPages[].nextCall with revision; a changed record fails with revision_changedversionKind: "consolidated") and can include future-effective provisions; it is not an as-enacted or point-in-time version. Attachments are returned as links, never downloadedriksdag_search_speeches toolmode: "search" (default) requires session; optional memberId, party, speechType: "all" | "speech" (speech excludes replies), and headingContains, which matches all tokens in headings and subheadings, never body text. limit defaults to 5 (max 20); textCount defaults to 1 (max 5, 0 for metadata only)mode: "get" reads one speechId copied from a search item (not sourceSpeechId) and pages the body with textOffset / textLength and nextTextCall. Default text pages start at 8,000 code points and fit the complete response; explicit lengths are honoredtextState is included, not_requested, unavailable, or failed, with recovery details on transient failures; retain revision on continuationsfound: false in get mode or textState: "unavailable" during search hydrationriksdag_get_votes toolmode and session. mode: "report" takes report (FiU20 or 2024/25:FiU20) or a report documentId, plus one point or pointOffset / pointLimit (default 5, max 10); mode: "member" takes memberId, optional party, and offset / limit (default 20, max 500)avser; rollCallState is available, acclamation, not_published, or unknown, and acclamation requires explicit decision evidence, never just empty vote rows. Incomplete groups retain unknown counts and observed labels; extra vote labels land in otherVotespoint, ballots: true adds individual votes and independent ballotPage pagination using offset / limit. Follow ballotPage.nextCall with both revision and ballotRevision; report-point counts keep their existing meaningnextCall with revision for remaining points or rowsriksdag_search_members toolregister: "service" (default) searches current members plus recent former members, substitutes, and ministers; register: "all" includes earlier records. A cold all-register request is substantially larger and can reach the normal timeoutnameContains matches all tokens as substrings, ignoring case and diacritics. party and constituency accept codes or exact labels. sitting: "all" | "serving" | "not_serving" (default all) filters source service labels, including serving substitutes, without establishing elected membershipoffset pagination; limit defaults to 20, clamped to 100. Returns actual candidateCount, filtered totalCount, sourceReportedCount, revision, and nextCall. Source-reported hits can differ from returned all-register records; a notice discloses this, and neither count is an independent historical censusmemberId keeps leading zeros. Entries without an IID return detailAvailable: false; their sourceRecordId is a different identifier and can't be passed to riksdag_get_memberriksdag_get_member toolmemberId, leading zeros included; copy it from a member search result with detailAvailable: true. Misses return found: false with guidanceassignmentOffset / assignmentLimit default to 0 / 20 (max 100), with assignmentTotal, nextCall, and revisionBuilt 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.
Riksdag-specific:
Agent-friendly output:
content[] and structuredContentcandidate_limit_reached instead of returning an incomplete traversalConnect to the hosted instance, no install:
claude mcp add --transport http sweden-parliament-mcp-server https://sweden-parliament.caseyjhand.com/mcp
Or run it locally:
claude mcp add sweden-parliament-mcp-server -- npx -y @cyanheads/sweden-parliament-mcp-server
For other MCP clients, add this to your configuration:
{
"mcpServers": {
"sweden-parliament-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/sweden-parliament-mcp-server"]
}
}
}
Riksdagen Open Data requires no API key or account. For Docker or a source build, see Running the server.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for every server setting and the common framework overrides.
Requires Bun v1.4.0 or higher (or Node.js v24+).
git clone https://github.com/cyanheads/sweden-parliament-mcp-server.git
cd sweden-parliament-mcp-server && bun install
cp .env.example .env
The environment file is optional; edit it for transport, authentication, or logging overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
docker run --rm -p 3010:3010 ghcr.io/cyanheads/sweden-parliament-mcp-server:latest
The image uses stateless HTTP and writes logs to /var/log/sweden-parliament-mcp-server. For stdio, use docker run -i --rm -e MCP_TRANSPORT_TYPE=stdio ghcr.io/cyanheads/sweden-parliament-mcp-server:latest as the client launch command. Build locally with docker build -t sweden-parliament-mcp-server .; add --build-arg OTEL_ENABLED=false to omit the optional OpenTelemetry dependencies.
| Directory | Purpose |
|---|---|
src/index.ts | Registers seven tools, initializes the service, and selects stateless HTTP sessions. |
src/mcp-server/tools/definitions | Seven read-only tool definitions; no resources or prompts. |
src/services/riksdag | Riksdagen endpoint parsing, reference tables, transport, cache, text conversion, and continuation. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
See docs/tree.md for the full file tree.
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.state for storagecreateApp() arrays in src/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.