Skip to content

Refactor agent to read tracker data via remote MCP server#118

Open
matthelm wants to merge 2 commits intoBuildCanada:mainfrom
matthelm:feat/mcp-agent-refactor
Open

Refactor agent to read tracker data via remote MCP server#118
matthelm wants to merge 2 commits intoBuildCanada:mainfrom
matthelm:feat/mcp-agent-refactor

Conversation

@matthelm
Copy link

@matthelm matthelm commented Mar 25, 2026

Builds on #117 — merge that first.

Summary

Refactors the evaluation agent to read tracker data through the remote MCP server (from #117) instead of direct Postgres queries, removing ~300 lines of raw SQL. Also enriches the REST API and MCP tools to support the agent's needs.

Agent changes

The agent previously maintained its own SQL queries for reading commitments, bills, sources, and parliament data (db_read.py — 277 lines). It now connects to two MCP servers:

  • "tracker" (remote) — the 13 read-only tools served by the Rails app at POST /mcp
  • "agent" (local) — entry processing and government page fetching (these need direct DB access or are side-effecting)

The CLI scan-all command now reads via the REST API with correct stale-first ordering.

REST API enhancements

Additive changes to existing endpoints to support both the agent and MCP tools:

  • GET /commitmentsstale_days filter, criteria_count/matches_count/last_assessed_at in response, NULLS FIRST ordering for last_assessed_at sort
  • GET /commitments/:id — evidence matches (linked bills/entries with relevance scores)
  • GET /billsparliament_number and government_bills filters
  • GET /bills/:id — Jbuilder view with linked_commitments
  • GET /policy_areas — new lightweight endpoint

New/updated MCP tools

  • list_policy_areas — discover valid policy area slugs for filtering
  • list_commitments — gains stale_days param, response includes criteria_count and matches_count
  • get_commitment — response includes evidence matches
  • list_bills — gains parliament_number and government_bills params
  • get_bill — response includes linked_commitments

The Build Canada tracker already makes government accountability data
publicly available through a REST API. This PR adds a Model Context
Protocol (MCP) server so AI assistants can query that data directly.

Anyone using Claude Desktop, Claude Code, Cursor, or any MCP client
can connect with a single URL: https://www.buildcanada.com/mcp

## MCP server

Uses the official `mcp` Ruby SDK with stateless Streamable HTTP
transport. Thirteen read-only tools, no auth required:

- list_policy_areas — discover valid policy area slugs
- list_commitments / get_commitment — search and inspect commitments
- list_promises / get_promise — platform promises with progress scores
- list_bills / get_bill — parliamentary bills with stage tracking
- list_departments / get_department — departments with ministers
- list_ministers — cabinet officials by portfolio
- list_activity — chronological feed of government activity
- get_commitment_summary — status overview by policy area
- get_commitment_progress — time-series for trend analysis

Each tool dispatches internally to the existing REST endpoints via
Rack — zero duplicated query or serialization logic. The entire MCP
surface is a single controller with a declarative config array.
Adding a new tool is ~8 lines.

No existing files are modified — this is purely additive (new
controller, new policy_areas endpoint, routes, and tests).

## Testing locally

1. Start Rails: `bin/rails server -p 3099`

2. Verify: `curl -X POST http://localhost:3099/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'`

3. To test with Claude Desktop, expose via ngrok:

       ngrok http 3099

4. In Claude Desktop: Settings > Connectors > Add custom connector,
   then enter the ngrok URL with /mcp appended.

   You may need to allow the ngrok host in Rails:

       # config/initializers/allow_tunnel.rb (do not commit)
       Rails.application.config.hosts.clear

5. Run tests: `bin/rails test test/controllers/mcp_controller_test.rb`
The evaluation agent previously read commitments, bills, and other
tracker data via ~300 lines of raw SQL in db_read.py. It now connects
to the remote MCP server (POST /mcp) for those reads, removing the
duplicated query logic.

The agent uses two MCP servers:
- "tracker" (remote) — read-only tools served by the Rails app
- "agent" (local) — entry processing and government page fetching

The CLI scan-all command now reads via the REST API with correct
stale-first ordering (sort=last_assessed_at, direction=asc).

## REST API enhancements (to support agent and MCP tools)

- GET /commitments: stale_days filter, criteria_count/matches_count
  in response, last_assessed_at in listing, NULLS FIRST ordering
- GET /commitments/:id: evidence matches (linked bills/entries)
- GET /bills: parliament_number and government_bills filters
- GET /bills/:id: Jbuilder view with linked_commitments
- GET /policy_areas: new endpoint (id, name, slug, description)

## New MCP tools (added to the controller from PR 1)

- list_policy_areas — discover valid policy area slugs
- Updated list_commitments with stale_days, criteria_count, matches_count
- Updated list_bills with parliament_number and government_bills filters
- Updated get_commitment with evidence matches
- Updated get_bill with linked_commitments

Depends on: feat/mcp-server (the MCP endpoint must be deployed first)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant