Search Parliamentary Committees
committees_search_committeesSearch or list UK parliamentary select committees by name, house, or active status. Returns committee names, house, and active indicator.
Instructions
Search or list UK parliamentary select committees.
Returns committee names, house, and active status. Use committees_get_committee with the committee ID for membership detail.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes | CommitteeSearchInput with optional query, house, active_only, limit. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Name substring filter applied, or None | |
| house | No | House filter applied, or None | |
| active_only | Yes | Whether results were restricted to currently active committees | |
| total | Yes | Number of committees returned in this call | |
| committees | No | Matching committees. Use committees_get_committee for membership detail. |
Implementation Reference
- src/modules/committees/tools.py:95-145 (registration)The register_tools function registers the tool via @mcp.tool with name='search_committees', and the handler function committees_search_committees is defined and decorated here.
def register_tools(mcp: FastMCP) -> None: @mcp.tool( name="search_committees", annotations={"title": "Search Parliamentary Committees", "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": True}, ) async def committees_search_committees(params: CommitteeSearchInput, ctx: Context) -> CommitteeSearchResult: """Search or list UK parliamentary select committees. Returns committee names, house, and active status. Use committees_get_committee with the committee ID for membership detail. Args: params: CommitteeSearchInput with optional query, house, active_only, limit. """ client: httpx.AsyncClient = ctx.lifespan_context["http"] qp: dict = {"Take": params.limit} if params.active_only: qp["CommitteeStatus"] = "Current" if params.house: qp["House"] = HOUSE_MAP.get(params.house) resp = await client.get(f"{COMMITTEES_BASE}/Committees", params=qp) resp.raise_for_status() data = resp.json() items = data.get("items", data.get("results", data)) if isinstance(data, dict) else data if not isinstance(items, list): items = [] committees: list[CommitteeSummary] = [] for item in items: name = item.get("name", "Unknown") if params.query and params.query.lower() not in name.lower(): continue cid = item.get("id", 0) committees.append(CommitteeSummary( id=cid, name=name, house=_parse_house(item.get("house")), is_active=True if params.active_only else None, url=f"https://committees.parliament.uk/committee/{cid}/", )) return CommitteeSearchResult( query=params.query, house=params.house, active_only=params.active_only, total=len(committees), committees=committees, ) - src/modules/committees/tools.py:101-145 (handler)The actual handler for committees_search_committees — fetches committees from the Parliament API, filters client-side by name query, and returns CommitteeSearchResult.
async def committees_search_committees(params: CommitteeSearchInput, ctx: Context) -> CommitteeSearchResult: """Search or list UK parliamentary select committees. Returns committee names, house, and active status. Use committees_get_committee with the committee ID for membership detail. Args: params: CommitteeSearchInput with optional query, house, active_only, limit. """ client: httpx.AsyncClient = ctx.lifespan_context["http"] qp: dict = {"Take": params.limit} if params.active_only: qp["CommitteeStatus"] = "Current" if params.house: qp["House"] = HOUSE_MAP.get(params.house) resp = await client.get(f"{COMMITTEES_BASE}/Committees", params=qp) resp.raise_for_status() data = resp.json() items = data.get("items", data.get("results", data)) if isinstance(data, dict) else data if not isinstance(items, list): items = [] committees: list[CommitteeSummary] = [] for item in items: name = item.get("name", "Unknown") if params.query and params.query.lower() not in name.lower(): continue cid = item.get("id", 0) committees.append(CommitteeSummary( id=cid, name=name, house=_parse_house(item.get("house")), is_active=True if params.active_only else None, url=f"https://committees.parliament.uk/committee/{cid}/", )) return CommitteeSearchResult( query=params.query, house=params.house, active_only=params.active_only, total=len(committees), committees=committees, ) - CommitteeSearchInput — input schema with optional query, house filter, active_only boolean, and limit.
class CommitteeSearchInput(BaseModel): model_config = ConfigDict(str_strip_whitespace=True, extra="forbid") query: str | None = Field(None, description=( "Search term for committee names, e.g. 'defence' or 'treasury'. " "Filtered client-side against committee names. Omit to list all committees." ), max_length=300) house: Literal["Commons", "Lords", "Joint"] | None = Field(None, description="Filter by house.") active_only: bool = Field(True, description="If true, only return currently active committees.") limit: int = Field( 100, ge=1, le=500, description=( "Maximum committees to return. Default 100 comfortably covers all " "currently-active UK select committees. Raise only for historical sweeps." ), ) - CommitteeSearchResult — output model for the search results, including committees list.
class CommitteeSearchResult(BaseModel): """Result of a committees_search_committees call.""" model_config = ConfigDict(str_strip_whitespace=True) query: str | None = Field(None, description="Name substring filter applied, or None") house: str | None = Field(None, description="House filter applied, or None") active_only: bool = Field(..., description="Whether results were restricted to currently active committees") total: int = Field(..., description="Number of committees returned in this call") committees: list[CommitteeSummary] = Field( default_factory=list, description="Matching committees. Use committees_get_committee for membership detail.", ) - Module init that creates the FastMCP instance and calls register_tools, along with namespace mounting instructions.
"""committees sub-module — UK Parliament select committees and evidence.""" from fastmcp import FastMCP from fastmcp.server.middleware.caching import ResponseCachingMiddleware, CallToolSettings from .tools import register_tools committees_mcp = FastMCP( name="committees", instructions=( "Search UK parliamentary select committees and their evidence submissions. " "Use committees_search_committees to find committees by name, house, or status. " "Use committees_get_committee to get detail including current membership. " "Use committees_search_evidence to find oral and written evidence for a committee. " "All data from committees-api.parliament.uk. No authentication required." ), ) committees_mcp.add_middleware(ResponseCachingMiddleware(call_tool_settings=CallToolSettings(ttl=3600))) register_tools(committees_mcp) __all__ = ["committees_mcp"]