Remote MCP server deployment#2151
Conversation
- 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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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>
…low diagram Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| <Row> | ||
| <Col className="py-3"> | ||
| <SectionContainer> | ||
| <SectionTitle className="p-2"> | ||
| Use AI to research MAPLE data | ||
| </SectionTitle> | ||
| <DescrContainer className="py-3 px-4"> | ||
| You can connect AI chat tools like Claude directly to MAPLE's | ||
| database of bills, testimony, and ballot questions. Ask questions | ||
| in plain English and get real-time answers drawn from the full | ||
| legislative record. | ||
| </DescrContainer> | ||
| <DescrContainer className="pb-3 px-4"> | ||
| <Internal href="/learn/ai-tools"> | ||
| Learn how to set up AI research tools with your MAPLE account → | ||
| </Internal> | ||
| </DescrContainer> | ||
| </SectionContainer> | ||
| </Col> | ||
| </Row> |
There was a problem hiding this comment.
Might be good to move the text from this section into mapleAI.json for translatability.
| You can connect AI chat tools like Claude directly to MAPLE's | ||
| database of bills, testimony, and ballot questions. Ask questions | ||
| in plain English and get real-time answers drawn from the full | ||
| legislative record. |
There was a problem hiding this comment.
nit: unnecessary period before "Ask". Should be one sentence: "You can connect AI chat tools like Claude directly to MAPLE's database of bills, testimony, and ballot questions, ask question in plain English, and get real-time answers drawn from the full legislative record. "
There was a problem hiding this comment.
This page has a bunch of text that could be moved to a json for next-i18next translatability. Could use mapleAI.json.
There was a problem hiding this comment.
This is so great! One small note- we should also update token.tsx here to "url": "https://mapletestimony.org/api/mcp" and here with "X-Maple-Token": "Bearer YOUR_TOKEN_HERE" now that you've done the Firebase Hosting rewrite.
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/)Firebase Function proxy (`functions/src/mcp/proxy.ts`)
Embedding infrastructure
User guide
What's deployed to dev
What's NOT done yet (before prod deploy)
🤖 Generated with Claude Code