DEV Community

wolfejam.dev
wolfejam.dev Subscriber

Posted on

Context Over MCP, Part III: Horses for Courses

Part I: an MCP client has no working directory, so it never sees your
AGENTS.md.

Part II: publish the server to the registry so a client can find
it. Now it can — and this part is about what belongs in the context it finds.

Horses for courses. A flat race wants the fastest horse. A course with fences
wants one that knows how to jump. Two different horses, and you would not swap
them.

The flat racer: Markdown, for instructions

AGENTS.md is a flat racer. Prose, fast to write, expressive, carries
judgment: use SerializerV2 for new features; V1 is back-compat only. Setup,
Build, Test, Conventions, Guardrails — how you work in this repo. The context
card renders exactly this: sections a client can navigate, the operational
manual an agent acts on.

For that course, prose is the right horse. Nothing beats a paragraph for "here
is the nuance, here is the exception."

The course has fences: the facts

Open the card as a human and the manual is not what you want first. First you
want the portrait: what is this, who is it for, why does it exist, where does it
run. The six W's. The card does not show them, because AGENTS.md sections
are a checklist, not a description.

You could add an ## About section. People do:

## About

mcp-context-card is a TypeScript MCP server. It runs on Node 22+, builds with
tsc, has no database (memory is a file), and deploys as a stdio process or a
stateless Streamable HTTP service. CI runs on GitHub Actions across three OSes.
Enter fullscreen mode Exit fullscreen mode

Every clause is a fact that already lives somewhere machine-readable —
package.json, tsconfig.json, the Dockerfile, ci.yml. It has been copied
into prose, and prose is where it goes to rot.

I found one of these while writing this article. mcp-context-card's own
AGENTS.md said "Node 22 or newer." Release 1.0.1 had lowered the engines
floor to >=20package.json moved, the README followed, the AGENTS.md
prose did not. An agent reads "Node 22+" at full confidence and tells a
contributor on Node 20 they are unsupported. Wrong, and the file was sure.

That is a fence. So are these: the facts feed more than one reader (the agent,
the card, a catalog); you want to know which of the six W's you have not
answered; two people edit the repo and the prose diverges. A flat racer piles
into the first fence.

This is separation of concerns — the oldest idea in the trade. One place for
each kind of thing.

The structured layer defines. AGENTS.md instructs.

The jumper: schema, for definitions

Facts want structure. Here is project.faf — YAML, one file at the repo root:

project:
  name: mcp-context-card
  main_language: TypeScript
  type: mcp
stack:
  runtime: Node.js
  build: TypeScript (tsc)
  api_type: MCP (JSON-RPC 2.0 — stdio + stateless Streamable HTTP)
  database: none            # memory is a file
  hosting: any Node host — stdio local, stateless HTTP remote
  cicd: GitHub Actions — typecheck + build + test on 3 OSes
human_context:
  who: MCP host and server implementers who want a project's context over MCP
  what: the essential context / memory / identity components for MCP
  why: AGENTS.md is the standard, but a client must know the file exists and read it whole
  where: github.com/Wolfe-Jam/mcp-context-card
Enter fullscreen mode Exit fullscreen mode

Diffable. One source. Scoreable — a completeness check tells you which W's are
still blank. And it is still YAML: a human reads it fine. You are not trading
readability for structure — you get both.

The example here uses .faf. It is IANA-registered
(application/vnd.faf+yaml), it ships with the scorer, and it is what
mcp-context-card reads — so it is the instance throughout.

— or use yours. The pattern is format-agnostic: a package.json plus a
short PROJECT.yaml, a custom schema, whatever your toolchain already emits.
The horse for this course is any structured source. The point is facts as
data, kept apart from the instructions.

Both horses, one card

The card only ever reads AGENTS.md — never project.faf, on purpose. That is
what keeps it vendor-neutral. So the facts reach it the same way any good
manual gets its spec sheet: you derive that part.

npx faf-cli export --agents      # or the equivalent over MCP
Enter fullscreen mode Exit fullscreen mode

human_context becomes a prose section at the top — the portrait. stack
becomes a facts block. Your hand-written conventions and guardrails stay exactly
where they were, outside the managed markers. Re-run it after a code change and
only the facts refresh.

Now the card shows the portrait and the manual, and neither drifts.

(Same "— or use yours": any tool that writes a facts section into AGENTS.md
from a structured source does this. agents-md-facts does the facts layer with
no project.faf at all.)

The loop

change the code
  → re-export         facts section refreshes · project.faf re-scores
  → the card updates  it just re-reads AGENTS.md
Enter fullscreen mode Exit fullscreen mode

The manual stays true because you wrote it once and it rarely changes. The
portrait stays true because it is derived, not typed.

What this series was about

Prose for instructions, schema for facts — run the right one on each, and the
card shows both: the six W's a human reads first, the manual an agent acts on,
in one page, honest on their own.

Build the schema layer with .faf — or use yours. The point was never the
format. It was: a client should be able to see your context, and your
context should be worth seeing.


Series: Part I — Invisible AGENTS.md? · Part II — Publishing to the Registry · mcp-context-card · the .faf format.

Top comments (1)

Collapse
 
raju_dandigam profile image
Raju Dandigam

@wolfejam, the split between structured project facts and hand-written operational judgment is a clean answer to AGENTS.md drift. Generating only the managed facts block preserves vendor neutrality while making runtime, CI, and deployment claims scoreable. Have you considered including provenance beside each generated field—source file plus key—so a reviewer or agent can trace a stale fact back to package.json or CI config without guessing?