Start
Connect the MCP server
One address and your key. Every tool, what it does and what it takes.
The MCP server lets the AI model your company uses read Hey Town Hall Data directly. Your AI client connects to one address with your API key and calls the server's tools. Every tool is read-only.
Connect
- Address:
https://data.heytownhall.com/mcp - Header:
Authorization: Bearer <your key> - Transport: Streamable HTTP
Most AI clients that take a remote MCP server accept a settings block like this one. Put in your own key:
{
"mcpServers": {
"hey-town-hall-data": {
"url": "https://data.heytownhall.com/mcp",
"headers": { "Authorization": "Bearer htd_test_..." }
}
}
}If your client asks for these in another form, give it the same two things: the address and the header.
Start with a sandbox key (htd_test_). Your client then reads the sandbox's fictional towns, free. Swap in a live key when you are ready.
Check the connection
You can check your key and the address without a client. This sends the first message a client sends:
curl https://data.heytownhall.com/mcp \
-H "Authorization: Bearer $HTD_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'The answer names the server hey-town-hall-data. With no key, or a key that is not valid, the server answers 401 before any handshake. A live key with no payment method answers 402.
What the server does
- Protocol. It serves the 2026-07-28 revision of the MCP specification. Clients still on the 2025-11-25 revision work too.
- Billing. The handshake and the tool list are free. Each tool call is one API request on its tool's meter, billed like any other request. A call that fails is not billed.
- Rate limits. Tool calls count against your key's rate limit, the same as REST requests.
- Page size. A tool returns 10 records unless you ask for more, and at most 50. Long text is cut at 2,000 characters. Each result carries
next_cursorto read the next page. - Sources. Every record keeps its
source_urlandread_at, so an answer your AI client writes can cite what it read. The server tells the client to cite them, and that a missing value is unknown, never a no. - Errors. A tool that fails returns a result marked as an error, with the API's error envelope as its text.
The server tells your client to start with find_jurisdictions or search_records.
The tools
Each tool is answered by one /v1 endpoint, through the same gate as a REST request.
search_records: Search the records
Full-text search across agenda items, motions, meeting transcripts, document and bylaw titles, and government posts, newest first. Use it to find where a subject has come up. Without a jurisdiction it searches transcripts, bylaws and posts; agenda items, motions and documents need a jurisdiction for now. Each hit names its family, id, jurisdiction, date, a snippet, source_url and read_at.
Answered by GET /v1/search, billed as one search request.
q(required): Words to find. Quotes keep a phrase; a leading minus leaves a word out.in: Limit to these kinds of record.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
find_jurisdictions: Find jurisdictions
Find public bodies (municipalities, regional districts, counties, school districts, First Nations, special districts) by name, region, kind or parent. Gives the jurisdiction ids the other tools filter by.
Answered by GET /v1/jurisdictions, billed as one records request.
name: Words in the name.region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: municipality, regional_district, school_district, first_nation, …parent: A parent jurisdiction id.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
jurisdictions_at_point: Who governs a point
Every jurisdiction whose boundary covers a latitude and longitude: the municipality, the regional district or county, the school district and so on.
Answered by GET /v1/jurisdictions/at, billed as one records request.
lat(required): Latitude, -90 to 90.lng(required): Longitude, -180 to 180.
list_meetings: List meetings
Council, board and committee meetings, newest first, with their date, kind, the vendor they were read from, and when the agenda first appeared.
Answered by GET /v1/meetings, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: council, committee_of_the_whole, public_hearing, board, committee, other.topic: A business topic id, such as "short_term_rentals", "data_centres", "solar_and_storage", "telecom_siting", "zoning", "procurement".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
get_meeting: Get a meeting
One meeting with its agenda items, documents, recordings and motions.
Answered by GET /v1/meetings/{id}, billed as one records request.
meeting_id(required): A meeting id from list_meetings.
get_transcript: Get a meeting's transcript
A meeting's recording transcript, in order, a page at a time, without speaker labels. An empty page means no transcript is held yet.
Answered by GET /v1/meetings/{id}/transcript, billed as one transcripts request.
meeting_id(required): A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_agenda_items: List agenda items
Agenda items, newest meeting first, with the recommendation, a plain-words summary where one passed its check, and business topics.
Answered by GET /v1/agenda-items, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".topic: A business topic id, such as "short_term_rentals", "data_centres", "solar_and_storage", "telecom_siting", "zoning", "procurement".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.meeting_id: A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_motions_and_votes: List motions and votes
Motions as the minutes print them, with mover, seconder, outcome and vote counts. Give motion_id to get one motion with each member's recorded vote.
Answered by GET /v1/motions, billed as one records request.
motion_id: One motion, with its recorded votes.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: A key decision's kind, such as bylaw_reading.topic: A business topic id, such as "short_term_rentals", "data_centres", "solar_and_storage", "telecom_siting", "zoning", "procurement".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.meeting_id: A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_attendance: List attendance
Who the minutes say was present or absent at meetings.
Answered by GET /v1/attendance, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.meeting_id: A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_documents: List documents
Documents a government publishes: staff reports, budgets, plans, bylaws, notices, with their link and whether their text is held. Give meeting_id for a meeting's agenda package, minutes and attachments instead.
Answered by GET /v1/documents, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: staff_report, budget, plan, bylaw, agenda, minutes, notice, map, form, other.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.meeting_id: A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_bylaws: List bylaws
Bylaws by number, title, kind, adoption date and core subject (subject "fees_charges" is a fees and charges bylaw), with their source.
Answered by GET /v1/bylaws, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: bylaw, amendment, consolidated, repeal.subject: zoning, building, animal_control, fire_burning, noise, trees, business_licence, fees_charges or other.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_defined_terms: List defined terms
The terms a government's bylaws define (for example 'accessory building'), each with the start of its definition as printed. Use it to learn a place's own word for a thing before searching.
Answered by GET /v1/defined-terms, billed as one records request.
term: Words in the term.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_fees: List published fees
Each fee row a permit's fee page prints, the label and amount as printed (never parsed). A body's whole fees and charges schedule is a bylaw: list_bylaws with subject fees_charges.
Answered by GET /v1/fees, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: The permit kind, such as building or business_licence.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_budgets: List budgets and financial statements
Budget and financial statement documents a government publishes, with their links. They are documents, not budget data; list_financials gives audited statement lines.
Answered by GET /v1/budgets, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: budget or financial_statement.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_financials: List financial statements
Audited financial statements by jurisdiction and year. Give report_id for the statement lines, as printed and in cents.
Answered by GET /v1/financial-lines, billed as one records request.
report_id: A report id, for its lines.statement: With report_id: one statement, such as statement_of_operations.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_bids: List open bids and tenders
Open requests for proposals, tenders and quotes, with closing times.
Answered by GET /v1/bids, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_applications: List development applications
Rezonings, development permits and subdivisions, with their address, stage and status.
Answered by GET /v1/applications, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: rezoning, development_permit, subdivision, …from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_jobs: List job postings
Open government job postings with pay, hours and terms. Give job_id for one posting with its sections.
Answered by GET /v1/jobs, billed as one records request.
job_id: One posting, with its sections.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: Employment type, such as full_time.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_officials: List elected officials
Mayors, councillors, chairs and directors as each government's own page names them.
Answered by GET /v1/officials, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: mayor, councillor, chair, director.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_departments: List departments
Departments and their published public contacts (an office's line, never a person's).
Answered by GET /v1/departments, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: The department's role, such as planning.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_news_and_notices: List news, notices and events
What governments post: news, public notices, council recaps, events and alerts. Engagement projects are kind "engagement".
Answered by GET /v1/news, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: news, notice, recap, event, alert, or engagement.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_permits: List permits, rules and fees
Each permit a government issues, where to apply, the fee table as published and the timeline it states.
Answered by GET /v1/permits, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: building, business_licence, …since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_works: List road and utility works
Announced road and utility work with its days and streets.
Answered by GET /v1/works, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: road or utility.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_press: List local press
Local press about a government: headline, publisher and link only.
Answered by GET /v1/press, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
get_platforms: Get the software each government runs
The platform census: which vendor each government uses for meetings, permits, payments and more.
Answered by GET /v1/platforms, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".kind: meetings, permits, payments, garbage, parking, feeds, video.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_platform_tenants: List vendor tenants
Each meeting vendor's tenant matched to a government and verified: the vendor census by tenant (vendor, the vendor's name for the tenant, its host, how it was matched).
Answered by GET /v1/platform-tenants, billed as one records request.
jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".region: A two-letter province or state code, such as "BC".country: "CA" or "US".vendor: The vendor, such as legistar or civicweb.since: Only records read at or after this ISO 8601 instant.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
list_topics: List business topic tags
The business topics given to agenda items, motions, documents and recordings. Filter by topic to follow it across governments.
Answered by GET /v1/topics, billed as one records request.
topic: A business topic id, such as "short_term_rentals", "data_centres", "solar_and_storage", "telecom_siting", "zoning", "procurement".jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".kind: meeting_item, motion, meeting_document, recording.from: On or after this date, YYYY-MM-DD.to: On or before this date, YYYY-MM-DD.since: Only records read at or after this ISO 8601 instant.meeting_id: A meeting id from list_meetings.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.
changes_since: What changed since
The change feed, oldest first: each change names the family and id of the record to read. Keep the last id and pass it as after next time.
Answered by GET /v1/events, billed as one records request.
after: The last event id you read.since: Only records read at or after this ISO 8601 instant.jurisdiction: A jurisdiction id from find_jurisdictions, such as "victoria".family: meeting, agenda_item, motion, recording, bylaw, post, jurisdiction, topic_tag.limit: Records to return, 1 to 50. Default 10.cursor: next_cursor from the previous result, for the next page.