io.github.cyanheads/switzerland-parliament-mcp-server

Official registry Government and legal

Search Swiss parliamentary business, votes, debates, members, and declared interests.

What can you do with io.github.cyanheads/switzerland-parliament-mcp-server?

  • Keyless, read-only access to business, procedural relationships, Nationalrat roll calls, debate passages, members, and declared interests
  • de (default), fr, and it metadata with no translation fallback; Italian completeness is not established. Bulletin text stays in the language the speaker used
  • Published 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
  • 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, totalCount when known, and the continuation
  • One record on both surfaces: content[] carries every structuredContent field, with multiline text and HTML in JSON-encoded fenced blocks that decode back losslessly
  • Unknown 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

Install

Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).

Remote (streamable-http)
Claude Code
claude mcp add --transport http switzerland-parliament-mcp-server 'https://switzerland-parliament.caseyjhand.com/mcp'
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "switzerland-parliament-mcp-server": {
            "type": "http",
            "url": "https://switzerland-parliament.caseyjhand.com/mcp"
        }
    }
}
NPM package @cyanheads/switzerland-parliament-mcp-server
Claude Code
claude mcp add switzerland-parliament-mcp-server -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/switzerland-parliament-mcp-server@0.1.2
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "switzerland-parliament-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/switzerland-parliament-mcp-server@0.1.2"
            ],
            "env": {
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

Environment variables

  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').
NPM package @cyanheads/switzerland-parliament-mcp-server
Claude Code
claude mcp add switzerland-parliament-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/switzerland-parliament-mcp-server@0.1.2
JSON configuration (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "switzerland-parliament-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/switzerland-parliament-mcp-server@0.1.2"
            ],
            "env": {
                "MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
                "MCP_HTTP_HOST": "127.0.0.1",
                "MCP_HTTP_PORT": "3010",
                "MCP_HTTP_ENDPOINT_PATH": "/mcp",
                "MCP_AUTH_MODE": "none",
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

Environment variables

  • MCP_TRANSPORT_TYPE Selects the HTTP transport.
  • MCP_HTTP_HOST The hostname for the HTTP server.
  • MCP_HTTP_PORT The port to run the HTTP server on.
  • MCP_HTTP_ENDPOINT_PATH The endpoint path for the MCP server.
  • MCP_AUTH_MODE Authentication mode to use: 'none', 'jwt', or 'oauth'.
  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').

Documentation

From the project's README on GitHub, refreshed weekly. Links open on GitHub.

Contents
  1. @cyanheads/switzerland-parliament-mcp-server
  2. Overview
  3. Capability reference
  4. Features
  5. Getting started
  6. Configuration
  7. Running the server
  8. Project structure
  9. Development guide
  10. Contributing
  11. License

@cyanheads/switzerland-parliament-mcp-server

Search Swiss parliamentary business, votes, debates, members, and declared interests via MCP. STDIO or Streamable HTTP.

7 Tools • 0 Resources • 0 Prompts

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
ToolDescription
chparl_search_businessFind business by title, submitter, type, status, submission session, dates, or committee role
chparl_get_businessRead business metadata, original texts, status history, bills, related business, committee consultations, or debate subjects
chparl_get_votesFind Nationalrat roll calls, page member decisions, or read complete vote and parliamentary-group counts
chparl_search_transcriptsFind debate passages by business, subject, speaker, session, council, or dates; retrieve original text
chparl_search_membersFind current or former parliamentary affiliation records by name, council, canton, party, or group
chparl_get_memberRead parliamentary identity, council terms, committee memberships, or declared interests
chparl_list_referenceResolve identifiers, coverage, languages, codes, committees, and sessions

Capability reference

chparl_search_business tool
  • query (title substring), author (published submitter label, not every co-signatory), typeId, statusId, sessionId (submission session), committeeId, and inclusive submittedFrom / submittedTo. Newest business IDs first, default 20/max 100
  • Continue with nextCursor and unchanged filters; a cursor from other filters fails as invalid_cursor. totalCount is 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 businessId or an exact published short number such as 99.1234. A short number matching several businesses fails as ambiguous_business_number, and a miss returns found: false
  • overview (default) returns metadata and availableTextFields with UTF-8 sizes. texts returns textDocument.kind: "full" | "outline": several large fields become an outline, and named textFields always return whole
  • status_history, bills, related_business, preconsultations, and subjects page independently, default 20/max 100 with nextOffset. subjects IDs narrow chparl_search_transcripts; linked bills are parliamentary records, not enacted law

chparl_get_votes tool
  • mode: "votes" with businessId, sessionId, or both lists roll calls (default 10/max 50). A returned voteId feeds mode: "members" (default 50/max 100, optional personNumber) or mode: "groups" (unpaged). Paged modes continue with nextOffset
  • mode: "members" with personNumber and no voteId pages that member's voting history, optionally narrowed by businessId and sessionId. Each history row carries its published vote, business, session, and time fields; selected-vote pages carry that context once in vote. cantonId uses the canton reference's numbering; votingCantonId preserves the source Voting identifier
  • members counts carry decisionCounts.scope: "page". groups reads every published member row and returns scope: "vote", complete: true, and per-group totals by the affiliation recorded on the vote. Count buckets retain every distinct published label in decisionTexts. 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 resigned
  • Nationalrat 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 businessId or subjectId (exclusive), personNumber, sessionId, or a date bound; council only narrows. query (original-text substring) also needs sessionId or a closed range of at most 31 calendar days
  • Metadata with textSizeBytes by default (20/max 100); includeText: true returns whole passages (3/max 10); an exact transcriptId defaults to full text. Continue with nextOffset
  • A business search covers up to 20 debate subjects; more fails as business_scope_too_broad, so page chparl_get_business section subjects and pass one subjectId. found marks exact-ID misses, scopeFound a missing business

chparl_search_members tool
  • query (first, last, or official name substring), membership (current default, former, all), council (N/S or the German, French, or Italian council name), cantonId, partyId, groupId. Default 20/max 100, nextOffset
  • Rows are MemberCouncil affiliation records, not deduplicated people. Their personNumber, which need not equal Person.ID, feeds chparl_get_member, chparl_get_votes, and chparl_search_transcripts

chparl_get_member tool
  • Requires personNumber. overview (default) returns identity and every MemberCouncil affiliation, unpaged; a miss returns found: false
  • council_terms, committees, and interests page independently, default 20/max 100 with nextOffset. Committee rows are published memberships, not a historical ledger. A missing paid flag means unknown, and empty interests do not establish the absence of conflicts

chparl_list_reference tool
  • Static topics identifiers, coverage, languages, and statuses (the official vocabulary effective 1 July 2023, each code tagged era: "legacy" | "current"). Live dictionaries business_types, councils, cantons, parties, groups, committees, and sessions
  • Default 50/max 100, nextOffset. Only sessions accepts dates: dateFrom bounds the start and dateTo the 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, and it metadata with no translation fallback; Italian completeness is not established. Bulletin text stays in the language the speaker used
  • Published 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, totalCount when known, and the continuation
  • One record on both surfaces: content[] carries every structuredContent field, with multiline text and HTML in JSON-encoded fenced blocks that decode back losslessly
  • Unknown 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/mcp

Or run it locally:

claude mcp add switzerland-parliament-mcp-server -- npx -y @cyanheads/switzerland-parliament-mcp-server

For 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.

VariableDescriptionDefault
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_PORTHTTP server port.3010
MCP_SESSION_MODEHTTP session mode: stateless, stateful, or auto.stateless
MCP_AUTH_MODEAuthentication: none, jwt, or oauth.none
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.).info
LOGS_DIRDirectory for log files (Node.js only).<app-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1.in-memory
OTEL_ENABLEDEnable OpenTelemetry.false

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 .env
  • 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
docker run --rm -p 3010:3010 ghcr.io/cyanheads/switzerland-parliament-mcp-server:latest

The 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

DirectoryPurpose
src/index.tscreateApp() entry point and service setup; seven tools, no resources or prompts.
src/mcp-server/toolsTool definitions, shared lossless rendering, and whole-record page fitting.
src/services/parliamentOData client, workflow deadlines, domain schemas and services, provenance, and reference snapshots.
tests/Unit and integration tests, mirroring the src/ structure.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for logging, ctx.state for storage
  • Register new tools and resources in the createApp() arrays in src/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

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

Frequently asked questions

What is io.github.cyanheads/switzerland-parliament-mcp-server?

Search Swiss parliamentary business, votes, debates, members, and declared interests.

How do I install io.github.cyanheads/switzerland-parliament-mcp-server?

It runs as a remote server. In Claude Code: claude mcp add --transport http switzerland-parliament-mcp-server 'https://switzerland-parliament.caseyjhand.com/mcp'. For other clients, paste the JSON configuration from this page into their MCP settings.

Does io.github.cyanheads/switzerland-parliament-mcp-server need an API key?

Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.

Is io.github.cyanheads/switzerland-parliament-mcp-server open source?

Yes. Its code is on GitHub under the Apache-2.0 license.

Who maintains io.github.cyanheads/switzerland-parliament-mcp-server?

It is published by cyanheads. AI.tn lists it but does not maintain or endorse it.

From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.