@cyanheads/eu-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., "@@cyanheads/eu-parliament-mcp-servershow me recent European Parliament plenary votes"
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.
Overview
European Parliament records from the Open Data API: discover legislative procedures, follow their evidence, find MEPs, inspect plenary decisions and voters, and retrieve document, speech, and question metadata. Runs as a stdio process or a local Streamable HTTP server. No API key is required.
Tools
Tool | Description |
| Discover filter codes, identifier formats, coverage, committees, and political groups |
| List procedure references by type |
| Read procedure identity, stage, events, participants, and document references |
| Search adopted texts, list committee/plenary documents, or retrieve any canonical document |
| Search tenth-term speech activities and retrieve metadata and recording-document links |
| Find MEPs across a complete current or selected-term roster |
| Read member identity and published membership history |
| Discover sittings, inspect decisions, and page recorded or intended voters |
| List questions by year/type or retrieve a question and answer references |
Related MCP server: UK Parliament MCP Server
Capability reference
All list tools accept offset (default 0), limit (default 20, accepted 1–1000, effective maximum 100 with notice), and language (default en, one of the 24 EU language codes). Follow page.next_offset; for local collections, also pass the returned page.snapshot. A snapshot_changed error requires restarting at offset 0 without a snapshot. Local snapshots detect changes on a fresh lookup; they do not retain historical data.
Localized text includes its actual source language; fallback is disclosed and text is never translated. Missing detail normally returns found: false; empty lists succeed with guidance. Rich decision lookup uses decision_not_found instead.
euparl_list_reference tool
Required
topic:committees,political_groups,procedure_types,document_types,question_types,activity_types,mep_filters,identifiers, orcoverageCommittees and political groups are live corporate bodies; organization identifiers do not imply accepted filter codes. Reference pages need no snapshot
euparl_list_procedures tool
Optional
process_typefromeuparl_list_reference; no keyword, year, committee, or stage filterSparse rows carry
procedure_id, source URL, and available reference/type; retrieve titles, stages, and participants witheuparl_get_procedure
euparl_get_procedure tool
Required
procedure_idacceptsYYYY-NNNN,YYYY/NNNN(TYPE), an optional letter suffix, the known path prefix, or the exact public procedure URIsection: "overview"returns scalar metadata and collection counts;events,participants, anddocumentspage one collection using snapshotsHistorical participant groups stay historical. Follow document IDs with
euparl_search_documentsin get mode
euparl_search_documents tool
mode: "search"defaults tosource: "adopted_texts"; only that family acceptstext,title, sitting dates, andrelated_process_id. Adopted texts accept year and term; committee accepts term, plenary accepts yearwork_typeuses family-specific codes fromeuparl_list_reference. Committee/plenary discovery has no keyword filtermode: "get"requiresdocument_idand rejects source, search filters, and nondefault paging. IDs from procedures, speeches, votes, questions, and answers all use this same lookupDetail includes metadata, procedure/parent references, and every source-file link in the selected language. Follow
parent_document_idswhen a subdivision lacks files; document bodies are not downloaded or extracted
euparl_search_speeches tool
Search by
text,title,person_id,activity_type, or sitting-date range; coverage is limited to parliamentary term 10mode: "get"requiresspeech_idand rejects search filters and nondefault pagingReturns activity metadata and participants, not transcripts. Follow
document_idsthrough document get and any parent references to source files
euparl_search_meps tool
Omitted
termselects members in office today; explicittermselects a published roster from terms 0–10. Optional country, political-group, and gender codes come frommep_filtersname_containsmatches every normalized token across the complete roster before paging, ignoring case, diacritics, and punctuationResults use snapshot continuation. Country/group describe the selected roster context, not voting-date affiliation
euparl_get_mep tool
mep_idaccepts a decimal person ID,person/prefix, or exact public person URIDefault
section: "overview"returns identity andmembership_count;section: "memberships"pages published history with snapshotsMissing membership end dates do not establish current membership
euparl_get_plenary_votes tool
mode: "sittings"requiresyear; defaultdecisionsrequiressitting_idand pages compact summaries. Sitting IDs accept a realYYYY-MM-DDdate,MTG-PL-form, known event prefix, or public URImode: "decision"requires sitting and decision IDs and returns one rich record with whole labels, commentary, and document references; it rejects paging and snapshotsmode: "voters"also requiresposition:favor,against,abstention,intended_favor,intended_against, orintended_abstention. Decisions and voter positions page independently with snapshotsresolve_names: trueis voters-only and requiresroster_term(0–10); unresolved IDs remain in output. Names come from that published term roster, with no voting-date affiliationsPublished tallies remain separate from voter-array counts.
available: falsemeans an array was absent; published empty arrays haveavailable: true. Intended corrections never replace recorded votes
euparl_list_questions tool
Default
mode: "list"acceptsyearandwork_type; no keyword, author, or addressee searchmode: "get"requiresquestion_id: a canonical work ID, known document prefix/public URI, or human citation such asE-000001/2025(also P/O prefixes). Optionaltermresolves a citation directly; omission searches the full citation year and requires one exact matchGet rejects list filters and nondefault paging. Detail returns metadata, source files, and published answer references; empty
answersdoes not prove the question is unanswered
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.
European Parliament-specific:
Keyless access to Parliament's public JSON-LD records, with canonical identifiers linking discovery, detail, and source evidence
Shared request pacing, bounded retries, and one 40-second operation deadline covering acquisition and queue waits
Complete-roster name filtering and separate paging for procedure evidence, membership history, decision summaries, and voters
Agent-friendly output:
Source URLs, actual language labels, normalized filters, exact totals when available, and continuation guidance
Missing fields retain their uncertainty; published zero values, absent arrays, and historical affiliations remain distinct
Matching data on
content[]andstructuredContent, with usable source links and typed error reasons
Data source: European Parliament Open Data, licensed under CC BY 4.0. This server normalizes identifiers and record structure. Parliament records do not establish enacted-law completeness or a member's lifetime voting history.
Getting started
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"eu-parliament-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/eu-parliament-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"eu-parliament-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/eu-parliament-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"eu-parliament-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/eu-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/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
No API key or upstream account is required.
Installation
Clone the repository:
git clone https://github.com/cyanheads/eu-parliament-mcp-server.gitNavigate into the directory:
cd eu-parliament-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env to override framework settings as neededConfiguration
Variable | Description | Default |
| Transport: |
|
| HTTP listen host. |
|
| HTTP server port. |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only). |
|
| Storage backend: |
|
| Enable OpenTelemetry. |
|
No server-specific environment variables are required. See .env.example for 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:stdioRun checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Project structure
Directory | Purpose |
| Nine read-only tool definitions ( |
| Shared schemas, lossless rendering, and enrichment. |
| JSON-LD client, edge schemas, reference codes, normalization, and domain workflows. |
| Unit and integration tests, mirroring the |
| Design contracts and generated project tree. |
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
Query FDA data on drugs, food, devices, and recalls via openFDA. STDIO or Streamable HTTP.
Query SEC EDGAR filings, XBRL financials, and company data via MCP. STDIO or Streamable HTTP.
Search MPs and Lords, fetch profiles, synopses, and Westminster constituencies
Official EUR-Lex, UK, US, and gazette search, metadata fetch, and change-only watches.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides access to European Parliament open data, enabling queries about MEPs, plenary documents, and session calendar.139 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables querying UK Parliament data including MPs, Lords, bills, Hansard debates, and divisions.6 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables access to U.S. congressional data including bills, laws, members, committees, votes, nominations, CRS reports, and the Congressional Record through MCP, with stdio and Streamable HTTP support.168 npm1Apache 2.0
- 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