Architecture
Process model
Single uvicorn process, single port (8000):
┌──────────────────────────────────────┐
│ uvicorn (port 8000) │
│ ┌────────────────────────────────┐ │
│ │ Starlette application │ │
│ │ ┌──────┐ ┌────────────────┐ │ │
│ │ │ /sse │ │ /health │ │ │
│ │ │ /mcp │ │ (direct) │ │ │
│ │ │/messages│ │ │ │
│ │ └──────┘ └────────────────┘ │ │
│ │ ┌──────────────────────────┐ │ │
│ │ │ WSGIMiddleware │ │ │
│ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ Flask (mount /) │ │ │ │
│ │ │ │ /api/v1/* │ │ │ │
│ │ │ └─────────────────────┘ │ │ │
│ │ └──────────────────────────┘ │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
- Flask handles all
/api/v1/*routes via WSGI. - MCP server and
/healthlive directly on Starlette (avoids WSGI threadpool). - MCP tools call the same data layer as the Flask API.
Data layer
┌─────────────┐ ┌──────────────┐
│ rfc-editor │────▶│ data/ │
│ (rsync) │ │ rfc-json/ │
│ │ │ rfc-text/ │
│ │ │ rfc-html/ │
└─────────────┘ └──────┬───────┘
│
▼
┌──────────────┐
│ ingest.py │
│ (incremental│
│ reindex) │
└──────┬───────┘
│
▼
┌──────────────┐
│ db/ │
│ rfc_index.db│
│ ─────────── │
│ rfcs │
│ sections │
│ relations │
│ rfc_fts │
│ section_fts │
└──────────────┘
SQLite schema
rfcs— metadata: number, title, authors, status, dates, keywords, section counts,sections_tiersections— per-section content:rfc_number,ordinal,section_id,title,level,bodyrelations— link table:source_rfc,target_rfc,relation_type(obsoletes, updates, see_also)rfc_fts— FTS5 virtual table over full RFC textsection_fts— FTS5 virtual table over individual sections
Section parsing
Two strategies live in rfc_mcp/sections.py:
- structured — parses HTML
<section id="...">from xml2rfc output. Preserves nesting, accurate boundaries. - heuristic — applies pattern matching on plain text for older RFCs without xml2rfc markup.
Container
- Base:
python:3.12-slim - Deps: Flask, uvicorn, starlette, mcp, aiosqlite, rsync
- No baked data — all data synced and indexed at runtime
- Entrypoint fires a background sync loop; server starts immediately