Skip to main content
Glama
shbernal

mcp-server-rfc

Let AI agents read the RFC corpus with 40x fewer tokens, and flag obsoleted specs.

Tests License



What it is

Two ways to give an AI agent the IETF RFC corpus: a skill and an MCP server. Both run the same stdlib-only Python core, so they find, read and flag documents identically. No RFC text ships with either; documents come from the RFC Editor on demand.

  • Obsolescence on every result. A superseded RFC says so in a banner the model can't miss: !! OBSOLETED BY: RFC 7230, 7231, ...

  • Section reads. List an RFC's headings with line numbers, then read only the section that answers the question.

  • Search. By title out of the box, or across the full text of all ~9,800 RFCs once you sync a local mirror.

  • Clean text. Page headers, footers and form feeds are stripped.

  • A guard on oversized reads. A read over 1500 lines that isn't a named section is refused, with its size and how to narrow it.

RFC and section

Whole RFC

One section

RFC 9110 HTTP Semantics, §15.5.5 404 Not Found

125.7k

177

RFC 9000 QUIC, §19.3 ACK Frames

100.9k

1,742

RFC 8446 TLS 1.3, §4.1.2 Client Hello

78.1k

1,865

RFC 5321 SMTP, §4.2 SMTP Replies

52.8k

4,003

RFC 6749 OAuth 2.0, §5.2 Error Response

38.0k

935

RFC 9111 HTTP Caching, §4.2 Freshness

21.1k

2,531

The median saving is 41x, the figure behind "40x fewer tokens". Tokens are approximated as bytes divided by 4, measured from rfc.py 0.5.0 output. assets/charts/context_sizes.json has the raw measurements.

Related MCP server: conceptio-search

Why

Agents cite dead specifications with confidence. RFC 2616 has been obsolete since 2014, and it's still the first thing most models reach for on HTTP. Every result here carries the RFC index's obsolescence field, so the agent follows the replacement before it quotes anything.

This project replaces mcp-server-ietf, which is unmaintained.

rfc-ai-tooling

mcp-server-ietf

Model fetches rfc-editor.org

Flags obsoleted RFCs

On every result

No

Only if it reads the header

RFCs below 1000, like IP and TCP

Yes

No, its index parser expected zero-padded numbers

Yes

Full titles

Yes

Cut at the first period, so RFC 2616 is "HTTP/1"

Yes

Newly published RFCs

Index refreshes

Index downloaded once

Yes

Read one section

By number or heading

Line ranges only

Whole document

Full-text search

Ranked by section, with a downloaded index

Titles only

No

Install

One config line, or none for the skill

Clone and pip install

Nothing

Pick a surface

Use the one that matches where your agent's tools run.

Your client

Use

Why

Claude Code, Codex CLI, OpenClaw, Cursor, Zed, or anything that runs commands on your machine

The skill

The agent gets the whole shell, including rg over the corpus, instead of three fixed tools

Claude Desktop

The MCP server over stdio

Desktop has no shell, but it spawns MCP servers on your machine

claude.ai on the web, Cowork, other cloud sessions

The MCP server over HTTP, hosted by you

A cloud session can't reach a process on your machine

There's no public instance of the server, and none is planned.

Install

Skill

ClawHub skills.sh

Install from this repo with skills:

npx skills add shbernal/rfc-ai-tooling

The skill is a single stdlib-only Python script, with nothing to pip install.

MCP server

PyPI

Add this to your client's MCP configuration. uvx fetches mcp-server-rfc from PyPI on first run.

{
  "mcpServers": {
    "rfc": {
      "command": "uvx",
      "args": ["mcp-server-rfc"]
    }
  }
}

I've tested it end to end in Claude Desktop on Linux. macOS and Windows should work, but I haven't checked them. docs/desktop-verification.md shows how to tell whether Desktop really called the tools.

The same binary serves HTTP:

mcp-server-rfc --transport http --host 0.0.0.0 --port 8080

mcp/Dockerfile and mcp/fly.toml deploy it as a container:

docker build -t mcp-server-rfc mcp/ && docker run --rm -p 8080:8080 mcp-server-rfc

Then add https://<your-app>/mcp as a custom connector in claude.ai, which needs a Pro, Max, Team or Enterprise plan.

  • There's no authentication. A public instance is an open proxy in front of a volunteer-run mirror, so put it behind auth or keep the URL private.

  • Full-text search needs the section index on the server. Run sync --index there, or it returns an error. Everything else needs only the 2 MB RFC index.

Quickstart

  1. Install the skill or the MCP server.

  2. Ask your agent a spec question, like "What does HTTP say about how long a cached response stays fresh?"

  3. Check that it cites a current RFC by section, like RFC 9111 §4.2, and not RFC 2616.

The agent runs the same loop you can run yourself: search, check obsolescence, list sections, read one.

Title search works with no setup. To search the text of every RFC, download the section index once.

For the skill, where <skills-dir> is where it was installed, like ~/.claude/skills:

python3 <skills-dir>/rfc-lookup/scripts/rfc.py sync --index

For the MCP server:

uvx mcp-server-rfc sync --index

Both write to the same directory, so one download serves both.

The index is a SQLite file holding every RFC, compressed, and an FTS5 index over each section. A search returns sections ranked by BM25, with the number to read next:

$ rfc search "how long can a cache serve a stale response" --fulltext
RFC 9111 — HTTP Caching  [INTERNET STANDARD]
   §4.2.4 Serving Stale Responses  (line 784, 17 lines)
   790: A cache MUST NOT generate a stale response if it is prohibited by an

Reads come from the index too, so nothing is fetched from the RFC Editor after that. On the retrieval eval it finds the answering section in its top 10 for more than half of the held-out questions; ripgrep over the corpus finds it for none.

Without the index, --fulltext falls back to rg or grep over a synced mirror of the corpus as plain files, which is also what --regex needs:

uvx mcp-server-rfc sync

Download

On disk

Source

sync --index

About 270 MB

360 MB

This project's GitHub releases, checked against a published SHA-256

sync

512 MB, about 5 minutes

512 MB

The RFC Editor's public rsync mirror, capped at 2 MB/s by default (--bwlimit)

Neither starts on its own, and the skill tells agents not to run them unasked. rfc index build makes the index from a synced mirror, in about two and a half minutes.

How it works

flowchart LR
    editor[("RFC Editor")]
    releases[("GitHub releases")]
    index[("Section index<br/>360 MB, optional")]
    mirror[("Local mirror<br/>512 MB, optional")]
    core["core/rfc.py<br/>stdlib only"]
    skill["Skill<br/>scripts/rfc.py"]
    mcp["mcp-server-rfc<br/>stdio or HTTP"]
    shell["Agent with a shell"]
    client["MCP client"]

    editor -- "HTTPS, on demand" --> core
    editor -. "rsync, when you run sync" .-> mirror
    releases -. "when you run sync --index" .-> index
    index --> core
    mirror --> core
    core -- "vendored copy" --> skill
    core -- "vendored copy" --> mcp
    skill --> shell
    mcp --> client

core/rfc.py is the only implementation. The skill and the MCP server each carry an identical copy, and CI fails if one drifts. The core parses the RFC Editor's index for titles, status and what obsoletes what, then fetches documents over HTTPS and caches them. With the section index, it reads from that file and ranks sections with SQLite's FTS5. With only a synced mirror, it reads from disk and searches with rg or grep.

More

Available Tools

3 tools
get_rfcA
Read-only

Read an RFC. Call list_sections first and pass a section — whole RFCs average 53 KB and run past 1.6 MB, and reading one in full is almost never what the question needs. section accepts a number ('9.3.1') or heading text ('Idempotent Methods') and includes that section's subsections. Any read of more than 1500 lines that is not a named section is an error naming its size, not a silent context-filling dump; pass full=true only when the entire text is genuinely what you need. start_line and max_lines are 1 or more. max_lines caps any read, including a section, and is the way to take the first part of one that list_sections showed is long. start_line is the fallback for RFCs without numbered headings and cannot be combined with section. Page headers and footers are stripped. The response carries a banner naming the RFC's status and, if it has been superseded, what replaced it.

NameRequiredDescriptionDefault
fullNo
numberYes
sectionNo
max_linesNo
start_lineNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, but the description adds substantial behavior beyond them: oversized non-section reads fail with an error naming the size rather than dumping context, page headers and footers are stripped, and the response carries a status/supersession banner. The failure mode and response shape are both disclosed, which is rare and valuable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the primary action and the single most important directive (pass a section), then the size rationale, then parameter rules. Dense but every sentence carries operational information; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description still covers the response banner, stripped boilerplate, and the error behavior for oversized reads. Combined with the parameter constraints, an agent has everything needed to call this correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage the description has to carry all five parameters, and it does for section (number or heading text, includes subsections), max_lines (caps any read, including sections), start_line (fallback, mutually exclusive with section) and full (escape hatch for whole text). The number parameter's accepted forms (integer or string) and heading-match tolerance are left implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Read an RFC") and immediately positions it in a workflow by naming the sibling list_sections as the prerequisite step. An agent can tell this apart from list_sections and search_rfcs without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing rules: call list_sections first and pass a section, use full=true only when the whole text is genuinely needed, and use start_line only as a fallback for RFCs without numbered headings. It also names a concrete exclusion (start_line cannot be combined with section), which is exactly the kind of constraint that prevents bad calls.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_sectionsA
Read-only

List an RFC's numbered headings with their line numbers and how many lines each one runs to. Cheap, and the right first call when you need part of a specification: use it to pick a section, then pass that section to get_rfc. The line counts are there to be read — a section of a few hundred lines is a normal read, and one running to four figures wants a subsection or a max_lines cap instead. Some pre-1990 RFCs have no numbered headings, in which case this returns an empty list and get_rfc's line range is the way in.

NameRequiredDescriptionDefault
numberYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare read-only/open-world, so the description adds the substantive behavior: the shape of each entry (heading, line number, line count), the empty-list outcome for pre-1990 RFCs, and the cost signal ('cheap'). It also interprets its own output (a few hundred lines is a normal read; four figures wants a subsection or max_lines cap), which is genuine guidance an agent could not get from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and return shape, then usage, then output interpretation, then the edge case. Every sentence carries information an agent needs; nothing repeats the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still conveys the return shape, the empty-result case, and how to proceed from the result into get_rfc. For a single-parameter listing tool this covers everything needed to call it and act on its output.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter and schema description coverage is 0%, so the description must carry the load. 'An RFC's numbered headings' implies the parameter is an RFC number, but it never names it or resolves the anyOf ambiguity between integer and string forms (e.g. '1234' vs 'RFC 1234'). Adequate but leaves a real gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list an RFC's numbered headings) plus exactly what each entry carries: line numbers and line counts. That is immediately distinguishable from siblings get_rfc (reads content) and search_rfcs (search), and no schema inspection is needed.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says it is the right first call when you need part of a spec, names the alternative path (pass the section to get_rfc), and gives a fallback for the case it cannot serve: pre-1990 RFCs return an empty list, so use get_rfc's line range. When-to-use, when-to-skip and the alternative are all stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_rfcsA
Read-only

Search RFCs. scope='title' matches all query terms against RFC titles and always works. scope='fulltext' searches the text of every RFC and needs either the section index or a local mirror the user has set up; it returns an error explaining what to run if there is neither. With the section index ('tool' is 'index'), the query is words, not a phrase: each result is one section, ranked by BM25 with headings weighted, carrying its 'section' number (null for the front matter), 'heading', 'line' and how many 'lines' it runs to, and a 'snippet' quoting its best line. Pass that section straight to get_rfc. Without the index ('tool' is 'rg' or 'grep'), the query is a literal string, each result is one RFC ranked by 'matching_lines', and 'matches' quotes a few lines with the section each falls in. regex=true opts into pattern matching, which only the mirror can do, in the backend's dialect. Results carry each RFC's status and obsolescence, and title results put current RFCs before superseded ones, so a page cut short at 'limit' keeps the replacement rather than the document it replaced. A 'note' says when the index could not be used. 'count' is how many results this page holds and 'total' is how many matched; when 'truncated' is true, report 'total' and raise 'limit' (at most 200) rather than counting the results you were given. An empty query is an error.

NameRequiredDescriptionDefault
limitNo
queryYes
regexNo
scopeNotitle

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint and openWorldHint, but the description adds substantial behavioral context: fulltext prerequisites, backend-dependent result shapes, ranking behavior, obsolescence ordering, truncation semantics, and error behavior for missing index/mirror or empty queries. This is exactly the kind of information an agent needs to invoke the tool correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although dense, every sentence adds operational detail needed for a search tool with multiple backends and no schema descriptions. Scope behavior is front-loaded, and the length is justified by the complexity of the result and pagination semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no parameter descriptions in the schema, the description nevertheless explains result fields, ranking, snippets, status/obsolescence ordering, count/total/truncated handling, and error cases. It is complete enough for an agent to use the tool without guessing at return semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning, and it does: scope values are explained, regex is tied to mirror-only pattern matching, limit is capped at 200 with truncation guidance, and query semantics differ explicitly between index word-based search and mirror literal-string search.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Search RFCs') and immediately clarifies the two scopes. It also tells the agent that matching sections should be passed to get_rfc, making the search-vs-retrieve boundary clear, even though list_sections is not named.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit conditions for scope selection, fulltext prerequisites, regex limitations, and pagination/truncation handling. The main gap is that it does not explicitly contrast this tool with sibling tools like list_sections or get_rfc beyond noting that a section can be passed to get_rfc.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedget_rfc
    • First observedlist_sections
    • First observedsearch_rfcs

TDQS

A4.8/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct role: list_sections maps document structure, get_rfc reads selected content, and search_rfcs finds RFCs or sections. The descriptions explicitly describe complementary workflows and warn about overlapping usage patterns such as line ranges versus section selection.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern: list_sections, get_rfc, search_rfcs. The naming is predictable and immediately readable.

Tool Count5/5

Three tools is well-scoped for an RFC reading and search server. Each tool has a distinct, necessary function: inspecting structure, retrieving content, and searching.

Completeness4/5

The core lifecycle of finding, navigating, and reading RFCs is covered, including status and obsoletion metadata. Minor gaps exist around richer metadata or bulk RFC listing, but agents can work around these using search and section navigation.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to search and fetch high-quality information from multiple sources, including general web APIs, Wikipedia, arXiv, Hacker News, Stack Exchange, and Crossref, with optional pro-mode deep research and clean markdown page extraction.
    10
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to search 1m+ open-access papers, standards, textbooks, and legal documents, resolve identifiers such as RFCs, DOIs, and legal citations, download PDFs, and retrieve citations and metadata through MCP tools.
    9
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to read RSS/Atom feeds, extract web page content as text or Markdown, search the web, and batch-fetch multiple URLs without building custom crawlers.
    5
    MIT
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables AI models to search and retrieve up-to-date technical documentation for supported agent frameworks such as LangChain, LlamaIndex, AutoGen, Agno, OpenAI Agents SDK, MCP, Camel-AI, and CrewAI, returning extracted web page text over stdio or SSE.
    -