Skip to content

Remote MCP server deployment#2151

Open
nesanders wants to merge 12 commits into
codeforboston:mainfrom
nesanders:mcp-server-deploy
Open

Remote MCP server deployment#2151
nesanders wants to merge 12 commits into
codeforboston:mainfrom
nesanders:mcp-server-deploy

Conversation

@nesanders
Copy link
Copy Markdown
Collaborator

What this does

Adds a remotely deployed MCP (Model Context Protocol) server so AI assistants like Claude and ChatGPT can search MAPLE's database of bills, testimony, and ballot questions in real time via natural language queries.

What's in this PR

MCP server (mcp-server/)

  • 7 search tools: search_bills, search_testimony, search_ballot_questions, search_policies, list_topics, list_committees, list_sponsors
  • HTTP transport (index-http.ts) + stdio transport for local use
  • Hybrid auth: Firebase ID Token or long-lived agent key (agentKeys Firestore collection)
  • Per-token rate limiting: 60 req/min, 1,000 req/day
  • Dockerfile for Cloud Run deployment

Firebase Function proxy (functions/src/mcp/proxy.ts)

  • mcpProxy function exposes the MCP server at /api/mcp via Firebase Hosting rewrite
  • Swaps client's X-Maple-Token header for a GCP identity token to call the private Cloud Run service
  • Clients never see the Cloud Run URL directly

Embedding infrastructure

  • createVectorIndexer.ts: writes embeddings as Firestore VectorValue (plain arrays are invisible to vector indexes)
  • backfill-embeddings-parallel.ts: parallel backfill with exponential backoff on quota errors
  • migrate-embeddings-to-vector.ts: one-time migration for existing plain-array embeddings
  • All required Firestore vector composite indexes added to firestore.indexes.json

User guide

  • New page at /learn/ai-tools explaining the feature for non-technical advocates
  • Added to the Learn nav menu
  • Linked from the "How MAPLE Uses AI" page

What's deployed to dev

  • Cloud Run service maple-mcp-server (private, max 2 instances, digital-testimony-dev)
  • Firebase Function mcpProxy deployed and tested end-to-end ✓
  • All vector indexes deployed; embeddings backfilled on both dev and prod
  • Billing budget alert: $60/month (~$2/day) on dev

What's NOT done yet (before prod deploy)

  • Deploy Cloud Run service + mcpProxy function to prod
  • The /api/mcp hosting rewrite activates on next CI hosting deploy — the nav link to /learn/ai-tools should not be publicly promoted until that deploy completes
  • Vertex AI quota reduction to 200 QPM on dev (needs Cloud Console — CLI cannot reduce below service default)
  • CI/CD pipeline for building and deploying the Cloud Run image on merge

nesanders and others added 12 commits May 29, 2026 17:18
- New page at /learn/ai-tools explaining how to connect AI assistants
  (Claude Desktop, ChatGPT) to MAPLE via MCP
- Covers: what MCP is, what users can ask, 4 example prompts,
  step-by-step setup with validated external links, privacy notes
- NavbarLinkAiTools added to Learn dropdown (mobile + desktop)
- navigation.aiTools and titles.ai_tools i18n keys added
- How MAPLE Uses AI page links to the new guide

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Processes all collections concurrently (CONCURRENCY=8) and retries
quota-exhausted requests with exponential backoff (up to 6 retries,
1s base, 2x multiplier + jitter) rather than failing permanently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…un deploy

- mcp-server/Dockerfile: two-stage build (builder compiles TS, runtime
  installs prod deps only); listens on PORT=8080/HOST=0.0.0.0 for Cloud Run;
  uses Workload Identity (no credentials file)
- mcp-server/.dockerignore: excludes tests, dev scripts, .env files
- next.config.js: proxies /api/mcp → MCP_SERVER_URL/mcp when env var is set,
  keeping the public endpoint at mapletestimony.org/api/mcp

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- rateLimit.ts: 60 req/min + 1,000 req/day per token (in-memory, resets
  on daily UTC boundary); applied after auth middleware on POST /mcp
- index-http.ts: wire in rateLimitMiddleware
- Cloud Run service deployed to digital-testimony-dev (us-central1):
  max-instances=2, 512Mi, 30s timeout, Workload Identity service account
- Artifact Registry repo maple-mcp created in us-central1
- Billing budget: $60/month (~$2/day) with 50%/100% alerts

Vertex AI QPM quota reduction (200 QPM / ~$1/day) requires manual
action in Cloud Console — CLI cannot reduce below service default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e Cloud Run

- pages/api/mcp.ts: server-side proxy that fetches a Google identity
  token for Cloud Run IAM and forwards the user's MAPLE token in
  X-Maple-Authorization; Cloud Run URL never exposed to clients
- mcp-server/auth.ts: check X-Maple-Authorization first (proxy path),
  fall back to Authorization (direct/local path)
- next.config.js: remove dead MCP_SERVER_URL rewrite (replaced by API route)
- mcp-server/create-agent-key.ts: fix stale /sse curl example → /mcp
- IAM: roles/run.invoker granted to Compute Engine and App Engine default
  service accounts so Next.js Cloud Run can invoke the MCP service
- google-auth-library added to main package.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- functions/src/mcp/proxy.ts: mcpProxy onRequest function that fetches a
  Google identity token for Cloud Run IAM and forwards the user MAPLE token
  in X-Maple-Authorization; Cloud Run stays --no-allow-unauthenticated
- functions/src/index.ts: export mcpProxy
- firebase.json: add hosting rewrite /api/mcp → mcpProxy (us-central1)
- Remove pages/api/mcp.ts — static export doesn't support API routes
- google-auth-library added to functions/package.json
- AiTools.tsx: add TODO to update connection config once proxy is live
- roles/run.invoker granted to App Engine default SA (Firebase Functions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Picked up automatically by Firebase CLI at deploy time via the
.env.digital-testimony-dev file convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Tested as working by connecting Claude to firebase function.

- proxy.ts: use GCP metadata server for identity token (google-auth-library
  getRequestHeaders() returns Headers object, not plain object — bracket
  access returns undefined); forward Accept + MCP-Protocol-Version headers
  from client so MCP content negotiation works end-to-end
- proxy.ts: remove google-auth-library dependency (metadata server is more
  reliable in GCP-hosted environments)
- auth.ts: add X-Maple-Token header support (Firebase Functions strips
  Authorization from allUsers-accessible functions); precedence order:
  X-Maple-Authorization > X-Maple-Token > Authorization
- AiTools.tsx: update config snippet to use X-Maple-Token header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove resolved TODO comment
- Fix Claude Desktop platform (Mac/Windows, not mobile)
- Fix ChatGPT link to consumer-facing help article
- Reframe token step in plain language for non-technical users

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
maple-dev Ready Ready Preview, Comment Jun 1, 2026 12:56am

Request Review

@nesanders nesanders changed the title feat: MCP server — AI research tools for MAPLE data Remote MCP server deployment Jun 1, 2026
@nesanders nesanders self-assigned this Jun 1, 2026
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