Switzerland Parliament MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Switzerland Parliament MCP Serversearch parliamentary business about the Alpine solar initiative"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://switzerland-parliament.caseyjhand.com/mcp
Overview
Swiss Federal Assembly records from Curia Vista and the Amtliches Bulletin. Find parliamentary business, read its original texts and procedural history, follow the debate in either council, inspect Nationalrat roll calls, and look up members and declared interests. Uses the public OData service without an API key; runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Results credit Parlamentsdienste der Bundesversammlung, Bern, with source URLs and download dates. This is an unofficial reproduction. The Parliament's open-data conditions apply to source content; underlying author rights remain intact.
Tools
Tool | Description |
| Find business by title, submitter, type, status, submission session, dates, or committee role |
| Read business metadata, original texts, status history, bills, related business, committee consultations, or debate subjects |
| Find Nationalrat roll calls, page member decisions, or read complete vote and parliamentary-group counts |
| Find debate passages by business, subject, speaker, session, council, or dates; retrieve original text |
| Find current or former parliamentary affiliation records by name, council, canton, party, or group |
| Read parliamentary identity, council terms, committee memberships, or declared interests |
| Resolve identifiers, coverage, languages, codes, committees, and sessions |
Related MCP server: cern-opendata-mcp-server
Capability reference
chparl_search_business tool
query(title substring),author(published submitter label, not every co-signatory),typeId,statusId,sessionId(submission session),committeeId, and inclusivesubmittedFrom/submittedTo. Newest business IDs first, default 20/max 100Continue with
nextCursorand unchanged filters; a cursor from other filters fails asinvalid_cursor.totalCountis reported only without author or committee filters. Author searches use an extra matching row to establish continuation; committee searches page role candidates, so pages can be short
chparl_get_business tool
Canonical eight-digit
businessIdor an exact published short number such as99.1234. A short number matching several businesses fails asambiguous_business_number, and a miss returnsfound: falseoverview(default) returns metadata andavailableTextFieldswith UTF-8 sizes.textsreturnstextDocument.kind: "full" | "outline": several large fields become an outline, and namedtextFieldsalways return wholestatus_history,bills,related_business,preconsultations, andsubjectspage independently, default 20/max 100 withnextOffset.subjectsIDs narrowchparl_search_transcripts; linked bills are parliamentary records, not enacted law
chparl_get_votes tool
mode: "votes"withbusinessId,sessionId, or both lists roll calls (default 10/max 50). A returnedvoteIdfeedsmode: "members"(default 50/max 100, optionalpersonNumber) ormode: "groups"(unpaged). Paged modes continue withnextOffsetmode: "members"withpersonNumberand novoteIdpages that member's voting history, optionally narrowed bybusinessIdandsessionId. Each history row carries its published vote, business, session, and time fields; selected-vote pages carry that context once invote.cantonIduses the canton reference's numbering;votingCantonIdpreserves the source Voting identifiermemberscounts carrydecisionCounts.scope: "page".groupsreads every published member row and returnsscope: "vote",complete: true, and per-group totals by the affiliation recorded on the vote. Count buckets retain every distinct published label indecisionTexts. Decision codes: 1 yes, 2 no, 3 abstention, 4 present, 5 did not participate, 6 excused under Art. 57 para. 4, 7 president does not vote, 8 resignedNationalrat only, from the 2003 winter session. An empty result does not establish that no vote occurred
chparl_search_transcripts tool
Both councils from the 1999 winter session. Scope with
businessIdorsubjectId(exclusive),personNumber,sessionId, or a date bound;councilonly narrows.query(original-text substring) also needssessionIdor a closed range of at most 31 calendar daysMetadata with
textSizeBytesby default (20/max 100);includeText: truereturns whole passages (3/max 10); an exacttranscriptIddefaults to full text. Continue withnextOffsetA business search covers up to 20 debate subjects; more fails as
business_scope_too_broad, so pagechparl_get_businesssectionsubjectsand pass onesubjectId.foundmarks exact-ID misses,scopeFounda missing business
chparl_search_members tool
query(first, last, or official name substring),membership(currentdefault,former,all),council(N/Sor the German, French, or Italian council name),cantonId,partyId,groupId. Default 20/max 100,nextOffsetRows are MemberCouncil affiliation records, not deduplicated people. Their
personNumber, which need not equalPerson.ID, feedschparl_get_member,chparl_get_votes, andchparl_search_transcripts
chparl_get_member tool
Requires
personNumber.overview(default) returns identity and every MemberCouncil affiliation, unpaged; a miss returnsfound: falsecouncil_terms,committees, andinterestspage independently, default 20/max 100 withnextOffset. Committee rows are published memberships, not a historical ledger. A missingpaidflag means unknown, and empty interests do not establish the absence of conflicts
chparl_list_reference tool
Static topics
identifiers,coverage,languages, andstatuses(the official vocabulary effective 1 July 2023, each code taggedera: "legacy" | "current"). Live dictionariesbusiness_types,councils,cantons,parties,groups,committees, andsessionsDefault 50/max 100,
nextOffset. Onlysessionsaccepts dates:dateFrombounds the start anddateTothe end, inclusively
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.
Swiss Parliament-specific:
Keyless, read-only access to business, procedural relationships, Nationalrat roll calls, debate passages, members, and declared interests
de(default),fr, anditmetadata with no translation fallback; Italian completeness is not established. Bulletin text stays in the language the speaker usedPublished text and HTML are returned unchanged, with an index of their links and images carrying absolute HTTP(S) URLs where the source supplies one
One 45-second deadline per complete workflow, covering joins and retries
Agent-friendly output:
Provenance on every result: attribution to Parlamentsdienste der Bundesversammlung, plus the source URL and retrieval time of each upstream response
Whole-record pages: replies fit a 24,000-byte budget by returning fewer records, never shorter fields, and report
returnedCount,hasMore,totalCountwhen known, and the continuationOne record on both surfaces:
content[]carries everystructuredContentfield, with multiline text and HTML in JSON-encoded fenced blocks that decode back losslesslyUnknown stays unknown: absent source values are omitted rather than defaulted, empty results carry next-step guidance, and failures carry typed reasons such as
upstream_rate_limited
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http switzerland-parliament-mcp-server https://switzerland-parliament.caseyjhand.com/mcpOr run it locally:
claude mcp add switzerland-parliament-mcp-server -- npx -y @cyanheads/switzerland-parliament-mcp-serverFor other clients, add this to the MCP config file:
{
"mcpServers": {
"switzerland-parliament-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/switzerland-parliament-mcp-server"]
}
}
}For Docker or a source build, see Running the server.
Configuration
No server-specific environment variables are required.
Variable | Description | Default |
| Transport: |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry. |
|
See .env.example for the common framework overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
git clone https://github.com/cyanheads/switzerland-parliament-mcp-server.git
cd switzerland-parliament-mcp-server
bun install
cp .env.example .envBuild and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdioRun checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Docker
docker run --rm -p 3010:3010 ghcr.io/cyanheads/switzerland-parliament-mcp-server:latestThe image defaults to HTTP transport, stateless sessions, and logs to /var/log/switzerland-parliament-mcp-server. For stdio, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/switzerland-parliament-mcp-server:latest"]. Build locally with docker build -t switzerland-parliament-mcp-server .; --build-arg OTEL_ENABLED=false omits OpenTelemetry peers.
Project structure
Directory | Purpose |
|
|
| Tool definitions, shared lossless rendering, and whole-record page fitting. |
| OData client, workflow deadlines, domain schemas and services, provenance, and reference snapshots. |
| Unit and integration tests, mirroring the |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor logging,ctx.statefor storageRegister new tools and resources in the
createApp()arrays insrc/index.tsWrap 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 testLicense
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Search Swiss federal legislation: laws, articles, amendments via the Fedlex SPARQL endpoint.
Query FDA data on drugs, food, devices, and recalls via openFDA. STDIO or Streamable HTTP.
Track Canadian federal bills, MPs, House votes, and Hansard speeches.
Search MPs and Lords, fetch profiles, synopses, and Westminster constituencies
Related MCP Servers
- AlicenseAqualityAmaintenanceAn MCP server connecting AI models to the Swiss Federal Parliament via the Curia Vista OData API, enabling queries of motions, votes, members, sessions, and debate transcripts without authentication.760 PyPI2MIT
- AlicenseNot gradedqualityAmaintenanceEnables searching and exploring CERN Open Data records, files, analysis environments, CMS validated-run (good-run) lists, and HLT trigger paths through MCP tools. Supports exact-vocabulary filtering with live facet counts, license and citation retrieval, and runs over stdio or Streamable HTTP.250 npm1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables tracking of Canadian federal parliamentary records by searching bills, members, House divisions, and indexed Hansard speeches, then retrieving detailed dossiers, profiles, tallies, and full speech text from official public sources. Runs over STDIO or Streamable HTTP with no API key required.57 npm1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables discovery and retrieval of European Parliament procedures, MEPs, plenary votes, documents, speeches, and questions from the Open Data API over STDIO or Streamable HTTP.479 npm1Apache 2.0