legislation-nz-mcp
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., "@legislation-nz-mcpWhat does section 22 of the Privacy Act 2020 say?"
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.
legislation-nz-mcp
A Model Context Protocol server for the New Zealand legislation.govt.nz developer API.
It lets an MCP client such as Claude search New Zealand legislation, browse every point-in-time version of an Act, Bill, or piece of secondary legislation, and read the text of a single section or schedule, all through the official API published by the Parliamentary Counsel Office (PCO).
Written in TypeScript on the official MCP SDK. It runs over stdio for local clients (Claude Desktop, Claude Code, Cursor, and any other MCP client) or over streamable HTTP as a standalone localhost service.
What it can do
Ask your assistant things like:
"What does section 22 of the Privacy Act 2020 say?"
"List every version of the Crimes Act 1961 and give me the one in force on 1 July 2013."
"Which Acts mention 'notifiable privacy breach'?"
"Show me all in-force secondary legislation administered by the Takeovers Panel."
"What is the structure of the Trusts Act 2019, and which Part covers trustees' duties?"
"Give me the PDF of the Crimes Act as originally enacted in 1961."
"How much of my daily API quota is left?"
Every answer comes with the official website link for the work or version so a reader can verify it at the source.
Related MCP server: au-eli-mcp
Tools
Tool | What it does |
| Search by title or full text with every filter the API offers, or browse by filters alone. Returns matching works, their newest matching version, website URLs, and a flag for content matches that only hit an older version. |
| Every point-in-time version of a work, with the work's metadata reported once at the top. Fetches all pages automatically, or one page on request. |
| Metadata for a single version, including the download URLs for each available format ( |
| The structure of a document: Parts, subparts, section numbers and headings, and schedules. Use it to find a section number before reading text. |
| The text of a whole document, a single section, or a single schedule, as clean plain text from the official XML. Can also return a PDF download URL instead. |
| The same search through the legacy Atom feed endpoint, returning parsed feed entries and a subscribable feed URL. Needs a separate RSS key. |
| A work's version history as an Atom feed, with a subscribable URL for change monitoring. Needs a separate RSS key. |
| Remaining daily quota for the API key and the feed key, read from the API's rate-limit response headers. |
Typical workflows
Read one section of an Act
search_legislationwithsearch_term: "Privacy Act 2020"gives thework_idact_public_2020_31.list_sectionswith thatwork_idlists every Part and section heading.get_legislation_textwithwork_idandsection: "22"returns just that section, with its Part and subpart context.
Read the law as it stood on a date
list_versionswith thework_idlists every version with its effective date.get_legislation_textwith the chosenversion_idand asectionorschedule.
Find legislation by what it says
search_legislation with search_field: "content" searches the body of every
document rather than titles. Wrap a phrase in double quotes to require the
exact words; otherwise stemming is on and "levy" also matches "levies".
Browse without a search term
Omit search_term and pass filters alone. Type-specific filters imply the
type, so act_status: "in_force" on its own returns in-force Acts, and
instrument_type_group: "regulations" returns only regulations.
Tool reference
search_legislation
Parameter | Notes |
| Optional. ElasticSearch simple query syntax. Omit to browse by filters. |
|
|
|
|
|
|
| Acts only. |
| Bills only. |
| Secondary legislation only. |
| The agency's full name exactly as listed on the browse agencies page. |
|
|
|
|
| Default 20 per page, maximum 100. |
Mixing filters from two types, or contradicting an explicit
legislation_type, returns a clear error rather than an empty result.
Each result includes work_id, title, url (the work's latest page),
publisher, administering_agencies, the type-specific fields, and the
matching version: latest_matching_version_id, its date, its URL, the format
types it offers, and latest_matching_version_is_latest. That last flag is
false when a content search matched only an older version, for example text
that has since been repealed.
list_versions
Takes a work_id and optional sort (desc by default). With no page it
fetches every page (the API serves at most 100 per page) and returns them all,
with pages_fetched and a truncated flag. With page (and optionally
per_page) it returns one page with has_more.
Work-level metadata (title, type, status, agencies) is reported once at the
top. Each version carries its version_id, version_date, url, and format
types; the newest version carries is_latest_version: true.
get_version_details
Takes a version_id. Returns the version's metadata, its url, the work's
work_url, and formats[] with a download URL for each format.
list_sections
Takes a version_id or a work_id (the newest version is used). Returns
parts[] with their subparts and sections, any sections outside a Part, and
schedules[]. Needs the XML format, which all PCO-published documents have.
get_legislation_text
Parameter | Notes |
| One is required. A |
| A section number such as |
| A schedule number such as |
|
|
| Truncates whole-document output (default 100,000 characters). Not applied to a single section or schedule. |
| Content types to strip: |
Text comes from the official XML format, which carries the document structure.
The HTML format is only a fallback, because it is the full website page. The
table of contents is always dropped, since list_sections covers it better.
search_legislation_rss and list_versions_rss
These call the two legacy feed endpoints in the API documentation. They need a
separate RSS-only key (see Setup). Entries are returned parsed: title, website
URL, timestamps, and a derived work_id and, for dated entries, version_id,
so results can be passed straight to the JSON tools. Each response includes
the public feed_url (without your key) for subscribing in a feed reader. The
search feed accepts search_term, search_field (title or content),
legislation_type, legislation_status, and a client-side limit; it returns
at most 100 entries and does not paginate.
get_rate_limit_status
Returns the latest quota figures for the API key and the feed key: limit,
remaining, and when the quota resets, in UTC and New Zealand time. By default
it spends one minimal request to refresh the API figure; refresh can be
api, rss, both, or none.
Quota on every response
Every tool result carries a rate_limit object taken from the response
headers of the request the tool just made:
"rate_limit": {
"scope": "api",
"limit": 10000,
"remaining": 9997,
"resets_at": "2026-09-22T12:00:00.000Z",
"resets_at_nz": "23/09/2026, 12:00:00 am NZST"
}Links and ephemeral identifiers
Results carry website links (url) built from the identifiers, following the
URL pattern the API documents: a work links to its latest alias and a
version to its dated page. Identifiers containing ~ are ephemeral (built
from fallback data for agency-published legislation and liable to change) and
carry ephemeral: true.
Setup
Requirements
Node.js 18 or later.
A legislation.govt.nz developer API key. Request one on the developer API page.
Optionally, an RSS-only key for the two feed tools. The feeds reject the regular API key, and the other six tools do not need the RSS key.
Install and build
git clone https://github.com/ezydubs/legislation-nz-mcp.git
cd legislation-nz-mcp
npm install
npm run buildProvide the API key
The recommended way is a .env file in the project root. The server loads it
at startup, so the key stays out of your shell and out of your MCP client
config:
cp .env.example .env
# edit .env and set LEGISLATION_NZ_API_KEY=....env is gitignored. A key already set in the environment, for example via an
MCP client env block, takes precedence over the file.
Use with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"legislation-nz": {
"command": "node",
"args": ["/absolute/path/to/legislation-nz-mcp/dist/index.js"],
"env": {
"LEGISLATION_NZ_API_KEY": "your_api_key_here"
}
}
}
}Leave out the env block if you use a .env file.
Use with Claude Code
claude mcp add legislation-nz -- node /absolute/path/to/legislation-nz-mcp/dist/index.jsAdd --env LEGISLATION_NZ_API_KEY=your_api_key_here if you are not using a
.env file. Add -s user to make the server available in every project.
Use with other MCP clients
Any client that can launch a stdio server works: the command is node and the
single argument is the absolute path to dist/index.js.
Run over HTTP
The server can also run as its own localhost HTTP service, for example behind a reverse proxy or gateway that handles authentication:
npm run start:httpIt serves the MCP streamable HTTP transport at http://127.0.0.1:8091/mcp.
Override the bind address with LEGISLATION_HTTP_HOST and
LEGISLATION_HTTP_PORT. The HTTP entry point has no authentication of its own
and must not be exposed on a public interface.
Environment variables
Variable | Required | Purpose |
| Yes | Key for the JSON API (10,000 requests/day). |
| No | RSS-only key for the two feed tools (1,500 requests/day). |
| No | Bind address for the HTTP transport (default |
| No | Port for the HTTP transport (default |
How it works
Search and metadata come from the JSON API at
https://api.legislation.govt.nz/v0/.Document text is fetched from the
formats[].urllinks a version advertises. The XML format is parsed to find a section by its label inside the main body only, so schedule provisions with the same number never collide, and to walk up to the enclosing Part and subpart.Feeds come from
https://www.legislation.govt.nz/api/rss/, are parsed as Atom, and have their website URLs mapped back to identifiers.Quota headers on every response are recorded per key and reported.
Errors are returned as MCP tool errors with readable messages, never as a crashed server.
Key handling
The API key is sent only to
legislation.govt.nzhosts. Agency-published secondary legislation can link to the agency's own website, and no key is sent there.The feed key travels in the query string because the feed endpoints accept nothing else. It is scrubbed from any error text and never included in the
feed_urlreturned to the client.Keys never appear in tool output.
Retries
Transient upstream errors (502, 503, 504) are retried up to three times with capped backoff. A 429 is not retried: it means the daily quota is spent until midnight New Zealand time, and the error message says when that is. A 403 means the burst limit (2,000 requests per five minutes per IP) was hit.
API notes
Base URLs:
https://api.legislation.govt.nzfor the JSON API;https://www.legislation.govt.nz/api/rss/for the legacy feeds.Auth:
X-Api-Keyheader for the JSON API;api_keyquery parameter for the feeds.Rate limits: 10,000 requests/day per API key, 1,500/day per feed key, 2,000 requests per five minutes per IP. Quotas reset at midnight NZ time.
The API returns document metadata; the text itself lives behind the
formats[].urllinks.Official documentation: https://api.legislation.govt.nz/docs/.
Observed API behaviour
The following notes record places where the live API behaves differently from what the published documentation implies. Each one affected the client implementation and may be useful to others building against the same API. Behaviour was verified against live responses in September 2026; confirm against the canonical documentation before relying on any point.
List responses use a
resultsenvelope, not a bare array. Search and version listings return{ "results": [ ... ], "total": N, "page": N, "per_page": N }.titleis on the version, not the work. In search results a work has no top-leveltitle; it appears only inlatest_matching_version.title.Versions carry no discrete date field. The effective date is encoded in the trailing segment of
version_id(e.g.act_public_2020_31_en_2026-05-01), possibly with a deduplication suffix letter (2020-06-30B), and must be parsed from the id.administering_agenciesis a string filter but an array in responses.The
htmlformat URL returns the full website page, with navigation and menus. Thexmlformat is the clean, machine-readable content.Identifiers are not zero-padded. Observed ids are
act_public_2020_31, notact_public_2020_0031.The versions endpoint paginates, and accepts
page/per_page. The documentation lists neither parameter for it, but the default page holds 20 versions and both parameters work;per_pageis capped at 100. The Income Tax Act 2007 has 206 versions, so a full listing takes three requests.The versions endpoint does not send
is_latest_version, only search does. The server derives it from the sort order.The legacy feeds live on a different host, need a different key, and are Atom.
/api/rss/search/and/api/rss/works/{work_id}/versions/return 404 onapi.legislation.govt.nz; they are served fromwww.legislation.govt.nz. They accept the key only as theapi_keyquery parameter, and a regular API key is rejected (401 Unauthorized API key). The body is an Atom 1.0 feed, not RSS 2.0. The search feed returns up to 100 entries and ignorespageandper_page. The documentedsearch_field=fulltextvalue returns no entries at all; the feed honourscontent, so the tool sendscontentfor either. An unknownwork_idin the versions feed returns HTTP 200 with<id>not_found</id>and no entries rather than a 404.Agency-published secondary legislation links off-site. Its format URLs can point at the agency's own website, and such records usually offer only a PDF, so
list_sectionsand text extraction are unavailable for them.get_legislation_textwithformat: "pdf"returns the link.
Development
npm run build # compile to dist/
npm run dev # compile on change
npm run typecheck # type-check without emitting
npm start # run the stdio server
npm run start:http # run the HTTP serverThere is no automated test suite yet. Changes have been verified with a stdio MCP client script exercising every tool against the live API, and with a script that extracts the OpenAPI spec from the docs page and checks every path, parameter, enum value, response field, and header against the source.
Limitations and future work
No caching. Every call hits the API. An in-memory or on-disk cache for document fetches and version lists would stretch the daily quota for repeated reads.
Agency-published documents are usually PDF-only and hosted off-site, so their text cannot be extracted.
Change monitoring. A "notify me of changes" feature could poll the version feed from
list_versions_rssand diff versions.
Project layout
src/
├─ index.ts # stdio entry point (Claude Desktop / Claude Code)
├─ http.ts # streamable HTTP entry point (localhost service)
├─ server.ts # transport-independent server factory; registers all tools
├─ client.ts # HTTP client: auth, retries, rate-limit headers, feed fetching
├─ types.ts # API response types (confirmed against live responses)
├─ util.ts # response envelope, version dates, website URLs, ephemeral ids
├─ format.ts # HTML → plain text
├─ xml.ts # XML parsing and document-structure extraction
├─ feed.ts # Atom feed parsing for the legacy /api/rss/ endpoints
└─ tools/
├─ search.ts # search_legislation
├─ versions.ts # list_versions
├─ versionDetails.ts # get_version_details
├─ listSections.ts # list_sections
├─ getText.ts # get_legislation_text
├─ searchRss.ts # search_legislation_rss
├─ versionsRss.ts # list_versions_rss
├─ rateLimit.ts # get_rate_limit_status
└─ resolve.ts # work_id → newest version_id helperLicense
MIT
Available Tools
8 toolsget_legislation_textA
Retrieve the text of a piece of legislation. Provide a version_id or work_id. Without section/schedule params, returns the whole document as cleaned plain text. With a section param (e.g. "22" or "25A"), returns just that section with its Part/subpart context. With a schedule param (e.g. "1"), returns just that schedule. Use list_sections to discover numbers first. With format:"pdf", returns the official PDF download URL instead of text; format:"pdf_original_scan" returns the scan of the original printed Act (pre-2008 as-enacted versions only).
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Set to "pdf" to retrieve the official PDF download URL instead of the document text (falls back to the scanned original if no typeset PDF exists). Set to "pdf_original_scan" to require the scan of the original printed Act, which only as-enacted versions of pre-2008 Acts have. Returns the URL and metadata without downloading the file. Cannot be combined with section or schedule. | |
| exclude | No | Content types to exclude from the rendered text. By default everything is included. Options: - "cover": Front-page block (title, assent date, PCO reprint note). Already returned as structured metadata fields — exclude to avoid duplication in the text body. - "history_notes": Amendment-history entries at the end of each provision, recording when it was inserted, amended, or repealed and by which Act. Useful for understanding how law evolved; omit if you only need current text. - "comparative_references": Terse cross-references to equivalent provisions in predecessor or overseas legislation (e.g. '1952 No 43 s 4(1)'). Lineage information only — not part of the current operative law. - "editorial_notes": Two kinds of PCO annotation: (1) editorial-note elements — free-text PCO notes such as secondary legislation compliance tables, explicitly flagged in the source as 'not part of the Act'; and (2) amends-note elements — machine-readable scheduling data for amendments not yet in force, recording the trigger date/event, affected provisions, and replacement text. Exclude if you only need the current operative text. - "defined_term_links": Inland Revenue (Income Tax Act) navigation lists enumerating which defined terms appear in a provision. Website navigation aids only — not legislative text. - "end_matter": Document-tail reprint metadata — the reprint index (table of reprint dates) and reprint notes (free-text describing what each reprint changed), plus the leg-history element (structured list of reprint issuance dates). Appears once at the end of the whole document; not present when fetching a single section. | |
| section | No | Return only this section number (e.g. "22" or "25A") instead of the whole document. Use list_sections first to discover section numbers. Cannot be combined with schedule. | |
| work_id | No | A work_id; the newest version will be resolved automatically. Provide either version_id or work_id. | |
| schedule | No | Return only this schedule number (e.g. "1") instead of the whole document. Cannot be combined with section. | |
| max_chars | No | Truncate whole-document output to this many characters (default 100000). Not applied when fetching a single section or schedule. | |
| version_id | No | A specific version to read. Provide either version_id or work_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses several behavioral traits: returns cleaned plain text by default, returns PDF download URL instead of text for format pdf, falls back to scanned original if no typeset PDF exists, pdf_original_scan only available for pre-2008 as-enacted versions, max_chars truncation default 100000 and not applied to single section/schedule, and exclude options that affect output. It does not explicitly state whether the operation is read-only or has rate limits, but the sibling get_rate_limit_status exists. Given the absence of annotations, the description is quite transparent about output behavior and edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense paragraph that front-loads the core purpose and then systematically covers variants. It is longer than ideal but every sentence adds meaningful behavioral or usage information. The structure is logical: core retrieval, section/schedule variants, discovery pointer, format variants. It could be slightly more scannable with line breaks, but it is not bloated or repetitive.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 7 parameters, no output schema, and no annotations, the description is remarkably complete. It explains the default behavior, all parameter combinations, exclusions, format fallbacks, truncation behavior, and points to list_sections for discovery. The only minor gap is not describing the exact structure of the returned text/URL, but the description explicitly says 'returns the URL and metadata' for PDF formats and 'cleaned plain text' for text, which is sufficient for an agent to invoke correctly. The sibling get_rate_limit_status covers rate-limit concerns.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 7 parameters. The description adds value by explaining the interaction between parameters: section/schedule cannot be combined, format cannot be combined with section/schedule, max_chars not applied to single section/schedule, and the fallback behavior for pdf format. It also clarifies that work_id resolves to newest version automatically. This goes beyond the schema's individual parameter descriptions, though the schema already does heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves legislation text, with a specific verb ('Retrieve') and resource ('text of a piece of legislation'). It distinguishes itself from siblings by mentioning list_sections for discovering section numbers and by describing format variants (pdf, pdf_original_scan) that no sibling tool name suggests. The description also clarifies the difference between whole-document, section, and schedule retrieval, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells the agent when to use this tool vs alternatives: 'Use list_sections to discover numbers first.' It also provides clear conditional guidance: without section/schedule params returns whole document, with section returns just that section, with schedule returns just that schedule, and with format pdf returns URL instead of text. It also states constraints like 'Cannot be combined with section or schedule' for format, and 'Cannot be combined with schedule' for section. This is explicit when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rate_limit_statusA
Report remaining daily quota from the X-RateLimit-* response headers: the JSON API key (10,000 requests/day) and the feed key (1,500 requests/day). Quotas reset at midnight NZ time. By default spends one minimal API request to get fresh numbers; refresh:"none" returns the values last observed. The separate burst limit of 2,000 requests per 5 minutes per IP is not reported in headers.
| Name | Required | Description | Default |
|---|---|---|---|
| refresh | No | Which quota to re-check with one minimal request each (default "api"). "none" returns the values last observed by earlier tool calls without spending a request. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full behavioral disclosure. It transparently states that a minimal API request is spent by default, explains the reset time (midnight NZ time), and discloses that the burst limit is not reported in headers. This goes beyond basic purpose and informs the agent of side effects and limitations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured paragraph. It front-loads the core purpose, then details refresh behavior and limitations. Every sentence adds essential information; there is no filler or repetition. It is concise yet complete.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Without an output schema, the description explains what the tool returns (remaining quota values) and covers the main operational details: refresh options, default behavior, reset time, and the absence of burst-limit info. An agent has enough context to invoke the tool correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'refresh' is fully covered by the schema (100% coverage) with enum values and descriptions. The tool description adds value by clarifying the default ('api'), the meaning of 'none' (returns last observed without spending a request), and the distinction between API and feed quotas. This supplements the schema without redundancy.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it reports remaining daily quota from X-RateLimit-* headers, distinguishing between JSON API key and feed key. It clearly differentiates from sibling tools that handle legislation search/retrieval, making the tool's purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the default behavior (spends one minimal request) and the refresh parameter options, including the 'none' behavior for returning cached values. It also notes the burst limit is not reported, setting expectations. While it doesn't explicitly name alternatives, siblings are unrelated, so this is sufficient guidance for when to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_version_detailsA
Get metadata for a single version, including the list of available document formats (html, pdf, xml) and their URLs.
| Name | Required | Description | Default |
|---|---|---|---|
| version_id | Yes | A version_id from a search result or list_versions call. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that the tool returns metadata including format URLs, which is useful. However, it does not explicitly state that the operation is read-only or free of side effects, nor does it mention any prerequisites or error behavior. For a simple 'get' tool the implied read-only nature is reasonable, but the lack of explicit disclosure prevents a higher score.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, concise sentence that front-loads the purpose ('Get metadata') and immediately provides specific details about the output. No unnecessary words or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one parameter and no output schema, the description sufficiently explains what it returns (metadata and format URLs). It is complete for a simple read operation, though it does not mention any edge cases or additional metadata fields. Given the low complexity, this is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes version_id as 'A version_id from a search result or list_versions call', covering 100% of parameters. The description adds no additional information about the parameter or its usage, so it meets the baseline but does not go beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'get' and the resource 'metadata for a single version', and further specifies the output includes available document formats and URLs. This distinguishes it from sibling tools like list_versions (which lists versions) and get_legislation_text (which gets text), so an agent can readily tell what it does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: when you need a single version's metadata and format URLs, this is the tool. However, it does not explicitly mention when not to use it or name alternatives. The distinction from siblings is implicit but not spelled out, leaving some inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sectionsA
List the structure of a legislation document: Parts, subparts, section numbers and headings, and schedules. Use this before get_legislation_text to find the right section or schedule number.
| Name | Required | Description | Default |
|---|---|---|---|
| work_id | No | A work_id; the newest version will be used. Provide either version_id or work_id. | |
| version_id | No | A specific version to inspect. Provide either version_id or work_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral burden. It does disclose the output scope (parts, subparts, section numbers, headings, schedules), which is the core contract for a read-only navigation tool. However, it does not address the both-optional-parameter case (what happens with neither work_id nor version_id), pagination for large documents, or how a work_id is obtained — meaningful gaps given there is no annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste: the first states purpose and output scope, the second gives the usage workflow. Every sentence earns its place and the key information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Purpose, output scope, and workflow position are all present, and the parameter either/or relationship is fully covered by the schema. Minor gaps remain: the description doesn't note how to obtain a work_id/version_id (e.g., via list_versions) or what to expect on very large documents, and there is no output schema to describe the return shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: both parameters already carry the 'Provide either version_id or work_id' semantics and the 'newest version will be used' resolution note. The description adds no parameter-level detail, so the schema baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('structure of a legislation document'), then enumerates exactly what is included: 'Parts, subparts, section numbers and headings, and schedules.' The content enumeration distinguishes it from siblings like get_legislation_text (content retrieval) and list_versions (version metadata).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly positions the tool in a workflow: 'Use this before get_legislation_text to find the right section or schedule number.' It names the downstream alternative tool and the condition that selects it, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_versionsA
List all point-in-time versions of a work (identified by work_id), newest first by default, each with its website URL; the newest carries is_latest_version: true. Work-level metadata (title, type, status, agencies) is reported once at the top rather than repeated per version. Fetches every page automatically (the API serves at most 100 per page); pass page (and optionally per_page) to fetch a single page instead. Use this to find a version_id for a specific date.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Fetch only this page of results. Omit to fetch every page and return all versions. | |
| sort | No | Order versions by date, ascending or descending (default desc = newest first). | |
| work_id | Yes | The work_id from a search result (e.g. "act_public_2020_31"). | |
| per_page | No | Page size (default 100, the API maximum). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does well: it discloses automatic pagination, the 100-per-page API limit, default sort order, the is_latest_version flag, and de-duplicated work-level metadata. This goes well beyond a bare 'list versions' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each earning its place: purpose, return shape, pagination behavior, and intended use case. The most important capability is front-loaded before implementation details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description still tells the agent what results look like, how pagination behaves, and when to use the tool. Nothing essential for correct invocation or interpretation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters in detail. The description reinforces the page/per_page behavior and the work_id source, but adds little beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('point-in-time versions of a work'), with clear scoping by work_id. It distinguishes itself from siblings by describing what it returns (versions with URLs and is_latest_version flag) versus details, text, or sections.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this to find a version_id for a specific date,' which gives a concrete use case. It also explains pagination behavior clearly, but does not name alternative tools or explicitly state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_versions_rssA
Read the legacy Atom feed of a work's versions (the documented /api/rss/works/{work_id}/versions/ endpoint). Returns one entry per version with its website URL, derived version_id, and publication timestamp, plus a subscribable feed URL for change monitoring. Needs LEGISLATION_NZ_RSS_API_KEY, a separate RSS-only key. For on-demand queries prefer list_versions.
| Name | Required | Description | Default |
|---|---|---|---|
| work_id | Yes | The work_id whose version feed to read (e.g. "act_public_2020_31"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses the auth requirement (LEGISLATION_NZ_RSS_API_KEY), describes the return contents (entries with URL, version_id, timestamp, feed URL), and flags the tool as legacy. It does not mention rate limits or error conditions, but the core behavior is transparent enough for a simple read tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, with the core purpose and endpoint in the first sentence, return structure and use case in the second, auth and alternative in the third. Each sentence earns its place, and the most important information is front-loaded. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with no output schema, the description covers the essential aspects: what it reads, what it returns, the auth key, and when to choose an alternative. It omits explicit mention of pagination or output format, but since it is an Atom feed and the scope is small, the description is sufficiently complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the work_id parameter is already well-documented with an example. The description adds no additional parameter details beyond including work_id in the endpoint path, so it stays at the baseline score; no compensation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Read'), names the exact resource ('legacy Atom feed of a work's versions'), and cites the endpoint path. It also distinguishes itself from the sibling list_versions by calling out the preference for on-demand queries, leaving no ambiguity about what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to prefer the alternative tool ('For on-demand queries prefer list_versions') and implies the suitable use case for this tool ('subscribable feed URL for change monitoring'). It also conveys the separate API key requirement, which is a key prerequisite for using this tool correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_legislationA
Search New Zealand legislation (acts, bills, secondary legislation, amendment papers) by title or full-text content, or browse by omitting search_term and using filters alone. Returns matching works with their newest matching version id, website URLs, publisher, and available formats. latest_matching_version_is_latest is false when a content search matched only an older version (e.g. text since repealed). Type-specific filters (act_*, bill_*, instrument_*) imply legislation_type; mixing types is rejected. Ids containing ~ are ephemeral and carry ephemeral: true. Use this first to find a work_id or version_id.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1). | |
| sort_by | No | Result ordering. | |
| act_type | No | Restrict acts to a subtype (e.g. public vs local/private). Acts only; implies legislation_type "act". | |
| per_page | No | Results per page (default 20, max 100). | |
| bill_type | No | Restrict bills to a type. Bills only; implies legislation_type "bill". | |
| publisher | No | Restrict by the publishing body. | |
| act_status | No | Restrict acts by their current legislative standing. Acts only; implies legislation_type "act". | |
| bill_status | No | Restrict bills by their current status. Bills only; implies legislation_type "bill". | |
| search_term | No | Search phrase. Supports ElasticSearch simple query syntax (e.g. "privacy", "data +breach"); stemming is on by default, wrap a phrase in double quotes to disable it. Omit it to browse: the filters alone (or no filters at all) list every matching work. | |
| search_field | No | Search titles only, or full document content. Defaults to the API default (title). | |
| legislation_type | No | Restrict to a category of legislation. Inferred automatically when an act_*, bill_*, or instrument_* filter is given. | |
| instrument_status | No | Restrict secondary legislation by its current status. Secondary legislation only; implies legislation_type "secondary_legislation". | |
| act_classification | No | Restrict acts to principal (foundational) or amendment acts. Acts only; implies legislation_type "act". | |
| legislation_status | No | Restrict by whether the legislation is currently in force. | |
| instrument_type_group | No | Restrict secondary legislation to an instrument type group. Secondary legislation only; implies legislation_type "secondary_legislation". | |
| administering_agencies | No | Filter by administering agency. Must be the agency's full name exactly as listed at https://www.legislation.govt.nz/browse/agencies (e.g. "Ministry of Justice"). | |
| instrument_classification | No | Restrict secondary legislation to principal or amendment instruments. Secondary legislation only; implies legislation_type "secondary_legislation". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It discloses meaningful quirks: ephemeral ids (~) carry ephemeral:true, latest_matching_version_is_latest is false when only an older version matched, and type-specific filters imply legislation_type. It does not cover rate limits or auth, but for a read/search tool these are less critical.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five sentences pack a large amount of information: scope, modes, return fields, a subtle result-field condition, filter interaction, ephemeral-id handling, and a usage priority hint. No filler or redundant restatement of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a 17-parameter tool with no output schema and no annotations, but the description covers the essential behavioral nuances and result fields. Pagination/sorting defaults are left to the schema, which is acceptable. It gives an agent enough context to select and invoke the tool correctly in most situations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds cross-parameter semantics beyond individual schema entries: type-specific filters imply legislation_type and cannot be mixed, and browsing is achieved by omitting search_term. The Elasticsearch syntax and stemming note already appears in the schema, so the added value is useful but modest.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Search') and resource ('New Zealand legislation'), enumerating the categories and the two operation modes (search vs browse). It clearly describes the return fields. It doesn't explicitly contrast with the sibling search_legislation_rss, but the 'Use this first to find a work_id or version_id' hint helps define its role among the siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this first to find a work_id or version_id' and explains when to browse (omit search_term, use filters alone). It also warns that mixing type-specific filters is rejected. Missing: does not name alternatives for other tasks (e.g., list_versions, get_legislation_text), so the routing guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_legislation_rssA
Search New Zealand legislation through the legacy Atom feed (the documented /api/rss/search/ endpoint) by title or full text, with type and status filters; omit search_term to browse by filters alone. Returns up to 100 feed entries (title, website URL, derived work_id/version_id, timestamps) plus a subscribable feed URL. Needs LEGISLATION_NZ_RSS_API_KEY, a separate RSS-only key. For on-demand queries prefer search_legislation, which is a superset.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Return at most this many entries. The feed itself returns up to 100 entries and ignores paging parameters. | |
| search_term | No | Search phrase. ElasticSearch simple query syntax; stemming is on by default (wrap a phrase in double quotes to disable it). Omit it to browse by the filters alone. | |
| search_field | No | Search titles only (the feed's default) or the full document text. "content" and "fulltext" both mean full text: the documentation says fulltext, but the live feed only honours content, so either is sent as content. | |
| legislation_type | No | Restrict to a category of legislation. | |
| legislation_status | No | Restrict by whether the legislation is currently in force. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full responsibility and does so thoroughly: it discloses the legacy endpoint, the 100-entry limit, the need for a separate RSS-only API key, and the actual behavior of search_field where 'content' and 'fulltext' are both sent as content. It also notes paging is ignored. This exceeds what a typical description provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is information-dense but well-organized, starting with the core purpose and then layering in essential behavioral details. It is slightly long, but every sentence serves a purpose—no filler. The structure is logical, moving from action to parameters to usage guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (5 params, no output schema), the description covers everything an agent needs: what it returns (entries with fields and a subscribable feed URL), the key requirement (API key), limitations (100 entries), and parameter semantics. It is self-contained and leaves no critical gaps for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds substantial meaning: it explains ElasticSearch query syntax, stemming and quoting, clarifies the search_field enum mapping, and describes the limit behavior and its interaction with the feed. This goes beyond the schema's terse descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches New Zealand legislation via the legacy Atom feed, supports title/full-text search with filters, and explicitly differentiates from the sibling search_legislation by noting it is a superset for on-demand queries. The verb and resource are specific, and the distinction prevents ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly advises 'For on-demand queries prefer search_legislation, which is a superset,' giving clear when-to-use guidance and naming the alternative. It also explains the browse-by-filters use case when search_term is omitted, covering both main usage patterns.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
get_legislation_text - First observed
get_rate_limit_status - First observed
get_version_details - First observed
list_sections - First observed
list_versions - First observed
list_versions_rss - First observed
search_legislation - First observed
search_legislation_rss
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose: searching vs listing versions vs retrieving text vs structure vs rate limits. The RSS variants are explicitly marked as legacy alternatives and are superseded by their modern counterparts, so no ambiguity remains.
All tools follow a consistent snake_case verb_noun pattern (search_, list_, get_). The _rss suffix is applied uniformly to the two RSS-specific tools, and the rest follow the same style without deviation.
8 tools is well-scoped for a legislation retrieval server. Each tool serves a distinct need—search, version enumeration, metadata, text, structure, RSS alternatives, and quota monitoring—without unnecessary bloat.
The tool surface covers the full read-only lifecycle: discovery (search, browse), version exploration, document retrieval in multiple formats, structure navigation, and rate limit monitoring. No obvious gaps exist for the domain; even PDF downloads and legacy RSS access are included.
Maintenance
Related MCP Connectors
Japan Law MCP — Japanese national laws & ordinances via the e-Gov Law API.
Search UK Acts, Statutory Instruments, and legislation with full text retrieval
- LegalizeOAuthdev.legalize
Official MCP connector for Legalize: read and search its whole open corpus, at any point in time.
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables searching and retrieval of UK legislation (Acts, Statutory Instruments) from legislation.gov.uk with persistent identifiers and verifiable citations.942 PyPIApache 2.0
- AlicenseAqualityAmaintenanceMCP server for Australia's Federal Register of Legislation. Enables searching and fetching Commonwealth Acts with verifiable citations.3Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables searching and retrieving Korean statutes, precedents, and constitutional court decisions via MCP, using the National Law Information Center API.1,542 npm1MIT
- AlicenseAqualityAmaintenanceEnables retrieval of Canadian federal legislation (Acts and regulations) from the Justice Laws Website by code, providing metadata and full consolidated text in English and French.3Apache 2.0