get_committee_details
Retrieve comprehensive details about a parliamentary committee, including members, leadership roles, and recent activities, based on the committee's unique ID, to understand its structure and work.
Instructions
Retrieves detailed information about a specific parliamentary committee, including its members, recent activities, and description. This provides deeper insight into the committee's composition, leadership roles, and recent work. Use this when you need comprehensive information about a particular committee's structure and activities.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| committeeId | Yes | Committee ID - the unique identifier for the parliamentary committee you want information about |
Implementation Reference
- src/index.ts:467-516 (registration)Registration of the get_committee_details tool using mcp.tool(), including description, Zod input schema for committeeId, and inline handler function that fetches committee HTML and extracts details./** Get committee details */ mcp.tool( "get_committee_details", "Retrieves detailed information about a specific parliamentary committee, including its members, recent activities, and description. This provides deeper insight into the committee's composition, leadership roles, and recent work. Use this when you need comprehensive information about a particular committee's structure and activities.", { committeeId: z.string().describe("Committee ID - the unique identifier for the parliamentary committee you want information about") }, async ({ committeeId }) => { try { const html = await apiService.fetchHtml(`/commissie.html?id=${encodeURIComponent(committeeId)}`); const committeeDetails = extractCommitteeDetailsFromHtml(html, BASE_URL, committeeId); if (!committeeDetails) { // If we couldn't extract details from the HTML, return a simplified response with just the name and ID const titleRegex = /<title>([^<]+)<\/title>/i; const titleMatch = html.match(titleRegex); const name = titleMatch?.[1]?.trim() || "Unknown Committee"; return { content: [{ type: "text", text: JSON.stringify({ id: committeeId, name: name, url: `${BASE_URL}/commissie.html?id=${encodeURIComponent(committeeId)}`, note: "This committee uses dynamic content rendering. Only basic information is available." }, null, 2) }] }; } return { content: [{ type: "text", text: JSON.stringify(committeeDetails, null, 2) }] }; } catch (error: any) { return { content: [{ type: "text", text: JSON.stringify({ error: `Error fetching committee details: ${error.message || 'Unknown error'}` }) }] }; } } );
- src/index.ts:474-515 (handler)Handler function that executes the tool: fetches HTML from /commissie.html?id={committeeId} using apiService, extracts details using helper function, handles fallback and errors, returns JSON response.async ({ committeeId }) => { try { const html = await apiService.fetchHtml(`/commissie.html?id=${encodeURIComponent(committeeId)}`); const committeeDetails = extractCommitteeDetailsFromHtml(html, BASE_URL, committeeId); if (!committeeDetails) { // If we couldn't extract details from the HTML, return a simplified response with just the name and ID const titleRegex = /<title>([^<]+)<\/title>/i; const titleMatch = html.match(titleRegex); const name = titleMatch?.[1]?.trim() || "Unknown Committee"; return { content: [{ type: "text", text: JSON.stringify({ id: committeeId, name: name, url: `${BASE_URL}/commissie.html?id=${encodeURIComponent(committeeId)}`, note: "This committee uses dynamic content rendering. Only basic information is available." }, null, 2) }] }; } return { content: [{ type: "text", text: JSON.stringify(committeeDetails, null, 2) }] }; } catch (error: any) { return { content: [{ type: "text", text: JSON.stringify({ error: `Error fetching committee details: ${error.message || 'Unknown error'}` }) }] }; } } );
- src/index.ts:471-473 (schema)Zod schema for tool input parameters: committeeId as string.{ committeeId: z.string().describe("Committee ID - the unique identifier for the parliamentary committee you want information about") },
- src/utils/html-parser.ts:238-393 (helper)Primary helper function implementing the parsing logic: extracts committee name, description, members (with ids, roles, parties), and recent activities from the committee page HTML using regex patterns on tables.export function extractCommitteeDetailsFromHtml(html: string, baseUrl: string, committeeId: string): CommitteeDetails | null { if (!html) { return null; } // Extract the committee name from the title tag or h2 tag let name = ""; // First try to get the name from the h2 tag const h2Regex = /<h2>([^<]+)<\/h2>/i; const h2Match = html.match(h2Regex); if (h2Match && h2Match[1]) { name = h2Match[1].trim(); } // If not found, try to get it from the title tag if (!name) { const titleRegex = /<title>([^<]+)<\/title>/i; const titleMatch = html.match(titleRegex); if (titleMatch && titleMatch[1]) { name = titleMatch[1].trim(); } } if (!name) { return null; } const details: CommitteeDetails = { id: committeeId, name, url: `${baseUrl}/commissie.html?id=${encodeURIComponent(committeeId)}`, members: [], recentActivities: [] }; // Extract description if available const descriptionRegex = /<p class="description">([^<]+)<\/p>/i; const descriptionMatch = html.match(descriptionRegex); details.description = descriptionMatch?.[1]?.trim() || null; // Extract members from the first table const membersTableRegex = /<table[^>]*>[\s\S]*?<thead>[\s\S]*?<\/thead>[\s\S]*?<tbody>([\s\S]*?)<\/tbody>/i; const membersTableMatch = html.match(membersTableRegex); if (membersTableMatch && membersTableMatch[1]) { const membersTableContent = membersTableMatch[1]; const rowRegex = /<tr[^>]*>([\s\S]*?)<\/tr>/gi; let rowMatch; while ((rowMatch = rowRegex.exec(membersTableContent)) !== null) { if (!rowMatch[1]) continue; const rowContent = rowMatch[1]; // Extract cells const cellRegex = /<td[^>]*>([\s\S]*?)<\/td>/gi; const cells: string[] = []; let cellMatch; while ((cellMatch = cellRegex.exec(rowContent)) !== null) { if (cellMatch[1]) { cells.push(cellMatch[1].trim()); } } if (cells.length < 3) continue; // Extract role, name, and party const role = cells[1] ? cells[1].replace(/<[^>]+>/g, "").trim() : ""; // Extract name and ID from the link const nameCell = cells[2] || ""; const nameMatch = nameCell.match(/<a href="persoon\.html\?nummer=([^"]+)">([^<]+)<\/a>/); if (!nameMatch || !nameMatch[1] || !nameMatch[2]) continue; const id = nameMatch[1]; const name = nameMatch[2].trim(); // Extract party if available (might be in the same cell as the name) let party = ""; const partyMatch = nameCell.match(/>([^<]+)<\/a>\s*\(([^)]+)\)/); if (partyMatch && partyMatch[2]) { party = partyMatch[2].trim(); } details.members?.push({ id: id, name: name, role: role || undefined, party: party || undefined }); } } // Extract recent activities from the second table const tablesRegex = /<table[^>]*>[\s\S]*?<thead>[\s\S]*?<\/thead>[\s\S]*?<tbody>([\s\S]*?)<\/tbody>/gi; let tableMatch; let tableCount = 0; let activitiesTableContent = ""; // Find the second table (activities) while ((tableMatch = tablesRegex.exec(html)) !== null) { tableCount++; if (tableCount === 2 && tableMatch[1]) { activitiesTableContent = tableMatch[1]; break; } } if (activitiesTableContent) { const rowRegex = /<tr[^>]*>([\s\S]*?)<\/tr>/gi; let rowMatch; while ((rowMatch = rowRegex.exec(activitiesTableContent)) !== null) { if (!rowMatch[1]) continue; const rowContent = rowMatch[1]; // Extract cells const cellRegex = /<td[^>]*>([\s\S]*?)<\/td>/gi; const cells: string[] = []; let cellMatch; while ((cellMatch = cellRegex.exec(rowContent)) !== null) { if (cellMatch[1]) { cells.push(cellMatch[1].trim()); } } if (cells.length < 2) continue; // Extract date const date = cells[0] ? cells[0].replace(/<[^>]+>/g, "").trim() : ""; if (!date) continue; // Extract title and link const titleCell = cells[1] || ""; const titleMatch = titleCell.match(/<a href="(activiteit\.html\?nummer=([^"]+))">([^<]+)<\/a>/); if (!titleMatch || !titleMatch[1] || !titleMatch[3]) continue; const url = new URL(titleMatch[1], baseUrl).href; const title = titleMatch[3].trim(); details.recentActivities?.push({ title, date, url }); } } return details; }
- src/utils/html-parser.ts:21-41 (schema)TypeScript interfaces defining the structure of Committee and output CommitteeDetails (name, description, members, recentActivities).interface Committee { id: string; name: string; url: string; } interface CommitteeDetails extends Committee { description?: string | null; members?: Array<{ name: string; id: string; party?: string; role?: string; }>; recentActivities?: Array<{ title: string; date: string; url: string; }>; }