UK Legal Research
Qué hace este MCP
Researches UK case law, legislation, parliamentary materials, HMRC guidance, bills, committees, and OSCOLA citations.
Herramientas
Esquema de entrada
{'type': 'object', 'required': ['bill_id'], 'properties': {'bill_id': {'type': 'integer', 'minimum': 1, 'description': 'Bill ID from bills_search_bills results.'}, 'max_summary_chars': {'type': 'integer', 'default': 5000, 'maximum': 50000, 'minimum': 500, 'description': 'Maximum characters of the bill summary text to return. Default 5,000 (~1,250 tokens) covers most bills. Raise for substantive government bills (Finance Act, Levelling-up) whose summary runs longer. Check summary_truncated in the response to see if it was cut.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['id', 'short_title', 'url'], 'properties': {'id': {'type': 'integer', 'description': 'Bill ID'}, 'url': {'type': 'string', 'description': 'Parliament URL for this bill'}, 'is_act': {'type': 'boolean', 'default': False, 'description': 'Whether the bill has received Royal Assent'}, 'stages': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the stage was reached'}, 'name': {'type': 'string', 'description': "Stage name, e.g. 'Second Reading'"}, 'house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House where stage occurred'}, 'is_current': {'type': 'boolean', 'default': False, 'description': 'Whether this is the current stage'}}}, 'description': 'Legislative stages the bill has passed through'}, 'summary': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Bill summary text, possibly truncated per max_summary_chars. Check summary_truncated and summary_original_length for full-text info.'}, 'sponsors': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': "Sponsor's display name"}, 'house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Commons or Lords'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Political party'}}}, 'description': 'Bill sponsors'}, 'long_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Full long title'}, 'short_title': {'type': 'string', 'description': 'Short title of the bill'}, 'current_house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House where the bill currently sits'}, 'current_stage': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Current legislative stage'}, 'originating_house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House where the bill was introduced'}, 'royal_assent_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date Royal Assent was given'}, 'summary_truncated': {'type': 'boolean', 'default': False, 'description': 'True if summary was cut to fit max_summary_chars'}, 'summary_original_length': {'type': 'integer', 'default': 0, 'description': 'Original summary length in characters before any truncation'}}}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'house': {'anyOf': [{'enum': ['Commons', 'Lords', 'All'], 'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Filter by originating house: the House the bill was introduced in, wherever it sits now. Omit (or 'All') for all houses."}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'Maximum bills to return in this call. Default 20 keeps responses focused; raise up to 100 for bulk exports.'}, 'query': {'type': 'string', 'maxLength': 500, 'minLength': 1, 'description': "Search term for bill titles and descriptions, e.g. 'online safety' or 'financial services'."}, 'stage': {'anyOf': [{'enum': ['firstreading', 'secondreading', 'committee', 'report', 'thirdreading', 'royalassent'], 'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Filter by current legislative stage.'}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 2147483647, 'minimum': 0, 'description': 'Number of results to skip before this page. Default 0 for the first page. Re-call with offset=offset+returned while has_more is true to paginate.'}, 'session': {'anyOf': [{'type': 'integer', 'minimum': 1}, {'type': 'null'}], 'default': None, 'description': "Numeric parliamentary session ID (e.g. 40 = 2024-25, 39 = 2023-24). NOT a year string like '2025'. If you only know the year, omit this and filter the results instead. Omit to search all sessions."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['query', 'offset', 'limit', 'returned', 'has_more'], 'properties': {'bills': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'short_title', 'url'], 'properties': {'id': {'type': 'integer', 'description': 'Bill ID'}, 'url': {'type': 'string', 'description': 'Parliament URL for this bill'}, 'is_act': {'type': 'boolean', 'default': False, 'description': 'Whether the bill has received Royal Assent'}, 'long_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Full long title'}, 'short_title': {'type': 'string', 'description': 'Short title of the bill'}, 'current_house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House where the bill currently sits'}, 'current_stage': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Current legislative stage'}, 'originating_house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House where the bill was introduced (what the search `house` filter matches)'}}}, 'description': 'Matching bills. Use the integer `id` field from any bill to call bills_get_bill for full detail.'}, 'limit': {'type': 'integer', 'description': 'Maximum results requested in this call'}, 'query': {'type': 'string', 'description': 'The search term that was used'}, 'total': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Total results matching the query across all pages, if the upstream API reported it. None if unknown.'}, 'offset': {'type': 'integer', 'description': 'Number of results skipped before this page'}, 'has_more': {'type': 'boolean', 'description': 'True if more results exist beyond this page. Re-call with offset=offset+returned to fetch the next page.'}, 'returned': {'type': 'integer', 'description': 'Number of results actually on this page'}}, 'description': 'One page of bill search results.\n\nWraps matching BillSummary records with search metadata so the LLM\nclient sees a real nested object on the wire, and can page through\nlarge result sets.'}
Esquema de entrada
{'type': 'object', 'required': ['slug', 'pattern'], 'properties': {'slug': {'type': 'string', 'minLength': 8, 'description': "TNA judgment slug, e.g. 'uksc/2024/12' or 'ewca/civ/2023/450'."}, 'pattern': {'type': 'string', 'maxLength': 200, 'minLength': 2, 'description': "Regex pattern (or plain substring) to search within paragraph text. If the pattern doesn't compile as regex, falls back to literal substring match."}, 'max_hits': {'type': 'integer', 'default': 25, 'maximum': 100, 'minimum': 1, 'description': 'Cap on number of hits returned.'}, 'case_insensitive': {'type': 'boolean', 'default': True, 'description': 'Default true. Set false for case-sensitive matching.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['slug', 'pattern', 'hits', 'truncated'], 'properties': {'hits': {'type': 'array', 'items': {'type': 'object', 'required': ['eId', 'snippet', 'match'], 'properties': {'eId': {'type': 'string', 'description': "LegalDocML paragraph identifier, e.g. 'para_12'. Use as {eId} in judgment://{slug*}/para/{eId} to read the full paragraph (typically 400-1700 tokens) with its sub-paragraphs."}, 'match': {'type': 'string', 'description': 'The exact text that matched the pattern'}, 'snippet': {'type': 'string', 'description': '~200 chars of context around the match'}}, 'description': 'A single paragraph match from grep_judgment.'}, 'description': 'Matching paragraphs in document order'}, 'slug': {'type': 'string', 'description': 'The judgment slug that was searched'}, 'pattern': {'type': 'string', 'description': 'The pattern that was searched for'}, 'truncated': {'type': 'boolean', 'description': 'True if hit count reached max_hits and more matches may exist'}}, 'description': 'Output schema for case_law_grep_judgment.'}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'page': {'type': 'integer', 'default': 1, 'maximum': 50, 'minimum': 1, 'description': 'Result page number (1-indexed)'}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Filter by court slug. Values: 'uksc', 'ukpc', 'ewca/civ', 'ewca/crim', 'ewhc/kb', 'ewhc/ch', 'ewhc/comm', 'ewhc/fam', 'ewhc/pat', 'ewhc/ipec', 'ewhc/admin', 'ewhc/tcc', 'ewhc/costs', 'ewfc', 'ewcop', 'eat', 'ukut/iac', 'ukut/aac', 'ukut/tcc', 'ukut/lc', 'ukftt/tc', 'ukftt/grc', 'nica', 'niqb'."}, 'judge': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Filter by judge surname. Case-insensitive substring match against the indexed form. Use the surname alone ('Reed', 'Sumption') or with the bare title ('Lord Reed'). Honorific suffixes silently zero the result set — do not append 'JSC', 'of Allermuir', 'KC' etc. Speculating a fuller form than what TNA indexed will return 0 hits with no error."}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Maximum results to return (1–50). TNA returns up to 50 per request; this slices client-side. Default 10 for a tight shortlist. Set higher for breadth (e.g. 50 to scan the full result set).'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Filter by party name'}, 'query': {'type': 'string', 'maxLength': 500, 'minLength': 1, 'description': "Full-text search query, e.g. 'negligence duty of care'"}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Latest judgment date (YYYY-MM-DD). Same caveat as `from_date` — currently silently ignored by upstream. Filtering happens client-side at best.'}, 'from_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Earliest judgment date (YYYY-MM-DD). NOTE: the TNA atom.xml endpoint currently appears to ignore this filter — the same results come back regardless. Do not rely on it to narrow output; sort+slice client-side or refine `query` instead.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['results', 'page', 'has_more'], 'properties': {'page': {'type': 'integer', 'description': 'Current page number (1-indexed)'}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['uri', 'title', 'published', 'updated'], 'properties': {'uri': {'type': 'string', 'description': 'TNA stable document URI (pre-2025: court/year/number; post-2025: UUID)'}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Court name, e.g. 'UK Supreme Court'"}, 'title': {'type': 'string', 'description': 'Case title as published'}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'URL to PDF version'}, 'updated': {'type': 'string', 'format': 'date-time', 'description': 'Last updated timestamp'}, 'xml_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'URL to LegalDocML XML source'}, 'published': {'type': 'string', 'format': 'date-time', 'description': 'Original publication date'}, 'next_steps': {'type': 'object', 'description': 'Canonical resource URIs and the search-within tool for reading this judgment. Read `header` first for orientation (~1k tokens), then `index` to discover paragraph eIds (~4k tokens), then `paragraph_template` (substitute the eId from the index) for specific paragraphs (~400-1700 tokens each). Use `grep_tool` for content discovery instead of brute-forcing every paragraph.', 'additionalProperties': {'type': 'string'}}, 'identifiers': {'type': 'array', 'items': {'type': 'object', 'required': ['type', 'value', 'slug'], 'properties': {'slug': {'type': 'string', 'description': "URL slug form, e.g. 'uksc/2024/12'. Use as {slug*} in judgment://{slug*}/header (metadata, ~1k tokens), judgment://{slug*}/index (paragraph list, ~4k tokens), judgment://{slug*}/para/{eId} (one paragraph), or as the `slug` input to case_law_grep_judgment for pattern search."}, 'type': {'enum': ['ukncn', 'fclid'], 'type': 'string', 'description': "Identifier type: 'ukncn' for neutral citation, 'fclid' for Find Case Law internal ID"}, 'value': {'type': 'string', 'description': "Human-readable identifier, e.g. '[2024] UKSC 12'"}}, 'description': 'A structured citation identifier for a judgment.'}, 'description': 'Neutral citation and other IDs'}, 'content_hash': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'SHA256 of body text — use for change detection in polling loops'}}, 'description': 'Summary metadata for a single judgment.'}, 'description': 'Matching judgments for this page'}, 'has_more': {'type': 'boolean', 'description': 'Whether additional pages exist'}, 'total_pages': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Total page count if available from API'}}, 'description': 'Paginated search result container for judgments.'}
Esquema de entrada
{'type': 'object', 'required': ['citation_type', 'confidence'], 'properties': {'raw': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'raw' from citations_resolve. Used as-is for EU retained law — the original text preserves the Regulation/Directive distinction."}, 'page': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'page' from citations_resolve (starting page in the law report)."}, 'year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'year' from citations_resolve."}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'court' from citations_resolve, e.g. 'UKSC', 'EWCA CIV', 'EWHC (KB)'."}, 'number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'number' from citations_resolve (judgment number within the year)."}, 'volume': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'volume' from citations_resolve (law report volume, if any)."}, 'section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'section' from citations_resolve, e.g. '47', '12', '20A'."}, 'si_year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'si_year' from citations_resolve."}, 'si_number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "'si_number' from citations_resolve."}, 'confidence': {'type': 'number', 'maximum': 1.0, 'minimum': 0.0, 'description': "'confidence' from citations_resolve. Refuses to format if 0.0 — that means TNA confirmed the document does not exist. Pass only the value citations_resolve returned; do not guess."}, 'resolved_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'resolved_url' from citations_resolve. Must be non-null for neutral citations."}, 'citation_type': {'enum': ['neutral', 'law_report', 'legislation', 'si', 'eu_retained'], 'type': 'string', 'description': "'type' field from citations_resolve result."}, 'report_series': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'report_series' from citations_resolve, e.g. 'WLR', 'AC', 'QB'."}, 'legislation_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "'legislation_title' from citations_resolve, e.g. 'Companies Act 2006'."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'additionalProperties': True}
Esquema de entrada
{'type': 'object', 'required': ['case_uri'], 'properties': {'case_uri': {'type': 'string', 'minLength': 5, 'description': "TNA judgment URI slug, e.g. 'uksc/2024/12' or 'ewca/civ/2023/450'. Use the 'uri' field from case_law_search results — not the full URL. Do not include the 'https://caselaw.nationalarchives.gov.uk/' prefix."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['case_uri', 'total_citations'], 'properties': {'eu_refs': {'type': 'array', 'items': {'type': 'string'}, 'description': "Retained EU law references, e.g. 'Regulation (EU) 2016/679'"}, 'si_refs': {'type': 'array', 'items': {'type': 'string'}, 'description': "Statutory Instrument references, e.g. 'SI 2018/1234'"}, 'case_uri': {'type': 'string', 'description': 'The judgment URI that was fetched and parsed'}, 'law_report_refs': {'type': 'array', 'items': {'type': 'string'}, 'description': "Law report citations, e.g. '[2020] 1 WLR 100'"}, 'total_citations': {'type': 'integer', 'description': 'Sum of all de-duplicated citations across every bucket'}, 'legislation_refs': {'type': 'array', 'items': {'type': 'string'}, 'description': "Legislation section references, e.g. 's.47 Companies Act 2006'"}, 'neutral_citations': {'type': 'array', 'items': {'type': 'string'}, 'description': "Neutral citations referenced, e.g. '[2020] UKSC 14'"}}, 'description': 'Citations found within a single judgment, grouped by type.\n\nEach list contains the de-duplicated raw citation text as it appeared\nin the source. To resolve any entry to a URL, pass it through\ncitations_resolve.'}
Esquema de entrada
{'type': 'object', 'required': ['text'], 'properties': {'text': {'type': 'string', 'maxLength': 50000, 'minLength': 1, 'description': 'Free text containing OSCOLA citations to extract. Supported: neutral citations ([2024] UKSC 12), law reports ([2024] 1 WLR 100), legislation sections (s.47 Companies Act 2006), SIs (SI 2018/1234), retained EU law (Regulation (EU) 2016/679). Max 50,000 chars.'}, 'disambiguate': {'type': 'boolean', 'default': False, 'description': "Default False — pure-regex parsing, no model in the loop. If True, ambiguous citations (e.g. bare EWHC without a division) are sent to the connected client's own LLM, via MCP sampling, to resolve the division. Opt in only when you want best-effort division resolution and accept that a model shapes the result."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['citations', 'ambiguous', 'text_length', 'parse_duration_ms'], 'properties': {'ambiguous': {'type': 'array', 'items': {'type': 'object', 'required': ['raw', 'type', 'confidence'], 'properties': {'raw': {'type': 'string', 'description': 'Original citation text as found in the source'}, 'page': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Starting page in the law report'}, 'type': {'enum': ['neutral', 'law_report', 'legislation', 'si', 'eu_retained'], 'type': 'string', 'description': 'Classification of the citation type'}, 'year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Year component of the citation'}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Court code: UKSC, UKPC, EWCA Civ, EWCA Crim, EWHC (KB), EWHC (Ch), EWHC (Comm), EWHC (Fam), EWHC (Pat), EWHC (IPEC), UKUT (IAC), UKUT (TCC), UKUT (AAC), UKUT (LC), EAT, UKFTT (TC), UKFTT (GRC)'}, 'number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Judgment number within the year'}, 'volume': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Report volume number (for law reports)'}, 'section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Section number referenced'}, 'si_year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI year (for SI YYYY/NNN citations)'}, 'si_number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI number'}, 'confidence': {'type': 'number', 'maximum': 1.0, 'minimum': 0.0, 'description': 'Parse confidence 0.0–1.0. Citations below 0.7 are ambiguous and may have been sent for LLM disambiguation.'}, 'resolved_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'TNA Find Case Law or legislation.gov.uk URL if successfully resolved'}, 'report_series': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Law report series abbreviation: WLR, AC, QB, KB, Ch, All ER, EWCA Civ, etc.'}, 'legislation_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Title of legislation (for s.NN Act YYYY citations)'}}, 'description': 'A single parsed OSCOLA citation with optional resolution.'}, 'description': 'Citations with confidence < 0.7; may have been partially disambiguated via sampling'}, 'citations': {'type': 'array', 'items': {'type': 'object', 'required': ['raw', 'type', 'confidence'], 'properties': {'raw': {'type': 'string', 'description': 'Original citation text as found in the source'}, 'page': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Starting page in the law report'}, 'type': {'enum': ['neutral', 'law_report', 'legislation', 'si', 'eu_retained'], 'type': 'string', 'description': 'Classification of the citation type'}, 'year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Year component of the citation'}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Court code: UKSC, UKPC, EWCA Civ, EWCA Crim, EWHC (KB), EWHC (Ch), EWHC (Comm), EWHC (Fam), EWHC (Pat), EWHC (IPEC), UKUT (IAC), UKUT (TCC), UKUT (AAC), UKUT (LC), EAT, UKFTT (TC), UKFTT (GRC)'}, 'number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Judgment number within the year'}, 'volume': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Report volume number (for law reports)'}, 'section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Section number referenced'}, 'si_year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI year (for SI YYYY/NNN citations)'}, 'si_number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI number'}, 'confidence': {'type': 'number', 'maximum': 1.0, 'minimum': 0.0, 'description': 'Parse confidence 0.0–1.0. Citations below 0.7 are ambiguous and may have been sent for LLM disambiguation.'}, 'resolved_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'TNA Find Case Law or legislation.gov.uk URL if successfully resolved'}, 'report_series': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Law report series abbreviation: WLR, AC, QB, KB, Ch, All ER, EWCA Civ, etc.'}, 'legislation_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Title of legislation (for s.NN Act YYYY citations)'}}, 'description': 'A single parsed OSCOLA citation with optional resolution.'}, 'description': 'All successfully parsed citations (confidence >= 0.7)'}, 'text_length': {'type': 'integer', 'description': 'Character length of the input text'}, 'parse_duration_ms': {'type': 'integer', 'description': 'Time taken to parse, in milliseconds'}}, 'description': 'Result of parsing all OSCOLA citations from a body of text.'}
Esquema de entrada
{'type': 'object', 'required': ['citation'], 'properties': {'citation': {'type': 'string', 'maxLength': 500, 'minLength': 3, 'description': "A single OSCOLA citation to parse and resolve. E.g. '[2024] UKSC 12', 'SI 2018/1234', 's.47 Companies Act 2006'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['raw', 'type', 'confidence'], 'properties': {'raw': {'type': 'string', 'description': 'Original citation text as found in the source'}, 'page': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Starting page in the law report'}, 'type': {'enum': ['neutral', 'law_report', 'legislation', 'si', 'eu_retained'], 'type': 'string', 'description': 'Classification of the citation type'}, 'year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Year component of the citation'}, 'court': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Court code: UKSC, UKPC, EWCA Civ, EWCA Crim, EWHC (KB), EWHC (Ch), EWHC (Comm), EWHC (Fam), EWHC (Pat), EWHC (IPEC), UKUT (IAC), UKUT (TCC), UKUT (AAC), UKUT (LC), EAT, UKFTT (TC), UKFTT (GRC)'}, 'number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Judgment number within the year'}, 'volume': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Report volume number (for law reports)'}, 'section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Section number referenced'}, 'si_year': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI year (for SI YYYY/NNN citations)'}, 'si_number': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'SI number'}, 'confidence': {'type': 'number', 'maximum': 1.0, 'minimum': 0.0, 'description': 'Parse confidence 0.0–1.0. Citations below 0.7 are ambiguous and may have been sent for LLM disambiguation.'}, 'resolved_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'TNA Find Case Law or legislation.gov.uk URL if successfully resolved'}, 'report_series': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Law report series abbreviation: WLR, AC, QB, KB, Ch, All ER, EWCA Civ, etc.'}, 'legislation_title': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Title of legislation (for s.NN Act YYYY citations)'}}, 'description': 'A single parsed OSCOLA citation with optional resolution.'}
Esquema de entrada
{'type': 'object', 'required': ['committee_id'], 'properties': {'committee_id': {'type': 'integer', 'minimum': 1, 'description': 'Committee ID from committees_search_committees results.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['id', 'name'], 'properties': {'id': {'type': 'integer', 'description': 'Committee ID'}, 'url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Parliament URL for this committee'}, 'name': {'type': 'string', 'description': 'Committee name'}, 'email': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Contact email'}, 'house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Commons, Lords, or Joint'}, 'phone': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Contact phone number'}, 'members': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'Member display name'}, 'role': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Role on the committee (e.g. 'Chair')"}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Political party'}}}, 'description': 'Current committee members'}}}
Esquema de entrada
{'type': 'object', 'properties': {'house': {'anyOf': [{'enum': ['Commons', 'Lords', 'Joint'], 'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Filter by house.'}, 'limit': {'type': 'integer', 'default': 100, 'maximum': 500, 'minimum': 1, 'description': 'Maximum committees to return. Default 100 comfortably covers all currently-active UK select committees. Raise only for historical sweeps.'}, 'query': {'anyOf': [{'type': 'string', 'maxLength': 300}, {'type': 'null'}], 'default': None, 'description': "Search term for committee names, e.g. 'defence' or 'treasury'. Filtered client-side against committee names. Omit to list all committees."}, 'active_only': {'type': 'boolean', 'default': True, 'description': 'If true, only return currently active committees.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['active_only', 'total'], 'properties': {'house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'House filter applied, or None'}, 'query': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Name substring filter applied, or None'}, 'total': {'type': 'integer', 'description': 'Number of committees returned in this call'}, 'committees': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'name'], 'properties': {'id': {'type': 'integer', 'description': 'Committee ID'}, 'url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Parliament URL for this committee'}, 'name': {'type': 'string', 'description': 'Committee name'}, 'house': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Commons, Lords, or Joint'}, 'is_active': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': 'Whether the committee is currently active (None if unknown)'}}}, 'description': 'Matching committees. Use committees_get_committee for membership detail.'}, 'active_only': {'type': 'boolean', 'description': 'Whether results were restricted to currently active committees'}}, 'description': 'Result of a committees_search_committees call.'}
Esquema de entrada
{'type': 'object', 'required': ['committee_id'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': "Maximum evidence items to return. Default 20. For evidence_type='both' a page may hold only oral, only written, or the last oral items followed by the first written items."}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 2147483647, 'minimum': 0, 'description': "Number of evidence items to skip before this page. Default 0. Re-call with offset=offset+returned while has_more is true. For evidence_type='both' this is a position in the combined sequence (all oral evidence, then all written evidence)."}, 'committee_id': {'type': 'integer', 'minimum': 1, 'description': 'Committee ID from committees_search_committees results.'}, 'evidence_type': {'enum': ['oral', 'written', 'both'], 'type': 'string', 'default': 'both', 'description': 'Type of evidence to search.'}, 'max_title_chars': {'type': 'integer', 'default': 300, 'maximum': 2000, 'minimum': 50, 'description': 'Per-item cap on the free-text title field. Default 300 prevents context blow-up from verbose inquiry titles. Raise to 1000+ only when you need the full title text.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['committee_id', 'evidence_type', 'offset', 'limit', 'returned', 'total', 'has_more'], 'properties': {'limit': {'type': 'integer', 'description': 'Max evidence items requested for this page'}, 'total': {'type': 'integer', 'description': "Evidence items matching this query, from committees-api's totalResults (for evidence_type='both', the oral count plus the written count)"}, 'offset': {'type': 'integer', 'description': 'Number of evidence items skipped before this page'}, 'evidence': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'type', 'title'], 'properties': {'id': {'type': 'integer', 'description': 'Evidence item ID'}, 'url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'URL to the evidence document'}, 'date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the evidence was given or submitted'}, 'type': {'enum': ['oral', 'written'], 'type': 'string', 'description': 'Type of evidence'}, 'title': {'type': 'string', 'description': 'Evidence title or session description (may be truncated per max_title_chars)'}, 'witnesses': {'anyOf': [{'type': 'array', 'items': {'anyOf': [{'type': 'string'}, {'type': 'null'}]}}, {'type': 'null'}], 'default': None, 'description': "Witness display names (oral evidence only, capped at 10 per item). An organisation witness (e.g. a regulator or company giving evidence collectively, not through one named individual) has no personal name upstream — that entry is rendered as '<Organisation> (<Role>)' instead, e.g. 'Bank of England (Governor)'. A null entry means committees-api.parliament.uk supplied neither a personal name nor an organisation for that witness slot — honest absence, not a fabricated placeholder; it is not omitted from the list, so the count of entries still matches the number of witnesses upstream."}}}, 'description': 'Evidence items in this page. Titles are capped per max_title_chars; witness lists are capped at 10 per item.'}, 'has_more': {'type': 'boolean', 'description': 'True if evidence exists beyond this page (offset + returned < total). Re-call with offset=offset+returned to fetch the next page.'}, 'returned': {'type': 'integer', 'description': 'Number of evidence items actually returned in this call'}, 'committee_id': {'type': 'integer', 'description': 'Committee ID this page belongs to'}, 'evidence_type': {'enum': ['oral', 'written', 'both'], 'type': 'string', 'description': 'Evidence type filter applied to this query'}}, 'description': 'A page of evidence submissions to a parliamentary committee.\n\nReturned by committees_search_evidence. Callers paginate by\nre-calling with offset=offset+returned while has_more is True.\nWhen evidence_type="both", the sequence being paged is all oral\nevidence followed by all written evidence.'}
Esquema de entrada
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'The name of the prompt to get'}, 'arguments': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None, 'description': 'Optional arguments for the prompt'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'description': 'Generic wrapper for non-object return types.', 'x-fastmcp-wrap-result': True}
Esquema de entrada
{'type': 'object', 'required': ['vrn'], 'properties': {'vrn': {'type': 'string', 'maxLength': 12, 'minLength': 9, 'description': "VAT Registration Number: 9 digits, e.g. '123456789'. GB prefix accepted and stripped automatically."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['vrn', 'mandated'], 'properties': {'vrn': {'type': 'string', 'description': 'VAT Registration Number queried'}, 'mandated': {'type': 'boolean', 'description': 'Whether this business is mandated for MTD VAT'}, 'trading_name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Registered trading name if available'}, 'effective_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date from which MTD obligation applies'}}, 'description': 'Making Tax Digital VAT status for a VAT registration number.'}
Esquema de entrada
{'type': 'object', 'required': ['commodity_code'], 'properties': {'commodity_code': {'type': 'string', 'maxLength': 200, 'minLength': 2, 'description': "Commodity code or plain-English description. E.g. 'food', 'domestic fuel', 'software', 'financial services', 'new build residential'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['commodity_code', 'source_url'], 'properties': {'rate': {'anyOf': [{'enum': ['standard', 'reduced', 'zero', 'exempt', 'outside_scope'], 'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "VAT rate category, or None when no specific category was confidently matched. None here is NOT a stand-in for any real rate — it means the lookup did not resolve, not that the item is outside VAT's scope."}, 'notes': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Any additional notes or conditions on this rate'}, 'source_url': {'type': 'string', 'description': 'GOV.UK/HMRC guidance page backing the matched entry; for an unresolved query, the general VAT rates page to consult instead'}, 'verified_on': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': "Date the matched entry was last checked against GOV.UK/HMRC guidance. None for an unresolved query, since no entry was matched. A data-currency signal only — see `effective_from` for the rate's own legal commencement date, when known."}, 'commodity_code': {'type': 'string', 'description': 'Commodity code or description queried'}, 'effective_from': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the represented VAT treatment is known, on researched evidence, to have taken legal effect. None when no such commencement date has been established for this entry — that is common and does NOT imply the rate is new, uncertain, or unmatched. For data currency (when this entry was last checked against GOV.UK/HMRC guidance) see `verified_on` instead — the two are deliberately independent.'}, 'rate_percentage': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Rate charged on a taxable supply: 20.0 (standard), 5.0 (reduced), 0.0 (zero). None for an exempt supply, which is not taxed at any rate (exempt is not the same as 0%), and None when `rate` is None.'}, 'matched_category': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The static lookup table category the query exactly named (e.g. 'hot food'), or None when the query is not a category name. `rate`/`rate_percentage` are None whenever this is None — see `notes`."}}, 'description': 'VAT rate for a commodity or service.\n\nBacked by a small static lookup table, not a live HMRC/GOV.UK query.\n\n`matched_category` is None whenever the query is not exactly a table\ncategory name (or alias). In that case `rate`, `rate_percentage` and\n`verified_on` are ALSO None — this tool never fabricates a rate for an\nunresolved query. Callers must not assume a default (e.g. standard 20%)\nwhen `rate` is None; read `notes` for guidance on where to check instead.\n\nExempt and zero-rated are different treatments: zero-rated has\n`rate_percentage` 0.0, exempt has `rate_percentage` None.'}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 25, 'minimum': 1, 'description': 'Maximum guidance results to return (1–25). Passed to the GOV.UK search count param.'}, 'query': {'type': 'string', 'maxLength': 300, 'minLength': 3, 'description': "Search query for HMRC guidance, e.g. 'VAT digital services', 'R&D tax relief SME'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['query', 'total'], 'properties': {'query': {'type': 'string', 'description': 'The search query that was run'}, 'total': {'type': 'integer', 'description': 'Number of guidance documents returned in this call'}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['title', 'url'], 'properties': {'url': {'type': 'string', 'description': 'GOV.UK URL for the guidance'}, 'title': {'type': 'string', 'description': 'Guidance document title'}, 'summary': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Brief summary of the guidance content'}, 'updated': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the guidance was last updated'}}, 'description': 'A single HMRC guidance document search result.'}, 'description': "Matching HMRC guidance pages. Each entry's `summary` is capped per the max_summary_chars input parameter."}}, 'description': 'Result of an HMRC guidance search on GOV.UK.\n\nWraps the list of matching guidance documents with search metadata so\nthe LLM client sees a real nested object on the wire rather than a\nstringified JSON blob.'}
Esquema de entrada
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'maxLength': 200, 'minLength': 3, 'description': "Judgment slug, e.g. 'uksc/2024/12' or 'ewca/civ/2023/450'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'additionalProperties': True}
Esquema de entrada
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'maxLength': 200, 'minLength': 3, 'description': "Judgment slug, e.g. 'uksc/2024/12'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'additionalProperties': True}
Esquema de entrada
{'type': 'object', 'required': ['slug', 'eId'], 'properties': {'eId': {'type': 'string', 'maxLength': 100, 'minLength': 1, 'description': "Paragraph eId from judgment_get_index, e.g. 'para_12'. Numeric strings like '12' are accepted and normalized to 'para_12'."}, 'slug': {'type': 'string', 'maxLength': 200, 'minLength': 3, 'description': "Judgment slug, e.g. 'uksc/2024/12'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'additionalProperties': True}
Esquema de entrada
{'type': 'object', 'required': ['type', 'year', 'number', 'section'], 'properties': {'type': {'type': 'string', 'maxLength': 10, 'minLength': 2, 'description': "Legislation type code: 'ukpga' (Acts), 'uksi' (SIs), 'asp' (Scottish Acts), 'nia' (NI Acts). Use the value from legislation_search results."}, 'year': {'type': 'integer', 'maximum': 2100, 'minimum': 1800, 'description': 'Year of enactment'}, 'number': {'type': 'integer', 'minimum': 1, 'description': 'Chapter or SI number'}, 'section': {'type': 'string', 'maxLength': 50, 'minLength': 1, 'description': "Provision number, e.g. '47' or '12A' — works for Act sections, SI regulations, and SI articles alike. Use the numeric part only — not 'section-47'/'regulation-47'/'article-47'. Schedules are not currently supported."}, 'max_chars': {'type': 'integer', 'default': 10000, 'maximum': 200000, 'minimum': 500, 'description': 'Maximum characters of section content to return. Default 10,000 (~2,500 tokens) covers almost every section. Raise to 50,000+ only for unusually long Finance Act definition sections. Check content_truncated in the response to see if it was cut.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['title', 'section_number', 'content'], 'properties': {'title': {'type': 'string', 'description': 'Section title or heading'}, 'extent': {'type': 'array', 'items': {'type': 'string'}, 'description': "Territorial extent: list of 'England', 'Wales', 'Scotland', 'Northern Ireland'. Empty list means unknown — do not assume full UK extent."}, 'content': {'type': 'string', 'description': 'Plain text content of the section, possibly truncated per max_chars. Check content_truncated and original_length for full-text information.'}, 'in_force': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': 'False if the section is explicitly marked repealed in CLML. True only when an InForce element is present in the section body (rare). Null for most sections — the data.xml endpoint does not carry a per-section current in-force boolean; null does not mean repealed.'}, 'warnings': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Non-fatal retrieval or parsing warnings the caller should disclose where relevant.'}, 'prospective': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': 'True if this section has not yet come into force; None if unknown'}, 'version_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date of the version retrieved'}, 'source_format': {'enum': ['xml', 'html_fallback'], 'type': 'string', 'default': 'xml', 'description': 'Source parsed for this response. html_fallback means CLML XML was unavailable and text was parsed from the public HTML page.'}, 'section_number': {'type': 'string', 'description': "Section number, e.g. '47', '12A', 'Schedule 2'"}, 'original_length': {'type': 'integer', 'default': 0, 'description': 'Original plain-text length in characters before any truncation'}, 'content_truncated': {'type': 'boolean', 'default': False, 'description': 'True if content was cut to fit max_chars'}}, 'description': 'A single section of an Act or SI, with full metadata.'}
Esquema de entrada
{'type': 'object', 'required': ['type', 'year', 'number'], 'properties': {'type': {'type': 'string', 'maxLength': 10, 'minLength': 2, 'description': "Legislation type code: 'ukpga' (Acts), 'uksi' (SIs), 'asp' (Scottish Acts), 'nia' (NI Acts). Use the value from legislation_search results."}, 'year': {'type': 'integer', 'maximum': 2100, 'minimum': 1800, 'description': 'Year of enactment'}, 'limit': {'type': 'integer', 'default': 200, 'maximum': 1000, 'minimum': 1, 'description': 'Maximum items to return in this call (default 200, max 1000). Raise only when you need a larger slice in one response. Check has_more and total_items to know if further pages exist.'}, 'number': {'type': 'integer', 'minimum': 1, 'description': 'Chapter or SI number'}, 'offset': {'type': 'integer', 'default': 0, 'minimum': 0, 'description': 'Number of items to skip from the flattened TOC. Use with limit to page through very large statutes like the Companies Act 2006 (1300+ items).'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['type', 'year', 'number', 'offset', 'limit', 'returned', 'total_items', 'has_more'], 'properties': {'type': {'type': 'string', 'description': 'Legislation type code echoed from the request'}, 'year': {'type': 'integer', 'description': 'Year of enactment echoed from the request'}, 'items': {'type': 'array', 'items': {'type': 'string'}, 'description': "TOC entries in XML document order, formatted as '<id>: <title>', e.g. 'section-47: Definitions'. When calling legislation_get_section pass only the numeric part ('47', not 'section-47')."}, 'limit': {'type': 'integer', 'description': 'Page size applied after offset'}, 'number': {'type': 'integer', 'description': 'Chapter or SI number echoed from the request'}, 'offset': {'type': 'integer', 'description': 'Offset applied to the full TOC item list'}, 'has_more': {'type': 'boolean', 'description': 'True if more items remain beyond offset+returned'}, 'returned': {'type': 'integer', 'description': 'Number of items in this response'}, 'total_items': {'type': 'integer', 'description': 'Total structural items parsed from the XML, before offset/limit. Compare to `returned` and `has_more` to decide whether to paginate.'}}, 'description': 'Paginated table of contents for an Act or Statutory Instrument.\n\nThe upstream XML is fetched in one shot (legislation.gov.uk has no\nserver-side pagination), then sliced client-side via offset/limit.\nFor very large statutes like the Companies Act 2006 (1300+ items)\nuse offset to page through. Check has_more and total_items to\nknow the full size.'}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'type': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Filter by type: 'ukpga' (Acts), 'uksi' (SIs), 'asp' (Scottish Acts), 'nia' (NI Acts). Exact-match — omit if you don't already know whether you're looking for an Act vs an SI."}, 'year': {'anyOf': [{'type': 'integer', 'maximum': 2100, 'minimum': 1800}, {'type': 'null'}], 'default': None, 'description': "Filter by year of enactment (exact-match — a single integer, not a range). Omit unless you already know the Act's year. Speculating a year (e.g. 'this is recent so it must be 2026') and getting it wrong will zero out the result set. Better workflow: query without `year`, then read the year from the returned results."}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 50, 'minimum': 1, 'description': 'Maximum results to return (1–50). Passed to the upstream results-count param.'}, 'query': {'type': 'string', 'maxLength': 500, 'minLength': 1, 'description': "Search query, e.g. 'Housing Act 1988' or 'data protection personal data'"}, 'fulltext': {'type': 'boolean', 'default': False, 'description': "Default false → searches Act/SI titles only (best for finding a named Act, e.g. 'Housing Act 1988' returns ukpga/1988/50 first). Set true to search the full text of every Act/SI for the query (returns SIs and regulations that cite the term — e.g. 'rental deposits' would return many implementing instruments)."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['results', 'total'], 'properties': {'total': {'type': 'integer', 'description': 'Total number of matches'}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['title', 'type', 'year', 'number', 'url'], 'properties': {'url': {'type': 'string', 'description': 'Canonical legislation.gov.uk URL'}, 'type': {'type': 'string', 'description': "Legislation type code, e.g. 'ukpga' (UK Public General Act), 'uksi' (Statutory Instrument), 'asp' (Scottish Parliament Act). Use with `year` and `number` as the triple {type}/{year}/{number} in the legislation_get_toc / legislation_get_section tools, or in legislation://{type}/{year}/{number}/section/{section}{?date} resource URIs."}, 'year': {'type': 'integer', 'description': 'Year of enactment or making. Part of the {type}/{year}/{number} triple that identifies an Act or SI.'}, 'score': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Relevance score from Lex API (higher = more relevant)'}, 'title': {'type': 'string', 'description': 'Full title of the legislation'}, 'number': {'type': 'integer', 'description': 'Chapter (for Acts) or SI number. Part of the {type}/{year}/{number} triple that identifies an Act or SI.'}, 'next_steps': {'type': 'object', 'description': 'Canonical resource URIs for reading this Act/SI. Read `toc` to discover sections, then `section_template` (substitute the section number) for the section text. Both URIs accept an optional ?date=YYYY-MM-DD query for point-in-time historical research.', 'additionalProperties': {'type': 'string'}}}, 'description': 'Single legislation search result.'}, 'description': 'Matching legislation items'}}, 'description': 'Container for legislation search results.'}
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'description': 'Generic wrapper for non-object return types.', 'x-fastmcp-wrap-result': True}
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'description': 'Generic wrapper for non-object return types.', 'x-fastmcp-wrap-result': True}
Esquema de entrada
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 200, 'minLength': 2, 'description': "Name or partial name, e.g. 'Starmer', 'Baroness Hale'"}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['query', 'total'], 'properties': {'query': {'type': 'string', 'description': 'The name that was searched'}, 'total': {'type': 'integer', 'description': 'Number of members matching the query'}, 'members': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'name', 'party', 'house'], 'properties': {'id': {'type': 'integer', 'description': 'Parliament Members API member ID'}, 'name': {'type': 'string', 'description': 'Full display name'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House of Parliament'}, 'party': {'type': 'string', 'description': 'Current or last party affiliation'}, 'is_current': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': "Whether the member currently sits, in priority order: (1) the source's own membershipStatus.statusIsActive when membershipStatus is present — authoritative, used directly; (2) False when membershipStatus is null/absent but this record's own membershipEndDate is set — an authoritative end date, not an inference from how other records look; (3) None when neither is available — genuinely indeterminate, not fabricated as True or False. A null membershipStatus is NOT by itself read as 'ended'."}, 'constituency': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Constituency (Commons); None for Lords'}}, 'description': 'A current or former Member of Parliament or Lord.'}, 'description': 'Matching members. Use the integer `id` field from any member to call parliament_member_debates or parliament_member_interests.'}}, 'description': 'Result of a parliament member name search.\n\nWraps the list of matching members with search metadata so the\nLLM client sees a real nested object on the wire rather than a\nstringified JSON blob.'}
Esquema de entrada
{'type': 'object', 'required': ['debate_ext_id'], 'properties': {'member_id': {'anyOf': [{'type': 'integer', 'minimum': 1}, {'type': 'null'}], 'default': None, 'description': "Optional integer Members API ID. When given, only that member's contributions in this debate are returned — regardless of which words they used. Resolves via parliament_find_member. When omitted, every contribution in the debate is returned (typical debate: 100-200 items)."}, 'debate_ext_id': {'type': 'string', 'minLength': 8, 'description': 'Debate GUID (DebateSectionExtId). Chain from parliament_search_hansard top_debates[].debate_ext_id, parliament_lookup_by_column matches[].debate_ext_id, or any tool that surfaces a debate identifier.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['member_id', 'total'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Page size requested'}, 'topic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Topic phrase filter applied, if any'}, 'total': {'type': 'integer', 'description': 'Number of contributions returned in this call'}, 'offset': {'type': 'integer', 'default': 0, 'description': 'Skip applied to this page'}, 'has_more': {'type': 'boolean', 'default': False, 'description': 'True if a full page was returned (more may exist)'}, 'member_id': {'type': 'integer', 'description': 'Parliament Members API member ID'}, 'contributions': {'type': 'array', 'items': {'type': 'object', 'required': ['attributed_to', 'date', 'debate_title', 'debate_id', 'debate_ext_id', 'contribution_ext_id', 'chamber_section', 'house', 'text', 'url'], 'properties': {'url': {'type': 'string', 'description': 'Public hansard.parliament.uk URL for this contribution (synthesised from House/Date/DebateSectionExtId/ContributionExtId).'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Date the contribution was made (SittingDate)'}, 'rank': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Upstream relevance score (Rank). Higher = more relevant to the query.'}, 'text': {'type': 'string', 'description': "Contribution text (capped per max_text_chars on the input; default 3000). Source: ContributionTextFull when text_mode='full', ContributionText preview otherwise."}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House of Parliament (House)'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "ALWAYS None. Hansard's AttributedTo is a citation-display string Hansard composes for readability, not structured party data — neither the search-contributions nor the debate-items schema declares a Party field, and the parenthesised text varies by convention (constituency, party, office, 'Maiden Speech', a virtual-attendance marker, or nothing at all) in ways that cannot be told apart by position alone. Guessing a party from it previously produced fabricated values for ministers/officeholders (e.g. party='Lucy Powell' for 'The Leader of the House of Commons (Lucy Powell)'). For a member's authoritative party, resolve `member_id` via parliament_find_member against the Members API's structured latestParty field."}, 'debate_id': {'type': 'integer', 'description': 'Integer DebateSectionId — internal Hansard identifier'}, 'member_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "Members API integer ID. Use as {member_id} in hansard://member/{member_id}/biography for the member's role history. None for a collective or otherwise unresolved attribution (e.g. 'Hon. Members') — Hansard itself has no member to identify there."}, 'column_end': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'The last Hansard column number this contribution spans, e.g. when a long speech runs across columns 200–203. Equal to `column_start` for short contributions. Same population semantics as `column_start`.'}, 'column_ref': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Hansard internal page-marker code from HansardSection (e.g. 'BE-BG1', 'AA-AD'). NOT the citable column number that appears in an OSCOLA footnote — see `column_start` / `column_end` for those, which are only available when reading the contribution via hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}. From parliament_search_hansard, only this page-marker is exposed."}, 'member_name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Authoritative display name of the contributing member — populated ONLY when the source endpoint itself supplies a real name field, never derived by parsing `attributed_to`. Populated from Hansard's MemberName field on the search endpoints (parliament_search_hansard, parliament_member_debates). ALWAYS None from parliament_get_debate_contributions (backed by /debates/Debate/{ext}.json), because DebateItem has no MemberName field at all — only `AttributedTo` (a citation-display string) and `member_id`. AttributedTo's shape varies unpredictably (own name first, hereditary-title styling, ministerial office, chair/speaker role, annotations, collective labels — e.g. 'Lord Pannick (CB)' vs 'The Earl of Devon (CB)' vs 'Madam Deputy Speaker (Judith Cummins)' vs 'Madam Deputy Speaker' alone, all verified live) with no positional rule that reliably recovers the person's name across all of them — two earlier attempts ('use the last parenthesis', then 'unless it starts with `The `') were each falsified by a real, live counterexample. `attributed_to` is preserved in full instead of being decomposed into a guess. Resolve authoritative identity via `member_id` and parliament_find_member when this is None."}, 'column_start': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "The citable Hansard column number where this contribution begins, e.g. 200, 1162. Extracted from `data-column-number` markers in the contribution HTML. Populated only when reading via the contribution resource — `parliament_search_hansard` returns this as None because Hansard's /search.json strips the column markers. To get the real column number for a search hit, read hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}."}, 'constituency': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Constituency (Commons only; None for Lords). Not currently populated from AttributedTo — see `party`'s note on why positional parsing of that string is unsafe; use parliament_find_member for authoritative constituency."}, 'debate_title': {'type': 'string', 'description': 'Title of the debate or question (DebateSection)'}, 'attributed_to': {'type': 'string', 'description': "Full citable attribution string, verbatim from Hansard, e.g. 'The Minister of State, DESNZ (Lord Whitehead) (Lab)' or 'Lord Pannick (CB)'. This is the authoritative citation text — quote it as-is rather than reconstructing it from other fields."}, 'debate_ext_id': {'type': 'string', 'description': 'DebateSectionExtId GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'chamber_section': {'type': 'string', 'description': "Hansard section bucket (Section): 'Commons Chamber', 'Lords Chamber', 'Westminster Hall', 'Written Answers', 'Written Statements'."}, 'contribution_ext_id': {'type': 'string', 'description': 'ContributionExtId GUID — stable citation key. Use as {contribution_ext_id} in hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}.'}}, 'description': 'A single Hansard debate contribution with citation-grade metadata.\n\nField provenance maps to the upstream hansard-api.parliament.uk\n`Contributions[i]` payload, so callers can footnote a contribution\nwithout re-querying.'}, 'description': 'Hansard contributions for the member. Each `text` field is capped at 3000 characters.'}}, 'description': 'Result of a member-filtered Hansard search.\n\nWraps the contributions for one member (optionally filtered further\nby topic) with query metadata.'}
Esquema de entrada
{'type': 'object', 'required': ['debate_ext_id'], 'properties': {'debate_ext_id': {'type': 'string', 'minLength': 8, 'description': 'Debate GUID (DebateSectionExtId). Chain from parliament_search_hansard contribution.debate_ext_id, top_debates[].debate_ext_id, or parliament_policy_position_summary top_debates[].debate_ext_id.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['debate_ext_id'], 'properties': {'divisions': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'external_id', 'number', 'date', 'house', 'ayes_count', 'noes_count'], 'properties': {'id': {'type': 'integer', 'description': 'Hansard-side division ID — distinct ID-space from the Lords/Commons Votes API. This value does NOT chain to votes_get_division (different API). For per-member voting, see `votes_id` below — populated when cross-resolution succeeded.'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Sitting date of the division (Date).'}, 'time': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Time of the division as HH:MM:SS, or None when the upstream omits it.'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House where the division was held.'}, 'number': {'type': 'string', 'description': "Division number within the sitting (e.g. '1', '2')."}, 'votes_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Lords/Commons Votes API division ID, cross-resolved from the upstream by (date + house + number). Use as the `division_id` input to votes_get_division for the full member-by-member voting record. None when the cross-resolve found no match (e.g. some Daily Part divisions are recorded in Hansard before the Votes API publishes them).'}, 'ayes_count': {'type': 'integer', 'minimum': 0, 'description': 'Number of Aye votes.'}, 'noes_count': {'type': 'integer', 'minimum': 0, 'description': 'Number of Noe votes.'}, 'external_id': {'type': 'string', 'description': 'Division GUID (ExternalId). Stable identifier for cross-reference.'}, 'motion_text': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The motion being voted on (TextBeforeVote), e.g. 'Division on Motion A1'. This is the citable description of what the division decided."}, 'result_text': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The result statement (TextAfterVote), e.g. 'Motion A1 disagreed.'"}, 'debate_section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Parent debate title (DebateSection), e.g. 'Renters' Rights Bill'."}, 'debate_section_ext_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Parent debate GUID (DebateSectionExtId). Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header to read the surrounding debate context.'}}, 'description': "A single division (formal parliamentary vote) — lightweight match shape.\n\nReturned as a preview slice on `parliament_search_hansard`'s `top_divisions`\nand as the full element of `parliament_get_debate_divisions`'s output.\n\nField provenance maps to the upstream `DivisionOverview` Swagger definition;\nthe live `/debates/divisions/{ext}` endpoint returns most integer/boolean\nvalues as strings, which the parser converts."}, 'description': "Divisions held in this debate, in chronological order. Empty when no divisions occurred. Each element's `id` chains to votes_get_division."}, 'debate_ext_id': {'type': 'string', 'description': 'Echo of the input debate GUID.'}}, 'description': 'Divisions held within a specific debate.\n\nEmpty `divisions` is the normal case — most debates contain no formal vote\n(Business of the House, statements, urgent questions, debates without a\ndivision). A populated list typically appears around bill stages, motions,\nand contested amendments.'}
Esquema de entrada
{'type': 'object', 'required': ['column_number', 'volume_number'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'default': 'both', 'description': "Restrict to one House. Default 'both' searches across both Houses."}, 'column_number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': "Hansard column number from an OSCOLA footnote, e.g. '200' for 'HL Deb 14 Oct 2025, vol 849, col 200'. String (not integer) to accommodate column suffixes like '1162W' for written answers."}, 'volume_number': {'type': 'integer', 'description': "Hansard volume number (the 'vol 849' part of an OSCOLA citation). Required — the endpoint only resolves citations when given the volume; sitting date is NOT a substitute (verified live 2026-05-29).", 'exclusiveMinimum': 0}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['column_number', 'volume_number', 'house', 'total_results'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'description': 'House filter applied.'}, 'matches': {'type': 'array', 'items': {'type': 'object', 'required': ['debate_id', 'debate_ext_id', 'debate_title', 'date', 'house'], 'properties': {'date': {'type': 'string', 'format': 'date', 'description': 'Sitting date of the debate'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House'}, 'source': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, '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."}, 'debate_id': {'type': 'integer', 'description': 'Internal Hansard debate ID.'}, 'source_code': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, '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.'}, 'debate_title': {'type': 'string', 'description': 'Debate title'}, 'debate_ext_id': {'type': 'string', 'description': 'Debate GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'relevance_rank': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, '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.'}, 'contribution_count': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, 'description': "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."}}, 'description': 'A top debate section returned as a search/lookup preview or aggregate result.'}, 'description': "Debate sections containing the cited column, in upstream relevance order. Each element's `debate_ext_id` chains to hansard://debate/{debate_ext_id}/header, and carries `source`/`source_code` for the citation's publication state. Resolution is NOT gated on publication state — Daily Part, Bound Volume, and Historic columns all resolve. Empty matches typically mean the volume number is wrong (running-volume vs bound-volume number), the column is a Written Answer/Statement needing its suffix (e.g. '1162W'), or a very recent column not yet indexed upstream."}, 'column_number': {'type': 'string', 'description': 'Echo of the requested column number.'}, 'total_results': {'type': 'integer', 'minimum': 0, 'description': 'Number of debate matches found.'}, 'volume_number': {'type': 'integer', 'description': 'Echo of the requested volume number.'}}, 'description': 'Result of looking up a Hansard citation by (volume, column).\n\nEach match is a debate section that contains the cited column. The lawyer\nthen drills into `debate_ext_id` via hansard://debate/{ext_id}/header for\nthe ordered contribution index, picking the contribution at the cited\ncolumn to footnote.'}
Esquema de entrada
{'type': 'object', 'required': ['member_id'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'Maximum contributions to return. Default 20.'}, 'topic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Optional phrase to find in THIS member's contribution text bodies. Hansard searches the words the member actually said, NOT the topic or title of the debate. Pass tokens this member would have spoken — distinctive arguments ('disproportionate sanction'), statutory references ('section 21'), or motion numbers ('Motion C1') — not the bill's name (members rarely say e.g. 'Renters\\' Rights Bill' verbatim in their speeches). If you want 'every contribution this member made in a specific debate' regardless of words used, find the debate_ext_id then use parliament_get_debate_contributions(debate_ext_id, member_id=...)."}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 2000, 'minimum': 0, 'description': 'Number of contributions to skip before this page. Default 0. Re-call with offset=offset+returned while has_more is true.'}, 'member_id': {'type': 'integer', 'minimum': 1, 'description': 'Parliament Members API integer ID. Obtain from parliament_find_member.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['member_id', 'total'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Page size requested'}, 'topic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Topic phrase filter applied, if any'}, 'total': {'type': 'integer', 'description': 'Number of contributions returned in this call'}, 'offset': {'type': 'integer', 'default': 0, 'description': 'Skip applied to this page'}, 'has_more': {'type': 'boolean', 'default': False, 'description': 'True if a full page was returned (more may exist)'}, 'member_id': {'type': 'integer', 'description': 'Parliament Members API member ID'}, 'contributions': {'type': 'array', 'items': {'type': 'object', 'required': ['attributed_to', 'date', 'debate_title', 'debate_id', 'debate_ext_id', 'contribution_ext_id', 'chamber_section', 'house', 'text', 'url'], 'properties': {'url': {'type': 'string', 'description': 'Public hansard.parliament.uk URL for this contribution (synthesised from House/Date/DebateSectionExtId/ContributionExtId).'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Date the contribution was made (SittingDate)'}, 'rank': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Upstream relevance score (Rank). Higher = more relevant to the query.'}, 'text': {'type': 'string', 'description': "Contribution text (capped per max_text_chars on the input; default 3000). Source: ContributionTextFull when text_mode='full', ContributionText preview otherwise."}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House of Parliament (House)'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "ALWAYS None. Hansard's AttributedTo is a citation-display string Hansard composes for readability, not structured party data — neither the search-contributions nor the debate-items schema declares a Party field, and the parenthesised text varies by convention (constituency, party, office, 'Maiden Speech', a virtual-attendance marker, or nothing at all) in ways that cannot be told apart by position alone. Guessing a party from it previously produced fabricated values for ministers/officeholders (e.g. party='Lucy Powell' for 'The Leader of the House of Commons (Lucy Powell)'). For a member's authoritative party, resolve `member_id` via parliament_find_member against the Members API's structured latestParty field."}, 'debate_id': {'type': 'integer', 'description': 'Integer DebateSectionId — internal Hansard identifier'}, 'member_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "Members API integer ID. Use as {member_id} in hansard://member/{member_id}/biography for the member's role history. None for a collective or otherwise unresolved attribution (e.g. 'Hon. Members') — Hansard itself has no member to identify there."}, 'column_end': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'The last Hansard column number this contribution spans, e.g. when a long speech runs across columns 200–203. Equal to `column_start` for short contributions. Same population semantics as `column_start`.'}, 'column_ref': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Hansard internal page-marker code from HansardSection (e.g. 'BE-BG1', 'AA-AD'). NOT the citable column number that appears in an OSCOLA footnote — see `column_start` / `column_end` for those, which are only available when reading the contribution via hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}. From parliament_search_hansard, only this page-marker is exposed."}, 'member_name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Authoritative display name of the contributing member — populated ONLY when the source endpoint itself supplies a real name field, never derived by parsing `attributed_to`. Populated from Hansard's MemberName field on the search endpoints (parliament_search_hansard, parliament_member_debates). ALWAYS None from parliament_get_debate_contributions (backed by /debates/Debate/{ext}.json), because DebateItem has no MemberName field at all — only `AttributedTo` (a citation-display string) and `member_id`. AttributedTo's shape varies unpredictably (own name first, hereditary-title styling, ministerial office, chair/speaker role, annotations, collective labels — e.g. 'Lord Pannick (CB)' vs 'The Earl of Devon (CB)' vs 'Madam Deputy Speaker (Judith Cummins)' vs 'Madam Deputy Speaker' alone, all verified live) with no positional rule that reliably recovers the person's name across all of them — two earlier attempts ('use the last parenthesis', then 'unless it starts with `The `') were each falsified by a real, live counterexample. `attributed_to` is preserved in full instead of being decomposed into a guess. Resolve authoritative identity via `member_id` and parliament_find_member when this is None."}, 'column_start': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "The citable Hansard column number where this contribution begins, e.g. 200, 1162. Extracted from `data-column-number` markers in the contribution HTML. Populated only when reading via the contribution resource — `parliament_search_hansard` returns this as None because Hansard's /search.json strips the column markers. To get the real column number for a search hit, read hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}."}, 'constituency': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Constituency (Commons only; None for Lords). Not currently populated from AttributedTo — see `party`'s note on why positional parsing of that string is unsafe; use parliament_find_member for authoritative constituency."}, 'debate_title': {'type': 'string', 'description': 'Title of the debate or question (DebateSection)'}, 'attributed_to': {'type': 'string', 'description': "Full citable attribution string, verbatim from Hansard, e.g. 'The Minister of State, DESNZ (Lord Whitehead) (Lab)' or 'Lord Pannick (CB)'. This is the authoritative citation text — quote it as-is rather than reconstructing it from other fields."}, 'debate_ext_id': {'type': 'string', 'description': 'DebateSectionExtId GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'chamber_section': {'type': 'string', 'description': "Hansard section bucket (Section): 'Commons Chamber', 'Lords Chamber', 'Westminster Hall', 'Written Answers', 'Written Statements'."}, 'contribution_ext_id': {'type': 'string', 'description': 'ContributionExtId GUID — stable citation key. Use as {contribution_ext_id} in hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}.'}}, 'description': 'A single Hansard debate contribution with citation-grade metadata.\n\nField provenance maps to the upstream hansard-api.parliament.uk\n`Contributions[i]` payload, so callers can footnote a contribution\nwithout re-querying.'}, 'description': 'Hansard contributions for the member. Each `text` field is capped at 3000 characters.'}}, 'description': 'Result of a member-filtered Hansard search.\n\nWraps the contributions for one member (optionally filtered further\nby topic) with query metadata.'}
Esquema de entrada
{'type': 'object', 'required': ['member_id'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'maximum': 20, 'minimum': 1, 'description': 'Max interests per call. Hard-capped at 20 by the upstream interests-api.parliament.uk (verified live 2026-05-29: Take=100 still returns 20). For prolific members, paginate via offset; total size is in totalResults on the response.'}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 500, 'minimum': 0, 'description': 'Number of interests to skip before this page. Default 0 for the first page. To paginate prolific members (100+ interests), re-call with offset=offset+returned while the previous response had has_more=true.'}, 'category': {'anyOf': [{'enum': ['employment', 'employment_adhoc', 'employment_ongoing', 'donations', 'gifts_uk', 'overseas_visits', 'gifts_overseas', 'land', 'shareholdings', 'miscellaneous', 'family_employed', 'family_lobbying'], 'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Filter by interest category. Common categories: 'donations' (donations and support), 'gifts_uk' (gifts/hospitality from UK), 'employment' (employment and earnings), 'land' (land and property), 'shareholdings', 'overseas_visits'. Omit for all categories."}, 'member_id': {'type': 'integer', 'minimum': 1, 'description': 'Parliament Members API integer ID. Get from parliament_find_member.'}, 'max_description_chars': {'type': 'integer', 'default': 500, 'maximum': 5000, 'minimum': 50, 'description': 'Per-entry cap on the free-text description field. Default 500 prevents context blow-up on members with lengthy donation or directorship narratives. Raise to 2000+ only for forensic provenance work.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['member_id', 'offset', 'limit', 'returned', 'has_more'], 'properties': {'limit': {'type': 'integer', 'description': 'Max interests requested for this page'}, 'offset': {'type': 'integer', 'description': 'Number of interests skipped before this page'}, 'category': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Category filter applied to this query, or None for all categories'}, 'has_more': {'type': 'boolean', 'description': 'True if there may be more interests beyond this page. Re-call with offset=offset+returned to fetch the next page.'}, 'returned': {'type': 'integer', 'description': 'Number of interests actually returned in this call'}, 'interests': {'type': 'array', 'items': {'type': 'object', 'required': ['category', 'description'], 'properties': {'category': {'type': 'string', 'description': "Interest category (e.g. 'Directorships', 'Donations')"}, 'description': {'type': 'string', 'description': 'Description of the interest'}, 'date_amended': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the interest was last amended'}, 'date_created': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the interest was registered'}}, 'description': 'A single registered financial interest.'}, 'description': 'The interests in this page. `description` text is capped per the max_description_chars input parameter.'}, 'member_id': {'type': 'integer', 'description': 'Parliament Members API member ID'}}, 'description': 'A page of registered financial interests for a member.\n\nReturned by parliament_member_interests. Callers paginate by\nre-calling with offset=offset+returned while has_more is True.'}
Esquema de entrada
{'type': 'object', 'required': ['topic'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'default': 'both', 'description': "Restrict to one House. Default 'both'."}, 'topic': {'type': 'string', 'maxLength': 200, 'minLength': 2, '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."}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'End date (YYYY-MM-DD)'}, 'from_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Start date (YYYY-MM-DD)'}, 'max_debates_scanned': {'type': 'integer', 'default': 200, 'maximum': 2000, 'minimum': 50, '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.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['topic', 'house', 'total_contributions', 'total_debates', 'total_written_statements', 'total_written_answers', 'total_divisions', 'debates_scanned'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'description': 'House filter applied'}, 'topic': {'type': 'string', 'description': 'Phrase searched in Hansard'}, 'by_year': {'type': 'array', 'items': {'type': 'object', 'required': ['key', 'count'], 'properties': {'key': {'type': 'string', 'description': "Bucket key (e.g. 'Lab', '2024', 'Lord Whitehead')"}, 'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions in this bucket'}}, 'description': 'A single facet bucket: a key (party / year / member / etc.) and its count.'}, 'description': 'Counts of debates by sitting year, desc by year'}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'End date filter applied'}, 'by_house': {'type': 'array', 'items': {'type': 'object', 'required': ['key', 'count'], 'properties': {'key': {'type': 'string', 'description': "Bucket key (e.g. 'Lab', '2024', 'Lord Whitehead')"}, 'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions in this bucket'}}, 'description': 'A single facet bucket: a key (party / year / member / etc.) and its count.'}, 'description': 'Counts of debates by house (Commons vs Lords)'}, 'by_party': {'type': 'array', 'items': {'type': 'object', 'required': ['key', 'count'], 'properties': {'key': {'type': 'string', 'description': "Bucket key (e.g. 'Lab', '2024', 'Lord Whitehead')"}, 'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions in this bucket'}}, 'description': 'A single facet bucket: a key (party / year / member / etc.) and its count.'}, 'description': "Counts 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_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Start date filter applied'}, 'by_section': {'type': 'array', 'items': {'type': 'object', 'required': ['key', 'count'], 'properties': {'key': {'type': 'string', 'description': "Bucket key (e.g. 'Lab', '2024', 'Lord Whitehead')"}, 'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions in this bucket'}}, 'description': 'A single facet bucket: a key (party / year / member / etc.) and its count.'}, 'description': 'Counts of debates by Hansard section bucket (Chamber / Westminster Hall / Written Answers / Written Statements)'}, 'top_debates': {'type': 'array', 'items': {'type': 'object', 'required': ['debate_id', 'debate_ext_id', 'debate_title', 'date', 'house'], 'properties': {'date': {'type': 'string', 'format': 'date', 'description': 'Sitting date of the debate'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House'}, 'source': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, '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."}, 'debate_id': {'type': 'integer', 'description': 'Internal Hansard debate ID.'}, 'source_code': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, '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.'}, 'debate_title': {'type': 'string', 'description': 'Debate title'}, 'debate_ext_id': {'type': 'string', 'description': 'Debate GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'relevance_rank': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, '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.'}, 'contribution_count': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, 'description': "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."}}, 'description': 'A top debate section returned as a search/lookup preview or aggregate result.'}, 'description': '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).'}, 'total_debates': {'type': 'integer', 'minimum': 0, 'description': 'Total distinct debates touching this topic (TotalDebates)'}, 'debates_scanned': {'type': 'integer', 'minimum': 0, 'description': 'Number of debates pulled from /search/Debates.json for the facet breakdown (≤ max_debates_scanned)'}, 'total_divisions': {'type': 'integer', 'minimum': 0, 'description': 'TotalDivisions upstream count. Non-zero → consider votes_search_divisions.'}, 'top_contributors': {'type': 'array', 'items': {'type': 'object', 'required': ['member_id', 'member_name', 'count'], 'properties': {'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions on this topic in the sampled window'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "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)."}, 'member_id': {'type': 'integer', 'description': "Members API integer ID. Use as {member_id} in hansard://member/{member_id}/biography for the member's role history."}, 'member_name': {'type': 'string', 'description': 'Member display name'}}, 'description': 'A top-volume contributor in the sampled window.'}, 'description': 'ALWAYS EMPTY in this summary — see by_party note. Use parliament_member_debates after picking a debate from top_debates.'}, 'by_month_recent_12': {'type': 'array', 'items': {'type': 'object', 'required': ['key', 'count'], 'properties': {'key': {'type': 'string', 'description': "Bucket key (e.g. 'Lab', '2024', 'Lord Whitehead')"}, 'count': {'type': 'integer', 'minimum': 0, 'description': 'Number of contributions in this bucket'}}, 'description': 'A single facet bucket: a key (party / year / member / etc.) and its count.'}, 'description': 'Counts of debates by YYYY-MM for the most recent 12 months in the sample, desc by month'}, 'total_contributions': {'type': 'integer', 'minimum': 0, 'description': 'Total contributions in Hansard matching topic+filters (TotalContributions)'}, 'total_written_answers': {'type': 'integer', 'minimum': 0, 'description': 'TotalWrittenAnswers upstream count'}, 'total_written_statements': {'type': 'integer', 'minimum': 0, 'description': 'TotalWrittenStatements upstream count'}}, 'description': 'Aggregate, member-agnostic Hansard signals on a topic.\n\nPure counts — no editorial labels, no LLM. Returned by\nparliament_policy_position_summary. Callers interpret the signals\nthemselves and drill into specific contributions via the\nparliament_search_hansard tool or the hansard:// resources.'}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'default': 'both', 'description': "Restrict to one House. Default 'both' returns Commons + Lords contributions."}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'Max contributions per call (1–100). Default 20. Paginate further with offset; total corpus size is in total_corpus on the response.'}, 'query': {'type': 'string', 'maxLength': 500, 'minLength': 1, 'description': "Phrase to find in Hansard contribution text bodies. Hansard searches the words members actually said in their speeches — NOT debate titles, topic metadata, or written headlines. Pass tokens that would appear in someone's speech: distinctive arguments ('disproportionate sanction'), statutory references ('section 21'), or specific phrases. Bill titles (e.g. 'Renters\\'s Rights Bill') often DON'T match because members refer to 'the Bill' or 'this legislation' in their speeches. Tokenised matching: 'housing benefit fraud' will match contributions saying 'fraud in housing benefit claims'. For 'all contributions in a specific debate' regardless of words used, drill via top_debates[].debate_ext_id into parliament_get_debate_contributions."}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 5000, 'minimum': 0, 'description': 'Skip this many contributions before the page. Default 0. Re-call with offset=offset+returned to paginate; has_more flags whether more remain.'}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'End date (YYYY-MM-DD)'}, 'from_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Start date (YYYY-MM-DD)'}, 'member_id': {'anyOf': [{'type': 'integer', 'minimum': 1}, {'type': 'null'}], 'default': None, 'description': "Filter to contributions by a single member. Pass the integer Members API ID (resolve a name via parliament_find_member). The prior `member` field accepted a name string but Hansard's /search.json silently ignored it — the spec requires `memberId`."}, 'text_mode': {'enum': ['preview', 'full'], 'type': 'string', 'default': 'preview', 'description': "'preview' returns the upstream ~250-char snippet (fast, low context cost). 'full' returns ContributionTextFull (still capped at 3000 chars). For full contribution text without the cap, read the resource hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}."}, 'contribution_type': {'enum': ['Spoken', 'Written', 'Corrections'], 'type': 'string', 'default': 'Spoken', 'description': "Which Hansard section to paginate. 'Spoken' = chamber + Westminster Hall debates (the default; what a lawyer usually means). 'Written' = written answers and statements. 'Corrections' = published corrections to the record. The corpus envelope (total_debates, total_divisions, etc.) is independent of this and always populated."}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['query', 'total'], 'properties': {'house': {'enum': ['Commons', 'Lords', 'both'], 'type': 'string', 'default': 'both', 'description': 'House filter applied'}, 'limit': {'type': 'integer', 'default': 20, 'description': 'Page size requested'}, 'query': {'type': 'string', 'description': 'The phrase that was searched in Hansard'}, 'total': {'type': 'integer', 'description': 'Number of contributions returned in this call'}, 'offset': {'type': 'integer', 'default': 0, 'description': 'Skip applied to this page (Hansard API: skip)'}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'End date filter applied, if any'}, 'has_more': {'type': 'boolean', 'default': False, 'description': 'True if a full page was returned (more may exist; re-call with offset=offset+limit)'}, 'from_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Start date filter applied, if any'}, 'member_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Members API integer ID filter applied, if any (echoed from input).'}, 'text_mode': {'enum': ['preview', 'full'], 'type': 'string', 'default': 'preview', 'description': 'Whether contribution `text` carries the upstream preview or full body (still capped).'}, 'date_range': {'anyOf': [{'type': 'array', 'maxItems': 2, 'minItems': 2, 'prefixItems': [{'type': 'string', 'format': 'date'}, {'type': 'string', 'format': 'date'}]}, {'type': 'null'}], 'default': None, 'description': '(min, max) SittingDate of returned contributions, or None if empty'}, 'top_debates': {'type': 'array', 'items': {'type': 'object', 'required': ['debate_id', 'debate_ext_id', 'debate_title', 'date', 'house'], 'properties': {'date': {'type': 'string', 'format': 'date', 'description': 'Sitting date of the debate'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House'}, 'source': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, '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."}, 'debate_id': {'type': 'integer', 'description': 'Internal Hansard debate ID.'}, 'source_code': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, '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.'}, 'debate_title': {'type': 'string', 'description': 'Debate title'}, 'debate_ext_id': {'type': 'string', 'description': 'Debate GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'relevance_rank': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, '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.'}, 'contribution_count': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None, 'description': "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."}}, 'description': 'A top debate section returned as a search/lookup preview or aggregate result.'}, 'description': "Top-ranked debates touching this topic (from upstream Debates[] preview, capped at 4 by Hansard's /search.json). Each entry's `debate_ext_id` chains to hansard://debate/{debate_ext_id}/header."}, 'total_corpus': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Total contributions in Hansard matching this query (TotalContributions). Use to decide whether to paginate further or escalate to parliament_policy_position_summary.'}, 'contributions': {'type': 'array', 'items': {'type': 'object', 'required': ['attributed_to', 'date', 'debate_title', 'debate_id', 'debate_ext_id', 'contribution_ext_id', 'chamber_section', 'house', 'text', 'url'], 'properties': {'url': {'type': 'string', 'description': 'Public hansard.parliament.uk URL for this contribution (synthesised from House/Date/DebateSectionExtId/ContributionExtId).'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Date the contribution was made (SittingDate)'}, 'rank': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Upstream relevance score (Rank). Higher = more relevant to the query.'}, 'text': {'type': 'string', 'description': "Contribution text (capped per max_text_chars on the input; default 3000). Source: ContributionTextFull when text_mode='full', ContributionText preview otherwise."}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House of Parliament (House)'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "ALWAYS None. Hansard's AttributedTo is a citation-display string Hansard composes for readability, not structured party data — neither the search-contributions nor the debate-items schema declares a Party field, and the parenthesised text varies by convention (constituency, party, office, 'Maiden Speech', a virtual-attendance marker, or nothing at all) in ways that cannot be told apart by position alone. Guessing a party from it previously produced fabricated values for ministers/officeholders (e.g. party='Lucy Powell' for 'The Leader of the House of Commons (Lucy Powell)'). For a member's authoritative party, resolve `member_id` via parliament_find_member against the Members API's structured latestParty field."}, 'debate_id': {'type': 'integer', 'description': 'Integer DebateSectionId — internal Hansard identifier'}, 'member_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "Members API integer ID. Use as {member_id} in hansard://member/{member_id}/biography for the member's role history. None for a collective or otherwise unresolved attribution (e.g. 'Hon. Members') — Hansard itself has no member to identify there."}, 'column_end': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'The last Hansard column number this contribution spans, e.g. when a long speech runs across columns 200–203. Equal to `column_start` for short contributions. Same population semantics as `column_start`.'}, 'column_ref': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Hansard internal page-marker code from HansardSection (e.g. 'BE-BG1', 'AA-AD'). NOT the citable column number that appears in an OSCOLA footnote — see `column_start` / `column_end` for those, which are only available when reading the contribution via hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}. From parliament_search_hansard, only this page-marker is exposed."}, 'member_name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Authoritative display name of the contributing member — populated ONLY when the source endpoint itself supplies a real name field, never derived by parsing `attributed_to`. Populated from Hansard's MemberName field on the search endpoints (parliament_search_hansard, parliament_member_debates). ALWAYS None from parliament_get_debate_contributions (backed by /debates/Debate/{ext}.json), because DebateItem has no MemberName field at all — only `AttributedTo` (a citation-display string) and `member_id`. AttributedTo's shape varies unpredictably (own name first, hereditary-title styling, ministerial office, chair/speaker role, annotations, collective labels — e.g. 'Lord Pannick (CB)' vs 'The Earl of Devon (CB)' vs 'Madam Deputy Speaker (Judith Cummins)' vs 'Madam Deputy Speaker' alone, all verified live) with no positional rule that reliably recovers the person's name across all of them — two earlier attempts ('use the last parenthesis', then 'unless it starts with `The `') were each falsified by a real, live counterexample. `attributed_to` is preserved in full instead of being decomposed into a guess. Resolve authoritative identity via `member_id` and parliament_find_member when this is None."}, 'column_start': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': "The citable Hansard column number where this contribution begins, e.g. 200, 1162. Extracted from `data-column-number` markers in the contribution HTML. Populated only when reading via the contribution resource — `parliament_search_hansard` returns this as None because Hansard's /search.json strips the column markers. To get the real column number for a search hit, read hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}."}, 'constituency': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Constituency (Commons only; None for Lords). Not currently populated from AttributedTo — see `party`'s note on why positional parsing of that string is unsafe; use parliament_find_member for authoritative constituency."}, 'debate_title': {'type': 'string', 'description': 'Title of the debate or question (DebateSection)'}, 'attributed_to': {'type': 'string', 'description': "Full citable attribution string, verbatim from Hansard, e.g. 'The Minister of State, DESNZ (Lord Whitehead) (Lab)' or 'Lord Pannick (CB)'. This is the authoritative citation text — quote it as-is rather than reconstructing it from other fields."}, 'debate_ext_id': {'type': 'string', 'description': 'DebateSectionExtId GUID. Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header.'}, 'chamber_section': {'type': 'string', 'description': "Hansard section bucket (Section): 'Commons Chamber', 'Lords Chamber', 'Westminster Hall', 'Written Answers', 'Written Statements'."}, 'contribution_ext_id': {'type': 'string', 'description': 'ContributionExtId GUID — stable citation key. Use as {contribution_ext_id} in hansard://debate/{debate_ext_id}/contribution/{contribution_ext_id}.'}}, 'description': 'A single Hansard debate contribution with citation-grade metadata.\n\nField provenance maps to the upstream hansard-api.parliament.uk\n`Contributions[i]` payload, so callers can footnote a contribution\nwithout re-querying.'}, 'description': 'Matching Hansard contributions with full citation metadata.'}, 'top_divisions': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'external_id', 'number', 'date', 'house', 'ayes_count', 'noes_count'], 'properties': {'id': {'type': 'integer', 'description': 'Hansard-side division ID — distinct ID-space from the Lords/Commons Votes API. This value does NOT chain to votes_get_division (different API). For per-member voting, see `votes_id` below — populated when cross-resolution succeeded.'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Sitting date of the division (Date).'}, 'time': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Time of the division as HH:MM:SS, or None when the upstream omits it.'}, 'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'description': 'House where the division was held.'}, 'number': {'type': 'string', 'description': "Division number within the sitting (e.g. '1', '2')."}, 'votes_id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Lords/Commons Votes API division ID, cross-resolved from the upstream by (date + house + number). Use as the `division_id` input to votes_get_division for the full member-by-member voting record. None when the cross-resolve found no match (e.g. some Daily Part divisions are recorded in Hansard before the Votes API publishes them).'}, 'ayes_count': {'type': 'integer', 'minimum': 0, 'description': 'Number of Aye votes.'}, 'noes_count': {'type': 'integer', 'minimum': 0, 'description': 'Number of Noe votes.'}, 'external_id': {'type': 'string', 'description': 'Division GUID (ExternalId). Stable identifier for cross-reference.'}, 'motion_text': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The motion being voted on (TextBeforeVote), e.g. 'Division on Motion A1'. This is the citable description of what the division decided."}, 'result_text': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The result statement (TextAfterVote), e.g. 'Motion A1 disagreed.'"}, 'debate_section': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Parent debate title (DebateSection), e.g. 'Renters' Rights Bill'."}, 'debate_section_ext_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Parent debate GUID (DebateSectionExtId). Use as {debate_ext_id} in hansard://debate/{debate_ext_id}/header to read the surrounding debate context.'}}, 'description': "A single division (formal parliamentary vote) — lightweight match shape.\n\nReturned as a preview slice on `parliament_search_hansard`'s `top_divisions`\nand as the full element of `parliament_get_debate_divisions`'s output.\n\nField provenance maps to the upstream `DivisionOverview` Swagger definition;\nthe live `/debates/divisions/{ext}` endpoint returns most integer/boolean\nvalues as strings, which the parser converts."}, 'description': "Top-ranked divisions touching this topic (from upstream Divisions[] preview, capped at 4). Each entry's `id` chains to votes_get_division; `debate_section_ext_id` chains back to the parent debate."}, 'total_debates': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalDebates — distinct debates touching this topic.'}, 'total_members': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalMembers — member-name matches in the corpus.'}, 'house_breakdown': {'type': 'object', 'description': 'Counts by house across the returned page', 'additionalProperties': {'type': 'integer'}}, 'party_breakdown': {'type': 'object', 'description': "ALWAYS EMPTY. Hansard's contribution schema has no structured party field (see HansardContribution.party) — an aggregation over unjustified values would just be a party-shaped guess. Kept as a field (rather than removed) for schema stability. For real party facets, resolve member_id per contribution via parliament_find_member; this tool does not do that automatically — it would cost one extra HTTP call per distinct member in the page.", 'additionalProperties': {'type': 'integer'}}, 'total_divisions': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalDivisions. Non-zero → consider `top_divisions` previews below or chain to votes_search_divisions.'}, 'total_petitions': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalPetitions.'}, 'total_committees': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalCommittees.'}, 'total_corrections': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalCorrections — published corrections to the Hansard record.'}, 'total_written_answers': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalWrittenAnswers.'}, 'total_written_statements': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'TotalWrittenStatements.'}}, 'description': 'Result of a Hansard debate search.\n\nWraps the list of matching contributions with the query, filters,\nand corpus-level facet counts so the client sees a real nested object\non the wire.'}
Esquema de entrada
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'Maximum petitions to return. Default 20.'}, 'query': {'type': 'string', 'maxLength': 300, 'minLength': 2, 'description': "Search term for petition titles, e.g. 'ban trophy hunting' or 'NHS funding'."}, 'state': {'enum': ['open', 'closed', 'all'], 'type': 'string', 'default': 'all', 'description': 'Filter by petition state.'}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 2000, 'minimum': 0, 'description': 'Number of petitions to skip before this page. Default 0. Re-call with offset=offset+returned while has_more is true.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['query', 'state', 'total'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Page size requested'}, 'query': {'type': 'string', 'description': 'The term that was searched in petitions'}, 'state': {'enum': ['open', 'closed', 'all'], 'type': 'string', 'description': 'Petition state filter applied to this query'}, 'total': {'type': 'integer', 'description': 'Number of petitions returned in this call'}, 'offset': {'type': 'integer', 'default': 0, 'description': 'Skip applied to this page'}, 'has_more': {'type': 'boolean', 'default': False, 'description': 'True if a full page was returned (more may exist)'}, 'petitions': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'action', 'state', 'signature_count', 'url'], 'properties': {'id': {'type': 'integer', 'description': 'Petition ID'}, 'url': {'type': 'string', 'description': 'Petition URL on petition.parliament.uk'}, 'state': {'type': 'string', 'description': 'Petition state (open, closed, etc.)'}, 'action': {'type': 'string', 'description': 'Petition title / call to action'}, 'created_at': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the petition was created'}, 'debate_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date the petition was debated, if any'}, 'signature_count': {'type': 'integer', 'description': 'Number of signatures'}, 'government_response_at': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Date of government response, if any'}}, 'description': 'A UK Parliament petition.'}, 'description': 'Matching petitions (title, state, signature count, key dates, URL).'}}, 'description': 'Result of a UK Parliament petitions search.\n\nWraps the matching petitions with the originating query and state\nfilter.'}
Esquema de entrada
{'type': 'object', 'required': ['uri'], 'properties': {'uri': {'type': 'string', 'description': 'The URI of the resource to read'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'description': 'Generic wrapper for non-object return types.', 'x-fastmcp-wrap-result': True}
Esquema de entrada
{'type': 'object', 'required': ['division_id'], 'properties': {'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'default': 'Commons', 'description': 'Which house this division belongs to.'}, 'division_id': {'type': 'integer', 'minimum': 1, 'description': 'Division ID from votes_search_divisions results.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['id', 'title', 'date', 'house', 'ayes_count', 'noes_count', 'passed'], 'properties': {'id': {'type': 'integer', 'description': 'Division ID'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Date of the division'}, 'house': {'type': 'string', 'description': 'Commons or Lords'}, 'title': {'type': 'string', 'description': 'Division title / motion text'}, 'passed': {'type': 'boolean', 'description': 'Whether the motion passed'}, 'truncated': {'type': 'boolean', 'default': False, 'description': 'Whether voter lists were truncated to fit response limits'}, 'aye_voters': {'type': 'array', 'items': {'type': 'object', 'required': ['member_id', 'name'], 'properties': {'name': {'type': 'string', 'description': 'Member display name'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Political party'}, 'member_id': {'type': 'integer', 'description': "Parliament Members API integer ID — same ID space as the parliament_* module. Use as `member_id` in parliament_member_debates / parliament_member_interests to see this voter's contributions and registered interests, or as {member_id} in hansard://member/{member_id}/biography for their role history."}}}, 'description': 'Members who voted Aye (may be truncated)'}, 'ayes_count': {'type': 'integer', 'description': 'Total Aye votes'}, 'noe_voters': {'type': 'array', 'items': {'type': 'object', 'required': ['member_id', 'name'], 'properties': {'name': {'type': 'string', 'description': 'Member display name'}, 'party': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Political party'}, 'member_id': {'type': 'integer', 'description': "Parliament Members API integer ID — same ID space as the parliament_* module. Use as `member_id` in parliament_member_debates / parliament_member_interests to see this voter's contributions and registered interests, or as {member_id} in hansard://member/{member_id}/biography for their role history."}}}, 'description': 'Members who voted No (may be truncated)'}, 'noes_count': {'type': 'integer', 'description': 'Total No votes'}, 'total_aye_voters': {'type': 'integer', 'default': 0, 'description': 'Total number of Aye voters before truncation'}, 'total_noe_voters': {'type': 'integer', 'default': 0, 'description': 'Total number of No voters before truncation'}, 'is_government_win': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': 'Whether the government won (Lords only)'}}}
Esquema de entrada
{'type': 'object', 'properties': {'house': {'enum': ['Commons', 'Lords'], 'type': 'string', 'default': 'Commons', 'description': 'Which house to search.'}, 'limit': {'type': 'integer', 'default': 25, 'maximum': 100, 'minimum': 1, 'description': 'Maximum divisions to return. Default 25. The Lords API honours up to 100; the Commons API returns at most 25 per call, so page by `returned`, not `limit`.'}, 'query': {'anyOf': [{'type': 'string', 'maxLength': 500}, {'type': 'null'}], 'default': None, 'description': "Search term for division titles, e.g. 'Rwanda' or 'Online Safety Bill'. Omit to browse recent divisions."}, 'offset': {'type': 'integer', 'default': 0, 'maximum': 2147483647, 'minimum': 0, 'description': 'Number of divisions to skip before this page. Default 0. Re-call with offset=offset+returned while has_more is true.'}, 'to_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'End date (YYYY-MM-DD).'}, 'from_date': {'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'default': None, 'description': 'Start date (YYYY-MM-DD).'}, 'member_id': {'anyOf': [{'type': 'integer', 'minimum': 1}, {'type': 'null'}], 'default': None, 'description': 'Filter to divisions where this member voted. Get the member ID from parliament_find_member.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', 'required': ['house', 'returned', 'total'], 'properties': {'house': {'type': 'string', 'description': 'Commons or Lords'}, 'limit': {'type': 'integer', 'default': 25, 'description': 'Page size requested (the Commons API returns at most 25 regardless)'}, 'query': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'The search term, if any (None = browse recent)'}, 'total': {'type': 'integer', 'description': "Total divisions matching the filters, from the source API's searchTotalResults count"}, 'offset': {'type': 'integer', 'default': 0, 'description': 'Skip applied to this page'}, 'has_more': {'type': 'boolean', 'default': False, 'description': 'True if divisions beyond this page exist (offset + returned < total)'}, 'returned': {'type': 'integer', 'description': 'Number of divisions returned in this call'}, 'divisions': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'date', 'house', 'ayes', 'noes', 'passed'], 'properties': {'id': {'type': 'integer', 'description': 'Division ID'}, 'ayes': {'type': 'integer', 'description': 'Number of Aye votes'}, 'date': {'type': 'string', 'format': 'date', 'description': 'Date of the division'}, 'noes': {'type': 'integer', 'description': 'Number of No votes'}, 'house': {'type': 'string', 'description': 'Commons or Lords'}, 'title': {'type': 'string', 'description': 'Division title / motion text'}, 'passed': {'type': 'boolean', 'description': 'Whether the motion passed'}, 'is_government_win': {'anyOf': [{'type': 'boolean'}, {'type': 'null'}], 'default': None, 'description': 'Whether the government won (Lords only)'}}}, 'description': 'Matching divisions. Use the integer `id` field with votes_get_division to fetch the full voter list.'}}, 'description': 'Result of a parliamentary divisions search.\n\nWraps the list of matching divisions with search metadata so the\nLLM client sees a real nested object on the wire rather than a\nstringified JSON blob.'}
Cambios recientes en herramientas
Servidores MCP similares
BNM Data Shop
Sells access to cached official reports, enforcement orders, regulatory documents, inspection records, and other public-source te…
OpenHelvetia Gateway
Provides sourced access to Swiss federal legislation and political data, including law metadata, versions, amendments, citations,…
Court Listener
Searches and retrieves US court opinions, case citations, federal docket filings, and related legal documents.
Gov Uk Content
Searches and retrieves GOV.UK content, government organisations, and HMRC manuals, sections, and revision histories.
OpenCaseLaw — Swiss Caselaw, Statutes & Doctrine
Searches and analyzes Swiss court decisions, statutes, doctrine, legislation, legal scholarship, citation graphs, and administrat…
Epstein
Searches, inventories, and retrieves documents from the House Oversight Committee’s Epstein investigation corpus, including fligh…
Crs Reports
Searches, retrieves, and summarizes Congressional Research Service reports, topics, legislation analysis, and recent publications.
Eu Parliament
Provides European Parliament open data on MEPs, plenary documents, sessions, and related parliamentary records.