About sweden-parliament-mcp-server
An MCP server for querying Swedish parliamentary records from Riksdagen Open Data. It covers documents, speeches, votes, members, and SFS statutes, and runs over stdio or Streamable HTTP.
Key features
- 01Search parliamentary documents and SFS statutes
- 02Read document text and decision details
- 03Find speeches by session and member
- 04Retrieve report and member voting records
- 05Search members and assignment histories
Use cases
- 01Find parliamentary documents by committee or session
- 02Read contributions from parliamentary debates
- 03Check report decisions and party vote totals
- 04Look up a member’s published assignment history
MCP support
Provides MCP clients with seven read-only tools for searching Swedish parliamentary documents, statutes, speeches, votes, and members. Supports stdio and Streamable HTTP.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://sweden-parliament.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-sweden-parliament https://sweden-parliament.caseyjhand.com/mcp{"mcpServers":{"cyanheads-sweden-parliament":{"type":"http","url":"https://sweden-parliament.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-sweden-parliament":{"type":"http","url":"https://sweden-parliament.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-sweden-parliament":{"type":"http","url":"https://sweden-parliament.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-sweden-parliament":{"serverUrl":"https://sweden-parliament.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
7| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Requested entries; values above 100 are clamped with a notice. |
| topic | enum | Yes | Vocabulary or guidance topic to browse.document_types | committees | parties | constituencies | speech_types | sessions | identifiers | coverage |
| offset | integer | No | Zero-based local entry offset. |
Details
From the project README@cyanheads/sweden-parliament-mcp-server
Search Swedish parliamentary documents, speeches, votes, members, and statutes via MCP. STDIO or Streamable HTTP.
Overview
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 or a local Streamable HTTP server; 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.
Tools
| 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, 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 with party main-vote totals 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 |
Capability reference
riksdag_list_reference tool
topic:document_types,committees,parties,constituencies,speech_types,sessions,identifiers, orcoverage- Dated offline snapshot with Swedish labels, available source English labels, source links, and
referenceVerifiedAt; document subtypes remain separate from parent codes, and the session catalog can lag current sessions offsetpagination;limitdefaults to 20 and is clamped to 100, withtotalCountand completenextCallarguments
riksdag_search_documents tool
- Optional
query,documentType,session,committee,party,dateFrom, anddateTo; dates useYYYY-MM-DD, and codes or exact reference labels are accepted - Remote
pagestarts at 1;pageSizedefaults to 10 and is clamped to 50. Every fetched row is returned, with source ordering, availabletotalCount, andnextCall - Use
documentType: "sfs"for consolidated statutes; narrow slow full-text searches withsessionordocumentType
riksdag_get_document tool
- Required
documentIdfrom search, or an unambiguous SFS identifier such as1974:152; missing records returnfound: false - Omit
sectionsfor metadata, the complete outline, and the first text page; selectmetadata,decisions,reservations,activities,properties,attachments,references,text, orsource_html - Text and HTML use Unicode code-point offsets (
textOffset/htmlOffset); lengths default to 1,000 and explicittextLength/htmlLengthvalues are honored. Array sections usesectionOffset/sectionLimit(default 20, maximum applied 100) - Follow
nextTextCall,nextHtmlCall, or eachsectionPages[].nextCall, retainingrevision; changed records fail withrevision_changed. Attachments are links, not downloaded files - SFS
versionKind: "consolidated"describes published consolidated text, which may include future-effective provisions; it is not an as-enacted or point-in-time legal version
riksdag_search_speeches tool
mode: "search"(default) requiressession; optionalmemberId,party, andspeechType: "all" | "speech"narrow the selection, withspeechexcluding repliesheadingContainsmatches all tokens against headings and subheadings, ignoring case and diacritics; it never searches speech body text- Local
offsetpagination;limitdefaults to 5 and is clamped to 20.textCountdefaults to 1, is clamped to 5, and accepts 0 for metadata only mode: "get"requires a retrievalspeechIdcopied from search, notsourceSpeechId; get mode rejects search filters.textOffsetand optionaltextLengthread the whole published body throughnextTextCall; the default text page is 1,000 code pointstextStateisincluded,not_requested,unavailable, orfailed; transient hydration failures include recovery details. Retainrevisionon search or text continuations
riksdag_get_votes tool
- Required
modeandsession;mode: "report"takesreport(designation or session:designation) or a reportdocumentId, whilemode: "member"requiresmemberIdand permitsparty - Report mode returns authoritative decisions and complete party groups. Select one
point, or usepointOffset/pointLimit(default 5, maximum applied 10); member mode usesoffset/limit(default 20, maximum applied 500) - Published main votes only, not every ballot round.
rollCallStateisavailable,acclamation,not_published, orunknown; acclamation requires explicit decision evidence, never merely empty vote rows - Missing aggregate counts remain unknown; additional source vote labels stay in
otherVotes. FollownextCallwithrevisionfor remaining whole points or member rows
riksdag_search_members tool
- Optional
nameContainsmatches all tokens ignoring case and diacritics;partyandconstituencyaccept codes or exact reference labels sitting: "all" | "serving" | "not_serving"defaults toall; this filters source service classification, not verified sitting or elected membership. Historical entries and ministers can appear, and unknown classifications remain inall- Local
offsetpagination;limitdefaults to 20 and is clamped to 100. ReturnscandidateCount, exact filteredtotalCount,revision, andnextCall - Keep leading zeros in
memberId. Some European Parliament entries have no IID and returndetailAvailable: false; theirsourceRecordIdis a different identifier and cannot be used withriksdag_get_member
riksdag_get_member tool
- Required numeric-string
memberIdfrom search, including leading zeros; missing entries returnfound: falsewith guidance - Published register metadata and assignments in source order;
assignmentOffset/assignmentLimitdefault to 0 / 20, with a maximum applied limit of 100 assignmentTotal,nextCall, andrevisionallow complete traversal. Assignment dates retain source precision and do not establish historical sitting status; contact details and photographs are excluded
Features
Built 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:
- Keyless access to official document, speech, vote, and member endpoints, plus dated official reference tables
- Document text as canonical Markdown or SFS source text, with separately selectable original HTML
- Shared upstream concurrency, bounded public-response caching, and one 55-second deadline across queueing, retries, and text hydration
- Historical coverage varies by record type; speeches and votes start in 1993/94, with gaps in older vote data
Agent-friendly output:
- Source attribution, retrieval time, effective filters, and source warnings on both
content[]andstructuredContent - Complete continuation calls for rows, sections, and text, with revision checks on local continuations; a changing remote document search is not a frozen snapshot
- Explicit misses, unavailable text, unknown counts, and source service classifications; candidate saturation fails as
candidate_limit_reachedinstead of returning an incomplete traversal
Getting started
Add the following to your MCP client configuration file.
{
"mcpServers": {
"sweden-parliament-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/sweden-parliament-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"sweden-parliament-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/sweden-parliament-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"sweden-parliament-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/sweden-parliament-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- Riksdagen Open Data requires no API key or account.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/sweden-parliament-mcp-server.git
- Navigate into the directory:
cd sweden-parliament-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env for optional transport, authentication, or logging overrides
Configuration
| 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.
Running the server
Local development
-
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
Project structure
| 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.
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register new tools and resources in the
createApp()arrays insrc/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.