Skip to main content
Glama

Hansard Policy Position Summary (deterministic facets)

parliament_policy_position_summary
Read-onlyIdempotent

USE THIS TOOL WHEN you want debate-level corpus signals on a topic — by_house, by_year, by_section breakdowns — without reading every contribution.

Aggregates Hansard debate-level signals on a topic. Pure counts — no LLM, no editorial labels. Sweeps /search/Debates.json with pagination (up to max_debates_scanned), then aggregates by_house, by_section, by_year, by_month, and top_debates from debate metadata. Also captures the corpus-wide envelope counts (total_contributions, total_written_statements, total_divisions, etc.) from /search.json for cross-section scope.

AFTER calling, pick a debate from top_debates and pass its debate_ext_id into parliament_get_debate_contributions to drill into who said what.

Note on member-level facets: Hansard's search API exposes debate metadata, not per-contribution member identifiers, at the corpus level. by_party and top_contributors are therefore omitted from this deterministic summary. To see who spoke in a specific debate, read hansard://debate/{debate_ext_id}/header for an ordered contribution index, or call parliament_member_debates for one named member.

This is the authoritative source for UK Hansard corpus-level signals.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
houseNoRestrict to one House. Default 'both'.both
topicYesPhrase to find in Hansard contribution text bodies for the facet aggregation. Same semantics as parliament_search_hansard.query: tokens that appear in members' actual speeches, not bill titles or topic metadata. The aggregator sweeps top_debates[] returned by /search/Debates.json — those debates are matched on the phrase appearing in titles or contribution text, so passing a Bill title (e.g. 'Renters\' Rights Bill') usually works for THIS tool even though it wouldn't for member-level text search, because debate-level matching uses metadata in addition to body text.
to_dateNoEnd date (YYYY-MM-DD)
from_dateNoStart date (YYYY-MM-DD)
max_debates_scannedNoHard cap on debates sampled from /search/Debates.json to compute facets. Default 200 issues ≤4 upstream calls (take=50 each). Raise to 2000 (≤40 calls) for an exhaustive sweep on a heavily-debated topic. Hansard rate limit: 1000 req/5min.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
houseYesHouse filter applied
topicYesPhrase searched in Hansard
by_yearNoCounts of debates by sitting year, desc by year
to_dateNoEnd date filter applied
by_houseNoCounts of debates by house (Commons vs Lords)
by_partyNoCounts by party. ALWAYS EMPTY in this summary — Hansard's search API only exposes member identifiers at the per-debate level, not the corpus level. For party breakdown within one debate, read hansard://debate/{ext_id}/header. For one member's contributions across the corpus, use parliament_member_debates.
from_dateNoStart date filter applied
by_sectionNoCounts of debates by Hansard section bucket (Chamber / Westminster Hall / Written Answers / Written Statements)
top_debatesNoTop 20 debates ranked by upstream relevance_rank, with debate_ext_id for hansard://debate/{debate_ext_id}/header drill-down. contribution_count is null in this preview shape (would require a secondary call per debate).
total_debatesYesTotal distinct debates touching this topic (TotalDebates)
debates_scannedYesNumber of debates pulled from /search/Debates.json for the facet breakdown (≤ max_debates_scanned)
total_divisionsYesTotalDivisions upstream count. Non-zero → consider votes_search_divisions.
top_contributorsNoALWAYS EMPTY in this summary — see by_party note. Use parliament_member_debates after picking a debate from top_debates.
by_month_recent_12NoCounts of debates by YYYY-MM for the most recent 12 months in the sample, desc by month
total_contributionsYesTotal contributions in Hansard matching topic+filters (TotalContributions)
total_written_answersYesTotalWrittenAnswers upstream count
total_written_statementsYesTotalWrittenStatements upstream count

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedOutput schema / properties / top_contributors / items / properties / party / description
      Previous value: -"Party affiliation parsed from AttributedTo"New value: +"Not derivable from Hansard's AttributedTo (see HansardContribution.party) — would require resolving member_id via parliament_find_member. Currently unused: top_contributors is always empty (see PolicyPositionSummary.by_party)."
  2. Changed1 schema field changed
    • changedOutput schema / properties / top_debates / items / properties / debate_id / description
      Previous value: -"Internal Hansard debate ID (DebateSectionId)"New value: +"Internal Hansard debate ID."
  3. Changed7 schema fields changed
    • addedInput schema / properties / from_date
      Added value: +{
      +  "anyOf": [
      +    {
      +      "format": "date",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Start date (YYYY-MM-DD)"
      +}
    • addedInput schema / properties / house
      Added value: +{
      +  "default": "both",
      +  "description": "Restrict to one House. Default 'both'.",
      +  "enum": [
      +    "Commons",
      +    "Lords",
      +    "both"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / max_debates_scanned
      Added value: +{
      +  "default": 200,
      +  "description": "Hard cap on debates sampled from /search/Debates.json to compute facets. Default 200 issues ≤4 upstream calls (take=50 each). Raise to 2000 (≤40 calls) for an exhaustive sweep on a heavily-debated topic. Hansard rate limit: 1000 req/5min.",
      +  "maximum": 2000,
      +  "minimum": 50,
      +  "type": "integer"
      +}
    • removedInput schema / properties / params
      Removed value: -{
      -  "additionalProperties": false,
      -  "description": "PolicyPositionSummaryInput with topic, optional date range, house, max_debates_scanned.",
      -  "properties": {
      -    "from_date": {
      -      "anyOf": [
      -        {
      -          "format": "date",
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Start date (YYYY-MM-DD)"
      -    },
      -    "house": {
      -      "default": "both",
      -      "description": "Restrict to one House. Default 'both'.",
      -      "enum": [
      -        "Commons",
      -        "Lords",
      -        "both"
      -      ],
      -      "type": "string"
      -    },
      -    "max_debates_scanned": {
      -      "default": 200,
      -      "description": "Hard cap on debates sampled from /search/Debates.json to compute facets. Default 200 issues ≤4 upstream calls (take=50 each). Raise to 2000 (≤40 calls) for an exhaustive sweep on a heavily-debated topic. Hansard rate limit: 1000 req/5min.",
      -      "maximum": 2000,
      -      "minimum": 50,
      -      "type": "integer"
      -    },
      -    "to_date": {
      -      "anyOf": [
      -        {
      -          "format": "date",
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "End date (YYYY-MM-DD)"
      -    },
      -    "topic": {
      -      "description": "Phrase to find in Hansard contribution text bodies for the facet aggregation. Same semantics as parliament_search_hansard.query: tokens that appear in members' actual speeches, not bill titles or topic metadata. The aggregator sweeps top_debates[] returned by /search/Debates.json — those debates are matched on the phrase appearing in titles or contribution text, so passing a Bill title (e.g. 'Renters' Rights Bill') usually works for THIS tool even though it wouldn't for member-level text search, because debate-level matching uses metadata in addition to body text.",
      -      "maxLength": 200,
      -      "minLength": 2,
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "topic"
      -  ],
      -  "type": "object"
      -}
    • addedInput schema / properties / to_date
      Added value: +{
      +  "anyOf": [
      +    {
      +      "format": "date",
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "End date (YYYY-MM-DD)"
      +}
    • addedInput schema / properties / topic
      Added value: +{
      +  "description": "Phrase to find in Hansard contribution text bodies for the facet aggregation. Same semantics as parliament_search_hansard.query: tokens that appear in members' actual speeches, not bill titles or topic metadata. The aggregator sweeps top_debates[] returned by /search/Debates.json — those debates are matched on the phrase appearing in titles or contribution text, so passing a Bill title (e.g. 'Renters\\' Rights Bill') usually works for THIS tool even though it wouldn't for member-level text search, because debate-level matching uses metadata in addition to body text.",
      +  "maxLength": 200,
      +  "minLength": 2,
      +  "type": "string"
      +}
    • changedInput schema / required
      Previous value: -[
      -  "params"
      -]New value: +[
      +  "topic"
      +]
  4. Changed1 schema field changed
    • changedInput schema / properties / params / properties / topic / description
      Previous value: -"Phrase to search in Hansard, e.g. 'short selling regulation'. Searched as an exact phrase. For broader recall, drop quotes by shortening the topic."New value: +"Phrase to find in Hansard contribution text bodies for the facet aggregation. Same semantics as parliament_search_hansard.query: tokens that appear in members' actual speeches, not bill titles or topic metadata. The aggregator sweeps top_debates[] returned by /search/Debates.json — those debates are matched on the phrase appearing in titles or contribution text, so passing a Bill title (e.g. 'Renters' Rights Bill') usually works for THIS tool even though it wouldn't for member-level text search, because debate-level matching uses metadata in addition to body text."
  5. Changed2 schema fields changed
    • addedOutput schema / properties / top_debates / items / properties / source
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Human-readable Hansard publication state (Swagger Source enum name). Tells a lawyer the citation's finality — RollingHansard/DailyHansard are pre-consolidation, BoundVolume/Historic are final bound volumes. Does NOT indicate whether the citation resolves: column lookup resolves across all four states."
      +}
    • addedOutput schema / properties / top_debates / items / properties / source_code
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Raw Hansard Overview.Source ordinal: 1=RollingHansard, 2=DailyHansard, 3=BoundVolume, 4=Historic. Populated only when the emitting tool fetches the debate payload (today: parliament_lookup_by_column); null otherwise."
      +}
  6. Changed9 schema fields changed
    • changedOutput schema / properties / top_debates / description
      Previous value: -"Top 20 debates ranked by upstream search relevance (Rank), with debate_ext_id for hansard://debate/{debate_ext_id}/header lookup. contribution_count in this list carries the upstream Rank score, not an actual contribution count (which requires fetching each debate's full Items list — too costly for a summary)."New value: +"Top 20 debates ranked by upstream relevance_rank, with debate_ext_id for hansard://debate/{debate_ext_id}/header drill-down. contribution_count is null in this preview shape (would require a secondary call per debate)."
    • changedOutput schema / properties / top_debates / items / description
      Previous value: -"A top debate section by contribution volume in the sampled window."New value: +"A top debate section returned as a search/lookup preview or aggregate result."
    • addedOutput schema / properties / top_debates / items / properties / contribution_count / anyOf
      Added value: +[
      +  {
      +    "minimum": 0,
      +    "type": "integer"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedOutput schema / properties / top_debates / items / properties / contribution_count / default
      Added value: +null
    • changedOutput schema / properties / top_debates / items / properties / contribution_count / description
      Previous value: -"Number of contributions in this debate matching the topic"New value: +"Number of contributions in this debate. Populated only when the emitting tool fetches the debate's full Items list (today: parliament_lookup_by_column). Null on preview arrays where the secondary fetch is too costly."
    • removedOutput schema / properties / top_debates / items / properties / contribution_count / minimum
      Removed value: -0
    • removedOutput schema / properties / top_debates / items / properties / contribution_count / type
      Removed value: -"integer"
    • addedOutput schema / properties / top_debates / items / properties / relevance_rank
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Upstream Hansard relevance score for this debate against the search query (0–100). Populated for relevance-scored searches (parliament_search_hansard, parliament_policy_position_summary). Null for column-lookup matches — the column-search endpoint does not rank."
      +}
    • changedOutput schema / properties / top_debates / items / required
      Previous value: -[
      -  "debate_id",
      -  "debate_ext_id",
      -  "debate_title",
      -  "date",
      -  "house",
      -  "contribution_count"
      -]New value: +[
      +  "debate_id",
      +  "debate_ext_id",
      +  "debate_title",
      +  "date",
      +  "house"
      +]
  7. Changed1 schema field changed
    • changedOutput schema / properties / top_contributors / items / properties / member_id / description
      Previous value: -"Members API integer ID. Use as `member_id` in parliament_member_debates / parliament_member_interests, or as {member_id} in hansard://member/{member_id}/biography for role history."New value: +"Members API integer ID. Use as {member_id} in hansard://member/{member_id}/biography for the member's role history."
  8. Added

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint, idempotentHint, openWorldHint, destructiveHint=false. The description adds behavior beyond that: it sweeps /search/Debates.json with pagination, states the hard cap semantics, discloses the rate limit ('1000 req/5min'), notes that by_party and top_contributors are deliberately omitted due to upstream limitations, and confirms 'no LLM, no editorial labels'. The omission disclosure is unusually valuable context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the WHEN clause; each sentence carries a distinct point (trigger, mechanics, follow-up, member-facet caveat, authority claim). The member-facet note is a bit long but earns its place by explaining an omission. Some repetition between the title and 'authoritative source' sentence, but overall tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

All key facets of the tool's behavior are covered for an agent: when to use it, what it aggregates, the sweep mechanism and cost, the follow-up path, and known limitations (missing member-level facets). With an output schema present, no return-value explanation is required, and nothing material is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

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 five parameters, including defaults, enums, and the rate-limit note in max_debates_scanned. The description briefly contrasts topic semantics with parliament_search_hansard.query (debate-level metadata matching vs body text), which is a small addition, but mostly repeats what the schema already says. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The title and body state a specific verb (aggregate) and resource (Hansard debate-level signals on a topic), and it explicitly differentiates itself from text-search siblings (parliament_search_hansard) by describing the facet-aggregation output (by_house, by_year, by_section). The mention of 'authoritative source for UK Hansard corpus-level signals' anchors the scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The opening 'USE THIS TOOL WHEN...' clause states the trigger condition, and it names a clear follow-up ('pass debate_ext_id into parliament_get_debate_contributions') plus an alternative for member-level queries (hansard://debate/.../header or parliament_member_debates). It doesn't fully name what this tool is not for versus parliament_search_hansard, but the WHEN clause plus alternatives is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.