Skip to main content
Glama

Oravan

Your line to Congress · Tu línea con el Congreso

Oravan is free, nonpartisan civic infrastructure: find your federal representatives, understand active bills in plain language (English and Spanish), get a 30-second call script, and make the call — in under 5 minutes, with no account.

The name is the Oravan: the platform in the Roman Forum where citizens stood to address the public and the powerful — the original place a voice met power. Latin roots are the shared ancestry of English and Spanish alike.

MCP server

This repository also implements a remote MCP (Model Context Protocol) server — the same decoded corpus and lookups, exposed for AI assistants and agents:

  • Endpoint (Streamable HTTP): https://oravan.org/api/mcp/mcp — keyless, read-only, rate-limited; no account or credentials required

  • Local/stdio: npm ci then npx tsx scripts/mcp-stdio.mjs — the same 5 tools over stdio, zero env vars/secrets required

  • Implementation: app/api/mcp/[transport]/route.ts (built on mcp-handler + @modelcontextprotocol/sdk), tool definitions shared with the stdio entry via lib/core/mcp-tools.ts, pure data layer in lib/core/

  • Five tools: lookup_representatives, get_bill, search_bills, whats_moving, get_representative — every response carries a citation envelope (source, as-of freshness, AI-content label, license) in English or Spanish

  • Official MCP Registry: published as org.oravan/mcp (server.json at the repo root, schema-validated in CI by scripts/check-server-json.mjs)

  • Docs: oravan.org/mcp (tool reference, client config, privacy posture) · docs/mcp-server-readme.md

Related MCP server: CongressMCP-full

Design principles

  1. Zero accounts. ZIP code, interests, and call history live in localStorage on the visitor's device. No server-side user data exists — nothing to breach, leak, or subpoena. This is the core privacy posture for at-risk users, not a missing feature.

  2. Static-first. Bills, legislators, district offices, and ZIP→district mappings are static JSON in data/, baked into ~1,000 statically generated pages. Fast, nearly free to host, resilient under load. The only dynamic endpoints are /api/script (AI script generation, cached per bill+stance+language, IP rate-limited), /api/reps (pure lookup), /api/district (stateless split-ZIP address refinement: proxies the Census geocoder so the visitor's IP never reaches census.gov; the address is never stored or logged), and /api/feedback (beta feedback relayed to a private GitHub issue — only what the visitor volunteered, no identifiers).

  3. Bilingual as a first-class feature. Full EN/ES UI via next-intl; scripts are generated in the user's language.

  4. The call moment is the product. Voicemail is legitimized (offices tally it identically), after-hours calling is encouraged, district offices are listed alongside DC, and outcomes (spoke / voicemail / couldn't reach) are logged locally.

  5. Honest about AI. Every generated summary and script is labeled, editable, and reviewed by the human before any call.

  6. Accessible by default. Semantic landmarks, skip link, visible focus, prefers-reduced-motion, 44px+ touch targets, AA contrast.

Data sources

File

Source

Refresh

data/bills.json + data/bills-es.json

Decoded bill corpus (Congress.gov bills + AI plain-language summaries, English and Spanish)

Nightly sync (scripts/sync-bills.mjs via sync-bills.yml): statuses refresh freely; new bills are decode-before-publish, entering the corpus only once their EN and ES summaries exist

data/legislators.json

unitedstates/congress-legislators (public domain) + district offices

scripts/process-data.py

data/zip-districts.json

OpenSourceActivismTech/us_zipcodes_congress

same

data/vacancies.json

Derived, not fetched: scripts/vacancy_diff.py diffs seat sets against the currently-committed data every run, so a departed member with no successor surfaces as an explicit vacancy (reps page, /api/reps, MCP lookup_representatives) instead of silently disappearing or being backfilled from a stale term record

scripts/process-data.py (same run as legislators.json)

data/redistricting-watch.json

Human-authored (status/note) for the 10 states with contested-or-recent 2025–26 mid-decade map changes; rdh_lastmod is a tripwire baseline against the Redistricting Data Hub's own state-page sitemap — see docs/solutions/two-clock-district-boundaries.md

scripts/check-redistricting-watch.mjs, weekly via refresh-legislators.yml; opens a redistricting-watch-labeled issue on change, never auto-updates status/note

data/coverage.json

Real news articles about top-band bills via TheNewsAPI, AI-relevance-filtered (Haiku)

scripts/sync-coverage.mjs (nightly, gated on NEWS_API_KEY)

data/media-bias.json

Outlet political-lean ratings by AllSides, used under CC BY-NC with attribution

Vendored snapshot

Portraits are served from the public-domain unitedstates/images project.

Solved pipeline incidents (root cause + the CI gates that prevent recurrence) are documented in docs/solutions/.

The "Read" section (outlet-bias coverage)

Each top bill's page shows real third-party articles about it, labeled by the outlet's political lean (Left / Center / Right) — reusing AllSides' publication-level ratings, never a Oravan-invented one. Oravan takes no stance and authors no partisan text: AI is used only behind the scenes — generating each bill's news-search terms (press-style names and a subject query) and a cheap relevance gate (is this article about this bill?) — and authors nothing displayed. The ingestion runs nightly in CI and bakes results to JSON, so the site still makes zero runtime third-party calls. Without NEWS_API_KEY the sync is a no-op and the section renders nothing; a small hand-built real sample (data/coverage.json) keeps it demoable. Lean is shown by text label + position only — never party colors (a hard rule; see DESIGN.md).

Develop

npm install
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env.local   # script generation + decode/relevance
echo "NEWS_API_KEY=..." >> .env.local               # optional; enables the "Read" coverage sync
npm run dev

npm run build statically generates every bill page in both locales.

Known v1 caveats

  • ZIP→district mapping is ZCTA-based; a split ZIP shows all candidate districts by default (senators are unaffected). Entering a street address — optional, sent once by POST, never stored or logged — narrows it to the actual district via a server-proxied Census-geocoder lookup; the all-candidates view remains the graceful fallback whenever the geocoder can't help. The geocoder request pins the "119th Congressional Districts" layer, which needs a bump when the Census rolls the vintage to the 120th.

  • Script cache and rate limits are in-memory per serverless instance — fine at demo scale, should move to a shared store before heavy traffic.

  • New bills can lag behind Congress.gov: the nightly sync decodes at most MAX_NEW_DECODES new bills per run (cost ceiling), so after a missed window the corpus catches up over several nights (decode-before-publish; the backlog drains oldest-first).

  • "Read" coverage exists only for top-band bills (the long tail shows nothing); the ES locale shows the same English articles with localized chrome; outlets absent from data/media-bias.json appear without a lean chip.

License

  • Code: GNU AGPL-3.0. You may use, modify, and run this code — including as a network service — provided modified versions you operate or distribute remain open under the same license. Embedding Oravan's hosted widgets on your site via the loader/script tag does not subject your site to the AGPL; that's use of our service, not distribution of this code.

  • Not licensed: the Oravan name, logo, and brand assets (assets/brand/, app icons). All rights reserved — forks must use their own identity.

  • Content: underlying legislative data is U.S. government work (public domain). AI-generated decodes and summaries are licensed CC BY 4.0, exactly as declared in the MCP citation envelope and on the citations page.

Install Server
A
license - permissive license
A
quality
A
maintenance

Maintenance

Maintainers
<1hResponse time
Release cycle
1Releases (12mo)
Commit activity

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cm2489/oravan'

If you have feedback or need assistance with the MCP directory API, please join our Discord server