Get GOV.UK Page Section
govuk_get_sectionRetrieve the HTML content of a specific section from a GOV.UK page by providing the base path and section anchor ID. Use after obtaining the list of available sections.
Instructions
Get the HTML content of one named section of a GOV.UK page.
Use govuk_get_content first to get the list of available section anchors, then call this with the anchor of the section you want to read.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| base_path | Yes | GOV.UK base_path, e.g. '/universal-credit' | |
| anchor | Yes | Section anchor ID from govuk_get_content sections list |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- govuk_mcp/server.py:469-478 (registration)The tool 'govuk_get_section' is registered via the @mcp.tool decorator with name='govuk_get_section' and annotations for title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint.
@mcp.tool( name="govuk_get_section", annotations={ "title": "Get GOV.UK Page Section", "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": True, }, ) - govuk_mcp/server.py:480-502 (handler)The async function govuk_get_section handles the tool logic: fetches content from GOV.UK Content API using the base_path, then calls parsers.extract_section(payload, anchor) to extract the HTML for the named section. Raises ValueError if the anchor is not found.
async def govuk_get_section( base_path: Annotated[str, Field(description="GOV.UK base_path, e.g. '/universal-credit'", min_length=1, max_length=500)], anchor: Annotated[str, Field(description="Section anchor ID from govuk_get_content sections list", min_length=1, max_length=200)], ctx: Context, ) -> dict: """Get the HTML content of one named section of a GOV.UK page. Use govuk_get_content first to get the list of available section anchors, then call this with the anchor of the section you want to read. """ path = base_path.lstrip("/") client = _client(ctx) resp = await client.get(f"{CONTENT_BASE}/{path}") resp.raise_for_status() payload = resp.json() try: html = parsers.extract_section(payload, anchor) except KeyError: raise ValueError( f"Section '{anchor}' not found in '{base_path}'. " "Use govuk_get_content to list available anchors." ) return {"base_path": base_path, "anchor": anchor, "content": html} - govuk_mcp/parsers.py:85-114 (helper)The extract_section function is the core parsing helper. It handles both guide-format pages (using details.parts by slug) and standard pages (slicing HTML between <h2 id='anchor'> tags). Raises KeyError if anchor not found.
def extract_section(payload: dict, anchor: str) -> str: """Return the content for a named section. For guide-format pages: returns the body of the part whose slug matches anchor. For standard pages: returns the HTML slice from `<h2 id="anchor">` to the next `<h2 id="...">`. Raise KeyError if no such anchor exists. """ details = payload.get("details", {}) # Guide format: look in parts by slug parts = details.get("parts") or [] if parts: for part in parts: if part.get("slug") == anchor: return part.get("body", "") raise KeyError(f"No part with slug {anchor!r}") # Standard format: h2 slice in body body = details.get("body", "") pattern = re.compile( rf'<h2\b[^>]*\bid="{re.escape(anchor)}"[^>]*>', re.IGNORECASE, ) m = pattern.search(body) if not m: raise KeyError(f"No <h2 id={anchor!r}> in body") rest = body[m.end():] next_m = _HEADING_WITH_ID.search(rest) end = m.end() + next_m.start() if next_m else len(body) return body[m.start():end] - govuk_mcp/server.py:481-484 (schema)Input parameters defined via Pydantic Field annotations: base_path (str, 1-500 chars) and anchor (str, 1-200 chars). Return type is dict (informal, not a Pydantic model).
base_path: Annotated[str, Field(description="GOV.UK base_path, e.g. '/universal-credit'", min_length=1, max_length=500)], anchor: Annotated[str, Field(description="Section anchor ID from govuk_get_content sections list", min_length=1, max_length=200)], ctx: Context, ) -> dict: