Canada Parliament Mcp Server

io.github.cyanheads由 GitHub 帳號 cyanheads 發布v0.2.1更新於 Nov 1, 2026

Track Canadian federal bills, MPs, House votes, and Hansard speeches.

已驗證Streamable HTTP可網頁執行網頁搜尋與抓取知識與記憶

概覽

AI 產生的概覽

檢索並讀取加拿大聯邦議會紀錄——法案、議員、下議院表決與漢薩德(Hansard)發言,資料來自官方來源與 OpenParliament。

可以做什麼
  • 檢索與讀取法案:依標題、編號、議院、類型、狀態或提案人尋找兩院法案,並開啟法案檔案查看階段、表決、摘要與法條引用
  • 檢索與讀取議員:查詢現任議員、歷屆議會名冊或歷史姓名索引,並讀取個人資料、任期、所提法案與近期投票
  • 檢索與讀取下議院表決:依法案、結果、日期或主題篩選已記錄的分組表決,並查看計票、黨派合計與個人投票
  • 檢索漢薩德發言:依發言者、所辯論或提及的法案、日期,或英法文原文片段尋找已索引的下議院發言
  • 列出參考詞彙:查看會期涵蓋範圍以及篩選所用的法案、表決與黨團術語
適用情境
適合追蹤加拿大聯邦立法進程、查核某位議員的投票或下議院發言,或研究某法案跨會期的歷史。適用於需要可溯源議會紀錄的研究與報導類問題,而非一般網頁搜尋。
執行需求
可使用託管的遠端端點,或透過 npx(Node.js)、Docker 或原始碼建置(Bun 或 Node.js 24+)在本機執行。需能連線 parl.ca、ourcommons.ca 與 openparliament.ca。無需 API 金鑰;CANPARL_USER_AGENT 為選用項,自行部署 HTTP 時另涉及 MCP_HTTP_PORT、MCP_AUTH_MODE 等設定。
安裝前請注意
資料為非官方資料,署名議會與 OpenParliament;提案人與發言涵蓋範圍僅限 OpenParliament 索引,可能落後於官方紀錄。OpenParliament 請求有節流,部分查詢可能耗時數十秒。引用的原文屬於資料,不是指令。自架 HTTP 部署預設不啟用驗證(MCP_AUTH_MODE),應限制對外暴露。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Canada Parliament Mcp Server,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.cyanheads%2Fcanada-parliament-mcp-server/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "canada-parliament": {
      "type": "http",
      "url": "https://canada-parliament.caseyjhand.com/mcp"
    }
  }
}

README

@cyanheads/canada-parliament-mcp-server

Track Canadian federal bills, MPs, House votes, and Hansard speeches via MCP. STDIO or Streamable HTTP.

8 Tools


Overview

Canadian federal parliamentary records from LEGISinfo, the House of Commons, and OpenParliament. Follow House and Senate bills through their stages, find current and former MPs, inspect recorded House divisions, and read indexed House Hansard speeches. Public sources require no API key.

Tools

ToolDescription
canparl_search_billsSearch a session's official bills by title, number, chamber, type, status, or indexed MP sponsor
canparl_get_billRead an official bill dossier: sponsor and title, stages, reading milestones, divisions, publications, legislative summary, notes, web references, and enacted statute citation
canparl_search_membersSearch the current House roster, a past Parliament's official roster, or OpenParliament's historical name index
canparl_get_memberRead a member profile, dated memberships, sponsored bills, and recent ballots
canparl_search_votesSearch recorded House divisions by bill, result, document type, date, or subject
canparl_get_voteRead a division's official tally, party totals, and individual recorded ballots
canparl_search_speechesFind indexed House speeches by speaker, bill debated or mentioned, date, and literal English or French text
canparl_list_referenceDiscover actual session coverage and source-specific filter vocabulary

Capability reference

canparl_search_bills tool

  • titleContains (matching ignores case, accents, dash and quote styles, and repeated whitespace), billCode, originatingChamber, billType, status, and sponsor, combined with AND; limit 1–100 (default 10; values up to 10,000 clamp to 100 with a notice) with offset pagination
  • Bilingual titles, status, latest major stage, and royal assent date, with the exact filtered total and pagination.nextOffset
  • Whole bill rows stop early at the 24,000-byte response budget; follow pagination.nextOffset with identical filters. An oversized single row returns whole with a notice
  • sponsor takes an OpenParliament slug, /politicians/ path, or profile URL (member.slug from canparl_get_member, or an includeFormer search row), or a current MP's personId. A digit-only value equal to a current personId, or its /politicians/<digits>/ path or URL, resolves through the same verified crosswalk as canparl_get_member; appliedFilters.sponsorName names the profile used
  • Sponsor results cover only OpenParliament's index (sponsorCoverage: "openparliament_index"), which excludes Senators; a scan past ten 100-row pages fails as sponsor_scan_incomplete

canparl_get_bill tool

  • billCode and its session from canparl_search_bills; returns the sponsor and their affiliation title, House/Senate/royal-assent stages, House divisions (dateTime is the LEGISinfo sitting date-time, not when the division was recorded), Senate vote records, publications, and statute
  • Also the Library of Parliament legislative summary and dossier notes as plain text (each note link kept as text (href)), the six reading milestones as UTC instants converted from LEGISinfo's Ottawa-time clocks, and related webReferences (press releases, background documents, costing notes) whose URLs are relayed as published, never fetched
  • Above a 24,000-byte response budget, returns kind: "outline" with sponsor, statute, and milestones inline, listing the sections sponsor, stages.house, stages.senate, stages.royalAssent, divisions, senateVoteDetails, publications, statute, summary.en, summary.fr, notes.en, notes.fr, milestones, and webReferences; re-call with section, paging collections by offset and limit (1–100, default 20; values up to 10,000 clamp to 100 with a notice) through pagination.nextOffset
  • Pages hold whole records; an indivisible record or language section over the budget returns whole with disclosure, and null, empty, and past-end sections stay distinct

canparl_search_members tool

  • Current roster: name and riding substrings (matching ignores case, accents, dash and quote styles, and repeated whitespace), province (postal code or full name), and party; limit 1–100 (default 25; values up to 10,000 clamp to 100 with a notice) with the exact filtered total
  • parliament (36th onward) searches that Parliament's official roster with the same filters: everyone who sat in it, one row each with the caucus and riding last held there, the membership from and to dates, and current. An unoffered Parliament fails listing the ones offered; it is rejected with includeFormer
  • includeFormer: true searches OpenParliament's historical name index instead: one token matches a surname, several match a full recorded name. Parliament, geographic, and party filters are rejected there, rows may carry only a name and slug, and total is null
  • Pass detailLookup unchanged to canparl_get_member: official roster rows carry an official personId, historical rows an OpenParliament slug
  • Whole member rows stop early at the 24,000-byte response budget; follow pagination.nextOffset with identical filters. An oversized single row returns whole with a notice

canparl_get_member tool

  • Exactly one personId or slug from detailLookup; returns the profile and dated memberships. A digit-only slug equal to a current personId, or its /politicians/<digits>/ path or URL, is read as that personId. A former member's personId (36th Parliament onward, as on canparl_get_vote ballots) resolves on the all-Parliaments roster with current: false, carrying their latest Parliament's caucus and riding; slug inputs stay current-roster only
  • personId crosswalks verify the official ID and a recorded name or published alias; a bounded surname lookup after an empty exact-name page accommodates accents and middle initials without guessing a slug
  • sponsoredBills (0–5, default 5) and recentVotes (0–10, default 10) page independently through billsOffset and votesOffset; 0 skips a section, and values up to 10,000 clamp to the cap with a notice
  • With one official personId, ballots come newest first from the official member-votes feed in one request, for the member's latest session or votesSession, optionally narrowed by votesBillCode. ballot reads Yes/No/Paired, officialBallot keeps Yea/Nay/Paired, and source names the feed; other members keep OpenParliament ballots
  • Each activity section reports available, unavailable, or not_requested, with failure metadata; unavailable history is never reported as empty
  • Profile links are never fetched: an absolute http or https URL is relayed as published, and a relative value is resolved against https://openparliament.ca

canparl_search_votes tool

  • billCode, result (Agreed To, Negatived, Tie), documentType, inclusive Ottawa-date dateFrom and dateTo, and subjectContains (matching ignores case, accents, dash and quote styles, and repeated whitespace); limit 1–100 (default 25; values up to 10,000 clamp to 100 with a notice) with offset pagination
  • Newest first, with official tallies and the exact filtered total; pass session and number to canparl_get_vote
  • Whole division rows stop early at the 24,000-byte response budget; follow pagination.nextOffset with identical filters. An oversized single row returns whole with a notice

canparl_get_vote tool

  • number and its session; ballot (Yea, Nay, Paired; Yes/No accepted), personId, party, and province filter only the ballot page; limit 1–400 (default 30; values up to 10,000 clamp to 400 with a notice) with offset pagination
  • tally, byParty, and ballotsTotal cover the whole division and ballotsMatched the filtered set; tallyMatchesBallots flags a disagreement without changing either count
  • Ballots are Yea, Nay, or Paired; nonvoters are not listed, so a personId with no ballot returns an empty page
  • A page stops at a 24,000-byte response budget with truncated and a notice; follow nextOffset for the rest

canparl_search_speeches tool

  • Needs a scope: politician, billDebated or mentionedBill ({ session, code }), dateFrom, or dateTo; contains is a literal substring of the selected language (en default, or fr; matching ignores case, accents, dash and quote styles, and repeated whitespace) and never a scope on its own. limit 1–10 (default 5; values up to 10,000 clamp to 10 with a notice), and a page stops at a 24,000-byte response budget, returning at least one speech whole
  • politician takes the same slug, path, URL, or current personId values as canparl_search_bills sponsor, resolved the same way; appliedFilters.politicianName names the profile used
  • Scans at most 100 raw candidates per call: follow nextOffset with identical filters until exhausted before concluding there is no match, and even then the answer covers OpenParliament's index only
  • Complete content, speaker, h1, and h2 in the selected language (null where that language has none, never the other language's text; older records carry no French), with speech-date party and riding in English (null when unavailable); substantiveOnly (default true) drops procedural remarks, and committee records are excluded and counted in excludedCommittees

canparl_list_reference tool

  • topic: sessions, bill_types, bill_statuses, vote_results, vote_document_types, or parties; returns the complete set without pagination
  • sessions takes no session and reports basic or full bill coverage and House division coverage per session; other topics take a session and mark each value observed in its feed; parties takes only the current session

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.

Canadian Parliament-specific:

  • Official bill coverage from session 35-1 (1994), full dossiers from 37-1 (2001), and House divisions from 38-1 (2004); OpenParliament's historical name index reaches 1994
  • Bills cover both chambers; member, division, and speech tools cover the House of Commons. Missing historical fields stay null
  • Sessions accept "45-1" or { "parliament": 45, "session": 1 }; an omitted session resolves from the current official bill feed, except in speech bill scopes
  • Shared source pacing, short-lived in-memory caches, retries, and one 50-second tool deadline. OpenParliament requests are serialized with a two-second start gap, so sponsored bills and OpenParliament ballots can take tens of seconds
  • Official-source HTTP 403 refusals fail with upstream_blocked, the source name, and guidance to retry that source later; response HTML is excluded, and official data is never replaced with another source

Agent-friendly output:

  • Provenance: source, url, original retrievedAt, and cached on every successful retrieval
  • Explicit coverage: normalized appliedFilters, continuation fields, notices, and typed failure reasons separate no matches from unavailable or incomplete data
  • Advertised input formats: dates, sessions, person IDs, bill codes, and bill sections carry a pattern in the tool schema that accepts what the tool accepts, padded values included. A value outside the format fails at argument validation (-32602, invalid_arguments) naming the field and the expected form; impossible dates, reversed bounds, out-of-range session numbers, and unknown vocabulary values keep their typed tool reasons
  • Both surfaces: every structuredContent value, complete source text included, also renders in Markdown content[]

The Canadian Parliament research guide connects bill, division, member, and Hansard records and explains the evidence needed for historical conclusions. It ships with plugin installs, npm, Docker, and the desktop bundle, and is available over MCP as skill://canada-parliament-guide/SKILL.md.

Getting started

Connect to the hosted server in Claude Code:

sh
claude mcp add --transport http canada-parliament-mcp-server https://canada-parliament.caseyjhand.com/mcp

Or run it locally:

sh
claude mcp add canada-parliament-mcp-server -- npx -y @cyanheads/canada-parliament-mcp-server

For other clients, add this to the MCP config file:

json
{  "mcpServers": {    "canada-parliament-mcp-server": {      "command": "npx",      "args": ["-y", "@cyanheads/canada-parliament-mcp-server"]    }  }}

No API key is required. Optionally set CANPARL_USER_AGENT to identify your deployment to the upstream sources. For Docker or a source build, see Running the server.

Configuration

VariableDescriptionDefault
CANPARL_USER_AGENTHTTP User-Agent sent to the upstream sources. Blank uses the default; CR and LF are rejected.canada-parliament-mcp-server ([email protected]; https://github.com/cyanheads/canada-parliament-mcp-server)
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_HOSTHTTP bind address.127.0.0.1
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 every server setting and the common framework overrides.

Running the server

Local development

Requires Bun v1.4.0 or higher (or Node.js v24+), and Internet access to parl.ca, ourcommons.ca, and openparliament.ca.

sh
git clone https://github.com/cyanheads/canada-parliament-mcp-server.gitcd canada-parliament-mcp-serverbun installcp .env.example .env
  • Build and run the production version:

    sh
    # One-time buildbun run rebuild
    # Run the built serverbun run start:http# orbun run start:stdio
  • Run checks and tests:

    sh
    bun run devcheck  # Lints, formats, type-checks, and morebun run test      # Runs the test suite

Docker

sh
docker run --rm -p 3010:3010 ghcr.io/cyanheads/canada-parliament-mcp-server:latest

The image defaults to HTTP transport, stateless sessions, and logs in /var/log/canada-parliament-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/canada-parliament-mcp-server:latest"]. Build locally with docker build -t canada-parliament-mcp-server .; OpenTelemetry peers are installed by default, or omitted with --build-arg OTEL_ENABLED=false.

Project structure

DirectoryPurpose
src/mcp-server/tools/definitionsTool definitions (*.tool.ts), the shared Markdown renderer, and the shared member-identity crosswalk.
src/services/legisinfoLEGISinfo service — session discovery, official bill lists and dossiers.
src/services/ourcommonsHouse of Commons service — current and per-Parliament rosters, division, and member-vote XML.
src/services/openparliamentOpenParliament service — historical identities, activity, speeches, and memberships.
src/domainShared schemas, normalization, reference vocabulary, and request budgets.
src/configServer-specific environment variable parsing and validation with Zod.
skills/Published parliamentary research guide for agents calling the tools.
tests/Parser, service, tool, and integration tests over synthetic upstream fixtures.

See docs/tree.md for the full tree.

Development guide

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

  • Handlers throw, framework catches; catch only to translate a known source failure or keep optional enrichment
  • Use ctx.log for logging and ctx.enrich for applied filters, totals, and notices
  • Register new tools 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:

sh
bun run devcheckbun run test

License

Code is licensed under Apache 2.0. Parliamentary data is an unofficial reproduction credited to Parliament and, where used, OpenParliament; Parliament retains copyright. Reuse is governed separately by the Parliament notices, the Speaker's Permission, the Senate terms, and the OpenParliament API terms. This free, noncommercial relay does not imply government endorsement or an open-data licence.

來源:README.md,提交 fe117e2

工具

8

canparl_search_bills

Canparl Search Bills

Find House and Senate bills in one session by title, number, type, chamber, status, or indexed MP sponsor. Sponsor results are the OpenParliament-indexed subset; fetch a bill for its sponsor, stages, divisions, and statute citation. Omitted session means the verified current official session. Follow nextOffset with identical filters.

輸入參數limitoffsetstatussessionsponsorbillCodebillTypetitleContainsoriginatingChamber

canparl_get_bill

Canparl Get Bill

Read one House or Senate bill's official dossier. Large dossiers return an outline; re-call with one section and follow pagination.nextOffset for collections. Stages preserve nested records whole. Obtain billCode and session from canparl_search_bills; omitted session means the verified current official session.

輸入參數limitoffsetsectionsessionbillCode必填

canparl_search_members

Canparl Search Members

Find House MPs by name, riding, province, or caucus in the complete current official roster, or set parliament to search everyone who sat in that Parliament (36th onward) with official personIds and membership dates. Set includeFormer for OpenParliament's historical name index; its rows may contain only a name and slug. Follow nextOffset with identical filters and use detailLookup with canparl_get_member.

輸入參數namelimitpartyoffsetridingprovinceparliamentincludeFormer

canparl_get_member

Canparl Get Member

Read one House MP by a returned OpenParliament slug or official personId, current or former (36th Parliament onward). Pass exactly one identifier from canparl_search_members detailLookup. Official profiles survive unavailable OpenParliament enrichment. Recent ballots come newest first from the official House member-votes feed when the member has one official personId, filterable by votesSession (default: the member's latest session) and votesBillCode; otherwise from OpenParliament. Sponsored bills and recent ballots are independently pageable; set their limits to zero for profile-only lookup.

輸入參數slugpersonIdbillsOffsetrecentVotesvotesOffsetvotesSessionvotesBillCodesponsoredBills

canparl_search_votes

Canparl Search Votes

Find recorded House divisions in one session by bill, result, document type, date, or subject. Return newest first and pass session plus number to canparl_get_vote. Omitted session resolves from the current official bill feed. Follow nextOffset with identical filters.

輸入參數limitdateTooffsetresultsessionbillCodedateFromdocumentTypesubjectContains

canparl_get_vote

Canparl Get Vote

Read a recorded House division, its full official tally, party totals, and a page of individual ballots. Ballot, personId, party, and province filters affect the ballot page only; nonvoters are absent. Omitted session means the verified current official session. Follow nextOffset with identical filters.

輸入參數limitpartyballotnumber必填offsetsessionpersonIdprovince

canparl_search_speeches

Canparl Search Speeches

Find indexed House Hansard speeches by speaker, bill debated or mentioned, or date. contains scans at most 100 candidate speeches per call; follow nextOffset without changing filters until exhausted before drawing a negative conclusion.

輸入參數limitdateTooffsetcontainsdateFromlanguagepoliticianbillDebatedmentionedBillsubstantiveOnly

canparl_list_reference

Canparl List Reference

List canonical session coverage and bill, division, and caucus vocabulary. Use source-specific terms when constructing filters. Omitted session means the verified current session for vocabulary. For topic sessions omit session; the entire global index is returned. Topic parties covers the current session only: its entries come from the current House roster, so a past division's caucuses come from canparl_get_vote byParty.

輸入參數topic必填session

版本歷史

5
  1. v0.2.1最新Nov 1, 2026
  2. v0.2.0Oct 29, 2026
  3. v0.1.3Oct 25, 2026
  4. v0.1.2Oct 21, 2026
  5. v0.1.1Oct 21, 2026

評分

已滿足適用檢查項的 100%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分