mcp-context-card 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,7 @@
18
18
  "displayName": "mcp-context-card — persistent memory (.fafm)",
19
19
  "type": "application/vnd.fafm+yaml",
20
20
  "mediaType": "application/vnd.fafm+yaml",
21
- "description": "Cross-session memory — 3 fact(s), profile \"knowledge\". Recall survives a process restart. No de-facto standard for this concern yet.",
21
+ "description": "Cross-session memory — 4 fact(s), profile \"knowledge\". Recall survives a process restart. No de-facto standard for this concern yet.",
22
22
  "url": "./project.fafm",
23
23
  "_meta": {
24
24
  "io.github.wolfe-jam.mcp-context-card/iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml"
@@ -29,7 +29,7 @@
29
29
  "displayName": "mcp-context-card — agent identity (.fafa)",
30
30
  "type": "application/vnd.fafa+yaml",
31
31
  "mediaType": "application/vnd.fafa+yaml",
32
- "description": "Reference MCP server that makes a project's context (AGENTS.md), memory, and identity discoverable to any MCP client, through the Server Card _meta block and a self-published ai-catalog.json.",
32
+ "description": "The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.",
33
33
  "url": "./.well-known/fafa",
34
34
  "_meta": {
35
35
  "io.github.wolfe-jam.mcp-context-card/iana": "https://www.iana.org/assignments/media-types/application/vnd.fafa+yaml"
package/.well-known/fafa CHANGED
@@ -8,11 +8,12 @@ version: "1.0"
8
8
  agent:
9
9
  name: "mcp-context-card"
10
10
  displayName: "mcp-context-card"
11
- vendor: "reference"
12
- version: "0.5.0"
11
+ vendor: "io.github.wolfe-jam"
12
+ version: "0.5.2"
13
13
  description: >-
14
- Reference MCP server that makes a project's context (AGENTS.md), memory,
15
- and identity discoverable to any MCP client, through the Server Card _meta
16
- block and a self-published ai-catalog.json.
17
- status: "reference"
14
+ The essential MCP components for a project's context (AGENTS.md),
15
+ cross-session memory, and identity — a base MCP on its own, or a
16
+ drop-in extension for any existing MCP server, discoverable through the
17
+ Server Card _meta block and a self-published ai-catalog.json.
18
+ status: "published"
18
19
  license: "MIT"
package/AGENTS.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # AGENTS.md
2
2
 
3
- `mcp-context-card` is an MCP server that makes a project's **context**
4
- (this file), **memory**, and **identity** discoverable to any MCP client —
5
- through the two surfaces already in the ecosystem: the Server Card `_meta`
6
- block and `ai-catalog.json` sibling entries.
3
+ `mcp-context-card` is the essential MCP server for a project's **context**
4
+ (this file), **memory**, and **identity** — usable as your base MCP, or
5
+ dropped into any existing MCP server as an extension. Discoverable to any
6
+ MCP client through the two surfaces already in the ecosystem: the Server
7
+ Card `_meta` block and `ai-catalog.json` sibling entries.
7
8
 
8
9
  `read_agents_md` serves this file, section by section, over the same MCP
9
10
  connection.
@@ -40,14 +41,14 @@ Windows for every push and PR to `main` (`.github/workflows/ci.yml`).
40
41
  |---|---|
41
42
  | `src/server.ts` | the MCP server — the nine tools + the Server Card resource |
42
43
  | `src/agents-md.ts` | reads and section-splits this file |
43
- | `src/author.ts` | `author_agents_md` — wraps `agents-md-facts` (the AGENTS.md authoring engine) |
44
+ | `src/author.ts` | `author_agents_md` — BETTER via `agents-md-facts`, BEST when `project.faf` exists |
44
45
  | `src/md.ts` | a minimal dependency-free Markdown → HTML renderer |
45
46
  | `src/render-card.ts` | the card — identity + this file + memory + discovery, as one HTML page |
46
47
  | `src/memory.ts` → `src/faf/parse-fafm.ts` | file-backed `remember` / `recall` / `forget` |
47
48
  | `src/identity.ts` | `whoami` (`.fafa` → `package.json` fallback) + the `_meta` context block |
48
49
  | `src/catalog-gen.ts` | writes `.well-known/ai-catalog.json` from the same three sources |
49
50
  | `src/transport/http.ts` | the stateless Streamable HTTP app (Hono) |
50
- | `src/bin.ts` | the entry point (`resolveLaunch`) — `stdio` · `--http` · `card` |
51
+ | `src/bin.ts` | the entry point (`resolveLaunch`) — `stdio` · `--http` · `card` · `--help` · `--version` |
51
52
  | `src/faf/parse-fafm.ts` · `parse-fafa.ts` | the `.fafm` / `.fafa` parsers |
52
53
 
53
54
  ## Conventions
@@ -80,6 +81,7 @@ plus `npm run catalog:check` and `npm run card:check` clean if you touched
80
81
 
81
82
  ## Authoring this file
82
83
 
83
- `AGENTS.md` here is maintained by hand. It can also be generated from the
84
- repo's `project.faf` with `faf export --agents` — the server doesn't care how
85
- the file was authored, only that it's valid Markdown.
84
+ `AGENTS.md` here is maintained by hand. The `author_agents_md` tool (or
85
+ `faf export --agents`) would draft a BEST version straight from this repo's
86
+ own `project.faf` plus its detected facts — the server doesn't care how the
87
+ file was authored, only that it's valid Markdown.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,63 @@
2
2
 
3
3
  All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
4
4
 
5
+ ## 0.5.2
6
+
7
+ The soak, closed out. Two Cursor host checks — a real bug found and fixed, a
8
+ real gap found and fixed, both confirmed against a real independent MCP host
9
+ on the current build.
10
+
11
+ - **`author_agents_md` now authors BEST, not just BETTER, when it can.**
12
+ BETTER is the facts-only draft from `agents-md-facts` (build/test
13
+ commands, entry points, conventions — nothing invented). **BEST** is that
14
+ plus a `## Project` section ahead of it — goal, who it's for, why, and a
15
+ "start here" file list — read straight from `project.faf` when one
16
+ exists. This is the point of the app: give the best AGENTS.md the
17
+ project has the material for, not a fixed floor. The tool's response
18
+ names the tier it produced.
19
+ - **Fix:** `remember` on a project that had never had a `project.fafm`
20
+ threw `ENOENT` instead of starting one — the single most common
21
+ first-use case. `remember` now creates a fresh `.fafm` on first write;
22
+ `forget` / `parseFafm` were already safe and are unchanged. A real
23
+ child-process e2e test (a cold root, two separate OS processes) makes
24
+ this a permanent regression guard, not just a fix.
25
+ - `docs/WIRING.md`: a note on hosts whose spawn `PATH` lacks `npx`
26
+ (`spawn npx ENOENT`, observed in Cursor) — point `command` at `node` +
27
+ the installed `dist/bin.js` instead.
28
+ - **The README / AGENTS.md / `project.faf` / manifest reframe** — dropped
29
+ "Small, MIT…" / "a piece, not the toolbox" for the real positioning:
30
+ essential context, memory, and identity components, usable as a base MCP
31
+ on their own, or a drop-in extension for any existing MCP server.
32
+ - An accuracy pass across every shipped surface, caught by re-reading
33
+ rather than by any check: stale test/tool counts (README, CHANGELOG,
34
+ and `project.faf`'s own `human_context.what` — it undercounted its own
35
+ tools), 3-release-old version strings sitting in two hand-shown examples
36
+ (`examples/README.md`, `docs/MECHANISMS.md`), a pre-rename
37
+ docker-compose service name (`trinity` → `context-card`), an internal
38
+ function that still carried the pre-rename product name (`trinityMeta` →
39
+ `serverCardMeta` — not a public export). `project.faf` itself rechecked
40
+ against the current architecture (`tech_stack`, `key_files`, `cicd`).
41
+ - 102 tests, coverage gate held, `card:check` / `catalog:check` green,
42
+ `faf-cli check`: ✪ Trophy 100%, 15/15 slots.
43
+
44
+ ## 0.5.1
45
+
46
+ First-hour ergonomics and wording, from the 0.5.0 soak.
47
+
48
+ - `--help` / `-h` and `--version` / `-V` (and the `help` / `version` subcommands)
49
+ — a bare `mcp-context-card` is a stdio server that waits on stdin, so at a
50
+ terminal it looked idle with no way to ask what it was.
51
+ - stdio mode now prints one line to **stderr** on start
52
+ (`… · stdio · waiting for an MCP host on stdin`) — mirrors what `--http`
53
+ already did. stdout stays clean for the JSON-RPC wire.
54
+ - The npm and `server.json` descriptions no longer open with "Reference MCP
55
+ server" — they now match the README ("An MCP server that makes a project's
56
+ context, memory, and identity discoverable…"). Same in `.well-known/fafa`;
57
+ the three `project.fafm` facts are `type: fact`. `package.json` `author` set
58
+ to the LICENSE holder.
59
+ - `.well-known/fafa` — `vendor: io.github.wolfe-jam`, `status: published`
60
+ (were both `reference`). Shows in `whoami` and as the card's pills.
61
+
5
62
  ## 0.5.0
6
63
 
7
64
  The first public release — installable, and settling in the open before a
@@ -47,7 +104,7 @@ tested server.
47
104
 
48
105
  ### Engineering
49
106
 
50
- - 88 tests across Linux / macOS / Windows, coverage-gated
107
+ - 90 tests across Linux / macOS / Windows, coverage-gated
51
108
  (lines 90 / funcs 85 / branches 80, `src/` only). A real `child_process`
52
109
  spawn proves memory across a genuine process boundary; stdio/HTTP
53
110
  tool-surface parity is asserted.
@@ -70,6 +127,6 @@ tested server.
70
127
 
71
128
  ## v0.1.0 (2026-08-12)
72
129
 
73
- - Initial private reference implementation (as `faf-trinity`): project context,
130
+ - Initial private implementation (as `faf-trinity`): project context,
74
131
  persistent memory, and agent identity in one MCP server, through two
75
132
  mechanisms already live in production. `demo.ts` proved all three.
package/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  [![CI](https://github.com/Wolfe-Jam/mcp-context-card/actions/workflows/ci.yml/badge.svg)](https://github.com/Wolfe-Jam/mcp-context-card/actions/workflows/ci.yml)
4
4
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
5
5
 
6
- An MCP server that makes a project's context, memory, and identity discoverable
7
- to any MCP client — and renders them as one card you can read.
6
+ The essential MCP server for a project's context, memory, and identity —
7
+ discoverable to any MCP client, and rendered as one card you can read.
8
8
 
9
9
  - **context** — the project's `AGENTS.md`, served whole or one section at a time
10
10
  - **memory** — facts that persist across sessions, in a file
@@ -13,26 +13,34 @@ to any MCP client — and renders them as one card you can read.
13
13
  Discovery goes through two surfaces already in the ecosystem: the Server Card
14
14
  `_meta` block and `ai-catalog.json` sibling entries.
15
15
 
16
- ## What it is / what it is not
16
+ ## A base MCP — or an extension for any other
17
17
 
18
- **It is** — an MCP server for a project's `AGENTS.md`, memory, and identity: nine
19
- tools, two discovery surfaces (Server Card `_meta`, `ai-catalog.json`), and a
20
- rendered [card](#the-card). Small, MIT — read it, `npx` it, or fork it.
18
+ Context, memory, and identity are essential — every MCP host needs an agent
19
+ that knows a project's instructions, remembers facts across sessions, and can
20
+ say what it is. `mcp-context-card` is those three, done once:
21
21
 
22
- **It is not**
22
+ - **Stand it up as your base MCP.** Point a host at it and an agent already
23
+ has `AGENTS.md` served section‑by‑section, `remember` / `recall` / `forget`
24
+ memory that survives a restart, and a `whoami` identity — before a single
25
+ tool of your own is written.
26
+ - **Or extend any existing MCP with it.** Run it alongside a server you
27
+ already have — filesystem, git, a database, your own — and that agent
28
+ gains context, memory, and identity discovery it didn't have. Nothing to
29
+ migrate; it composes.
23
30
 
24
- - a framework or a platform — three concerns, nothing more
25
- - a file, shell, or search tool — it never touches your files or runs commands
26
- - tied to FAF — context is plain Markdown (`AGENTS.md`); the memory and identity
27
- formats are swappable examples
31
+ Nine tools, two discovery surfaces already in the ecosystem (Server Card
32
+ `_meta`, `ai-catalog.json`), and a rendered [card](#the-card). MIT, on npm.
28
33
 
29
34
  It composes:
30
35
 
31
36
  - **serve · discover · render** — this server
32
- - **author · keep true** — [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts) (the `author_agents_md` tool wraps it)
37
+ - **author BETTER, keep true** — [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts) (`author_agents_md` wraps it for the facts layer; adds a BEST layer of its own from `project.faf` when one exists)
33
38
  - **files · shell · git** — [`server-filesystem`](https://github.com/modelcontextprotocol/servers), [`server-git`](https://github.com/modelcontextprotocol/servers) / github‑mcp‑server, your test runner's MCP
34
39
 
35
- A piece, not the toolbox.
40
+ Not a framework or a platform — three concerns, nothing more. Not a file,
41
+ shell, or search tool — it never touches your files or runs commands. Not
42
+ tied to FAF — context is plain Markdown (`AGENTS.md`); the memory and identity
43
+ formats are swappable examples.
36
44
 
37
45
  ## The card
38
46
 
@@ -55,7 +63,7 @@ Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
55
63
 
56
64
  | You want… | Reach for |
57
65
  |---|---|
58
- | an `AGENTS.md` and you don't have one | `author_agents_md` — or [`npx agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts) |
66
+ | an `AGENTS.md` and you don't have one | `author_agents_md` — BEST with a `project.faf`, BETTER without |
59
67
  | your agent to pull *one* `AGENTS.md` section on demand, not the whole file | `read_agents_md` · `list_agents_md_sections` |
60
68
  | a persistent notepad for your agent — survives restarts, no setup | `remember` · `recall` · `forget` |
61
69
  | a shareable view of what your MCP server exposes to agents | `GET /card` · `npx mcp-context-card card` |
@@ -65,20 +73,21 @@ Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
65
73
 
66
74
  ### No `AGENTS.md` yet?
67
75
 
68
- The `author_agents_md` tool authors one from your repo's facts — real
69
- build/test commands, entry points, toolchain conventions — and hands the agent
70
- the draft. It's a thin wrapper over
71
- [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts); to author or
72
- keep one true outside a session:
76
+ The `author_agents_md` tool authors one — **BETTER** from your repo's real
77
+ facts (build/test commands, entry points, toolchain conventions, via
78
+ [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts)), or
79
+ **BEST** when a `project.faf` exists: the same facts, plus its structured
80
+ goal, who it's for, and why, as a section ahead of them. Nothing to
81
+ configure — the tier follows what's actually there.
82
+ ([The ladder this follows.](https://github.com/Wolfe-Jam/agents-md-facts/blob/main/docs/BETTER-BEST.md))
83
+
84
+ To author or keep the facts layer true outside a session:
73
85
 
74
86
  ```bash
75
87
  npx agents-md-facts # author / refresh AGENTS.md
76
88
  npx agents-md-facts --check # fail if missing or stale (CI, pre-commit)
77
89
  ```
78
90
 
79
- A `project.faf` is the next rung — a structured source that refreshes the file.
80
- Short model: [`agents-md-facts/docs/BETTER-BEST.md`](https://github.com/Wolfe-Jam/agents-md-facts/blob/main/docs/BETTER-BEST.md).
81
-
82
91
  ### See the card
83
92
 
84
93
  One command, no host, no config:
@@ -109,6 +118,11 @@ memory tools work with or without it; identity is optional. Over HTTP instead:
109
118
  [docs/WIRING.md](./docs/WIRING.md); transport choice in
110
119
  [docs/TRANSPORT.md](./docs/TRANSPORT.md).
111
120
 
121
+ Extending an MCP you already run: most hosts accept more than one
122
+ `mcpServers` entry — add `context-card` alongside `server-filesystem`,
123
+ `server-git`, or your own, and every agent in that host gains context,
124
+ memory, and identity discovery without anything else changing.
125
+
112
126
  ## Why
113
127
 
114
128
  `AGENTS.md` is the de-facto standard for telling a coding agent how to work in a
@@ -137,7 +151,7 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
137
151
 
138
152
  | Tool | What it's for |
139
153
  |---|---|
140
- | `author_agents_md` | draft an `AGENTS.md` from the repo's facts (via `agents-md-facts`) — a managed block, ready to drop in |
154
+ | `author_agents_md` | draft an `AGENTS.md` — BETTER from the repo's facts (via `agents-md-facts`), BEST when a `project.faf` exists — ready to drop in |
141
155
  | `read_agents_md` | return the project's `AGENTS.md` — whole, or one section by heading |
142
156
  | `list_agents_md_sections` | the headings, so a client pulls one section instead of the whole file |
143
157
  | `remember` | write a fact that will still be there next session |
@@ -159,9 +173,10 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
159
173
  4. **Discovery** — `list_context_sources()`, then the same server over stateless
160
174
  HTTP with its `.well-known` routes and `GET /card`.
161
175
 
162
- 88 tests on Linux, macOS, and Windows, coverage‑gated in CI. One spawns a real
163
- child process and checks a remembered fact survives the restart; another checks
164
- the stdio and HTTP tool surfaces match.
176
+ 99 tests on Linux, macOS, and Windows, coverage‑gated in CI. Two spawn a real
177
+ child process and check a remembered fact survives the restart — one against
178
+ an existing `project.fafm`, one starting from a project that has never had
179
+ one; another checks the stdio and HTTP tool surfaces match.
165
180
 
166
181
  ## Layout
167
182
 
@@ -169,14 +184,14 @@ the stdio and HTTP tool surfaces match.
169
184
  |---|---|
170
185
  | `src/server.ts` | the nine tools + the Server Card resource |
171
186
  | `src/agents-md.ts` | reads and section‑splits `AGENTS.md` |
172
- | `src/author.ts` | `author_agents_md` — wraps [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts) |
187
+ | `src/author.ts` | `author_agents_md` — BETTER via [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts), BEST when `project.faf` exists |
173
188
  | `src/md.ts` | a minimal dependency‑free Markdown → HTML renderer |
174
189
  | `src/render-card.ts` | the card — identity + `AGENTS.md` + memory + discovery, as one HTML page |
175
190
  | `src/memory.ts` | file‑backed `remember` / `recall` / `forget` |
176
191
  | `src/identity.ts` | `whoami` (`.fafa` → `package.json` fallback) + the `_meta` block |
177
192
  | `src/catalog-gen.ts` | writes `ai-catalog.json` from the same three sources |
178
193
  | `src/transport/http.ts` | the stateless Streamable HTTP app (Hono) |
179
- | `src/bin.ts` | the entry point — `stdio` · `--http` · `card` |
194
+ | `src/bin.ts` | the entry point — `stdio` · `--http` · `card` · `--help` · `--version` |
180
195
 
181
196
  ## Related
182
197
 
package/dist/author.d.ts CHANGED
@@ -1,11 +1,20 @@
1
1
  /** The markers `agents-md-facts` uses to bound its managed block. */
2
2
  export declare const BLOCK_START = "<!-- agents:from-facts:start -->";
3
3
  export declare const BLOCK_END = "<!-- agents:from-facts:end -->";
4
+ /** The markers this file uses to bound the project.faf-sourced intent block. */
5
+ export declare const FAF_BLOCK_START = "<!-- context:from-faf:start -->";
6
+ export declare const FAF_BLOCK_END = "<!-- context:from-faf:end -->";
4
7
  export interface Authored {
5
- /** the AGENTS.md text — a managed block, ready to drop in */
8
+ /** the AGENTS.md text — one or two managed blocks, ready to drop in */
6
9
  markdown: string;
7
10
  /** whether an AGENTS.md already exists at the target */
8
11
  exists: boolean;
12
+ /** which tier was authored — BEST only when a readable project.faf was found */
13
+ tier: "better" | "best";
9
14
  }
10
- /** Author a managed AGENTS.md block for `root`, from its repo facts. */
15
+ /**
16
+ * Author AGENTS.md for `root`. BETTER from repo facts alone; BEST — facts
17
+ * plus the project.faf intent block, ahead of it — when a project.faf with
18
+ * real content exists.
19
+ */
11
20
  export declare function authorAgentsMd(root: string): Authored;
package/dist/author.js CHANGED
@@ -1,27 +1,86 @@
1
1
  /**
2
- * author — author an AGENTS.md for a project from its repo facts.
2
+ * author — author an AGENTS.md for a project, at the tier the project earns.
3
3
  *
4
- * The engine is `agents-md-facts` (a published, standalone tool, AGENTS.md
5
- * BETTER tier): it detects real build/test commands, entry points, toolchain
6
- * conventions and nothing invented. This wraps it in the managed-block
7
- * markers so `agents-md-facts --check` (or its Action / pre-commit hook) can
8
- * keep the result true afterwards.
4
+ * BETTER: the engine is `agents-md-facts` (a published, standalone tool) —
5
+ * it detects real build/test commands, entry points, toolchain conventions
6
+ * and nothing invented. Every project gets at least this.
9
7
  *
10
- * A `project.faf` is the BEST tier — the same discipline plus a structured
11
- * source of truth that refreshes the file. This wrapper stays at BETTER; the
12
- * README points at the BEST path.
8
+ * BEST: when `project.faf` exists, its structured intent — goal, who it's
9
+ * for, why it exists, the files that matter most — is real, human-authored
10
+ * truth that no amount of repo-scanning can detect. A project with a
11
+ * `project.faf` gets BOTH: the facts block, unchanged, plus this intent as
12
+ * its own managed block ahead of it. This is the whole point of the app:
13
+ * give the BEST AGENTS.md when the structured source to build it from is
14
+ * sitting right there.
13
15
  */
14
- import { existsSync } from "node:fs";
16
+ import { existsSync, readFileSync } from "node:fs";
15
17
  import { join } from "node:path";
18
+ import { parse } from "yaml";
16
19
  import { authorAgentsMd as authorBlock, buildRepoContext } from "agents-md-facts";
17
20
  /** The markers `agents-md-facts` uses to bound its managed block. */
18
21
  export const BLOCK_START = "<!-- agents:from-facts:start -->";
19
22
  export const BLOCK_END = "<!-- agents:from-facts:end -->";
20
- /** Author a managed AGENTS.md block for `root`, from its repo facts. */
23
+ /** The markers this file uses to bound the project.faf-sourced intent block. */
24
+ export const FAF_BLOCK_START = "<!-- context:from-faf:start -->";
25
+ export const FAF_BLOCK_END = "<!-- context:from-faf:end -->";
26
+ /** Read the structured intent out of `root`'s project.faf, or null if there isn't one to read. */
27
+ function readFafIntent(root) {
28
+ const path = join(root, "project.faf");
29
+ if (!existsSync(path))
30
+ return null;
31
+ try {
32
+ const doc = (parse(readFileSync(path, "utf8")) ?? {});
33
+ const project = doc.project ?? {};
34
+ const humanContext = doc.human_context ?? {};
35
+ const intent = {
36
+ name: str(project.name),
37
+ goal: str(project.goal),
38
+ who: str(humanContext.who),
39
+ why: str(humanContext.why),
40
+ keyFiles: Array.isArray(doc.key_files) ? doc.key_files.map(String).filter(Boolean) : undefined,
41
+ };
42
+ // A .faf with nothing usable in it isn't a real intent source.
43
+ return intent.goal || intent.who || intent.why ? intent : null;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ function str(v) {
50
+ const s = typeof v === "string" ? v.trim() : "";
51
+ return s || undefined;
52
+ }
53
+ /** Render the project.faf-sourced intent as its own managed block. */
54
+ function fafIntentBlock(intent) {
55
+ const lines = ["## Project", ""];
56
+ if (intent.goal)
57
+ lines.push(intent.goal, "");
58
+ if (intent.who)
59
+ lines.push(`**Who it's for:** ${intent.who}`, "");
60
+ if (intent.why)
61
+ lines.push(`**Why:** ${intent.why}`, "");
62
+ if (intent.keyFiles?.length) {
63
+ lines.push("**Start here:**", "");
64
+ for (const f of intent.keyFiles)
65
+ lines.push(`- \`${f}\``);
66
+ lines.push("");
67
+ }
68
+ return `${FAF_BLOCK_START}\n${lines.join("\n").trimEnd()}\n${FAF_BLOCK_END}\n`;
69
+ }
70
+ /**
71
+ * Author AGENTS.md for `root`. BETTER from repo facts alone; BEST — facts
72
+ * plus the project.faf intent block, ahead of it — when a project.faf with
73
+ * real content exists.
74
+ */
21
75
  export function authorAgentsMd(root) {
22
- const block = authorBlock(buildRepoContext(root)).trim();
76
+ const factsBlock = `${BLOCK_START}\n${authorBlock(buildRepoContext(root)).trim()}\n${BLOCK_END}\n`;
77
+ const exists = existsSync(join(root, "AGENTS.md"));
78
+ const intent = readFafIntent(root);
79
+ if (!intent)
80
+ return { markdown: factsBlock, exists, tier: "better" };
23
81
  return {
24
- markdown: `${BLOCK_START}\n${block}\n${BLOCK_END}\n`,
25
- exists: existsSync(join(root, "AGENTS.md")),
82
+ markdown: `${fafIntentBlock(intent)}\n${factsBlock}`,
83
+ exists,
84
+ tier: "best",
26
85
  };
27
86
  }
package/dist/bin.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export type Mode = "stdio" | "http" | "card";
2
+ export type Mode = "stdio" | "http" | "card" | "help" | "version";
3
3
  export interface Launch {
4
4
  mode: Mode;
5
5
  /** port for http mode (ignored otherwise). */
@@ -7,14 +7,18 @@ export interface Launch {
7
7
  /** directory to read from — cwd for `card`, else MCP_CONTEXT_CARD_ROOT ?? package root. */
8
8
  root: string;
9
9
  }
10
+ /** what a bare `--help` / `help` prints. */
11
+ export declare const HELP = "mcp-context-card 0.5.2\nServe a project's context (AGENTS.md), memory, and identity over MCP.\n\nUSAGE\n mcp-context-card stdio MCP server \u2014 what an MCP host spawns (default)\n mcp-context-card --http stateless Streamable HTTP on PORT (default 3000)\n mcp-context-card --stdio force stdio even when PORT is set\n mcp-context-card card [> f.html] render this directory's context card to stdout\n --theme light|dark --accent #hex\n mcp-context-card --help this text\n mcp-context-card --version print version\n\nENV\n MCP_CONTEXT_CARD_ROOT read AGENTS.md / project.fafm / .well-known/ from here\n PORT if set, run HTTP instead of stdio\n\nA bare run is an stdio server: it waits for a host to speak JSON-RPC on stdin,\nso it looks idle at a terminal. Try `card` or `--http` to see output directly.\nhttps://github.com/Wolfe-Jam/mcp-context-card\n";
10
12
  /**
11
13
  * Decide how to launch, from argv + env. Pure — so the mode matrix is unit
12
14
  * tested without spawning a process.
13
15
  *
14
- * card → render the cwd's card to stdout
15
- * (nothing) → stdio
16
- * --http | PORT=<n> → http
17
- * --stdio → stdio, even when PORT is set
16
+ * --help | -h | help → print usage
17
+ * --version | -V | version → print version
18
+ * card → render the cwd's card to stdout
19
+ * (nothing) → stdio
20
+ * --http | PORT=<n> → http
21
+ * --stdio → stdio, even when PORT is set
18
22
  */
19
23
  export declare function resolveLaunch(argv: readonly string[], env?: NodeJS.ProcessEnv): Launch;
20
24
  /** value of `--flag <value>` in argv, or undefined. */
package/dist/bin.js CHANGED
@@ -8,6 +8,8 @@
8
8
  * mcp-context-card --stdio → force stdio even when PORT is set
9
9
  * mcp-context-card card → render THIS directory's context card to stdout
10
10
  * ( > card.html · --theme light|dark · --accent #hex )
11
+ * mcp-context-card --help → usage
12
+ * mcp-context-card --version → version
11
13
  *
12
14
  * MCP_CONTEXT_CARD_ROOT=/path/to/project → read AGENTS.md / project.fafm /
13
15
  * .well-known/ from there instead of the package's own bundled copies.
@@ -15,17 +17,46 @@
15
17
  import { resolve } from "node:path";
16
18
  import { pathToFileURL } from "node:url";
17
19
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
20
+ import { NAME, VERSION } from "./constants.js";
18
21
  import { ROOT, serve } from "./server.js";
22
+ /** what a bare `--help` / `help` prints. */
23
+ export const HELP = `${NAME} ${VERSION}
24
+ Serve a project's context (AGENTS.md), memory, and identity over MCP.
25
+
26
+ USAGE
27
+ mcp-context-card stdio MCP server — what an MCP host spawns (default)
28
+ mcp-context-card --http stateless Streamable HTTP on PORT (default 3000)
29
+ mcp-context-card --stdio force stdio even when PORT is set
30
+ mcp-context-card card [> f.html] render this directory's context card to stdout
31
+ --theme light|dark --accent #hex
32
+ mcp-context-card --help this text
33
+ mcp-context-card --version print version
34
+
35
+ ENV
36
+ MCP_CONTEXT_CARD_ROOT read AGENTS.md / project.fafm / .well-known/ from here
37
+ PORT if set, run HTTP instead of stdio
38
+
39
+ A bare run is an stdio server: it waits for a host to speak JSON-RPC on stdin,
40
+ so it looks idle at a terminal. Try \`card\` or \`--http\` to see output directly.
41
+ https://github.com/Wolfe-Jam/mcp-context-card
42
+ `;
19
43
  /**
20
44
  * Decide how to launch, from argv + env. Pure — so the mode matrix is unit
21
45
  * tested without spawning a process.
22
46
  *
23
- * card → render the cwd's card to stdout
24
- * (nothing) → stdio
25
- * --http | PORT=<n> → http
26
- * --stdio → stdio, even when PORT is set
47
+ * --help | -h | help → print usage
48
+ * --version | -V | version → print version
49
+ * card → render the cwd's card to stdout
50
+ * (nothing) → stdio
51
+ * --http | PORT=<n> → http
52
+ * --stdio → stdio, even when PORT is set
27
53
  */
28
54
  export function resolveLaunch(argv, env = process.env) {
55
+ const has = (...flags) => flags.some((f) => argv.includes(f));
56
+ if (argv[0] === "help" || has("--help", "-h"))
57
+ return { mode: "help", port: 0, root: ROOT };
58
+ if (argv[0] === "version" || has("--version", "-V"))
59
+ return { mode: "version", port: 0, root: ROOT };
29
60
  if (argv[0] === "card") {
30
61
  return {
31
62
  mode: "card",
@@ -49,7 +80,13 @@ export function flagValue(argv, flag) {
49
80
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
50
81
  const argv = process.argv.slice(2);
51
82
  const { mode, port, root } = resolveLaunch(argv);
52
- if (mode === "card") {
83
+ if (mode === "help") {
84
+ process.stdout.write(HELP);
85
+ }
86
+ else if (mode === "version") {
87
+ process.stdout.write(`${VERSION}\n`);
88
+ }
89
+ else if (mode === "card") {
53
90
  const { renderCard, safeAccent } = await import("./render-card.js");
54
91
  const theme = flagValue(argv, "--theme");
55
92
  process.stdout.write(renderCard(root, {
@@ -62,9 +99,12 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
62
99
  const { serve: serveHttp } = await import("@hono/node-server");
63
100
  serveHttp({ fetch: httpApp(root).fetch, port });
64
101
  // stderr, not stdout — stdout is the MCP wire in stdio mode.
65
- console.error(`mcp-context-card · http · :${port} (POST /mcp · GET /card · GET /.well-known/*)`);
102
+ console.error(`${NAME} · http · :${port} (POST /mcp · GET /card · GET /.well-known/*)`);
66
103
  }
67
104
  else {
105
+ // stderr so it never touches the JSON-RPC wire on stdout; a bare run at a
106
+ // terminal otherwise looks hung.
107
+ console.error(`${NAME} · stdio · waiting for an MCP host on stdin (--help for usage · Ctrl-C to exit)`);
68
108
  await serve(new StdioServerTransport(), root);
69
109
  }
70
110
  }
@@ -1,5 +1,5 @@
1
1
  /** Server identity constants, in their own module so any file can import
2
2
  * them without pulling in the whole server. */
3
3
  export declare const NAME = "mcp-context-card";
4
- export declare const VERSION = "0.5.0";
4
+ export declare const VERSION = "0.5.2";
5
5
  export declare const SERVER_CARD_URI = "mcp-context-card://server-card";
package/dist/constants.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Server identity constants, in their own module so any file can import
2
2
  * them without pulling in the whole server. */
3
3
  export const NAME = "mcp-context-card";
4
- export const VERSION = "0.5.0";
4
+ export const VERSION = "0.5.2";
5
5
  export const SERVER_CARD_URI = "mcp-context-card://server-card";
@@ -27,8 +27,29 @@ function factMap(entries) {
27
27
  m.set(k, q(v));
28
28
  return m;
29
29
  }
30
+ /** A brand-new .fafm — what `remember()` writes the first time a project has none. */
31
+ const FRESH_FAFM = `version: "1.1"
32
+ memory:
33
+ facts: []
34
+ sessions: []
35
+ preferences: {}
36
+ custom: {}
37
+ `;
38
+ /**
39
+ * Load the .fafm at `path`. A missing file is not an error here — it means
40
+ * "no memory yet", and remember()/forget() need a document to edit even
41
+ * before anything has ever been written. Any other read error (permissions,
42
+ * a directory in the way, …) still throws.
43
+ */
30
44
  function load(path) {
31
- return parseDocument(readFileSync(path, "utf8"));
45
+ try {
46
+ return parseDocument(readFileSync(path, "utf8"));
47
+ }
48
+ catch (err) {
49
+ if (err.code === "ENOENT")
50
+ return parseDocument(FRESH_FAFM);
51
+ throw err;
52
+ }
32
53
  }
33
54
  export function parseFafm(path) {
34
55
  let doc;
@@ -16,7 +16,7 @@ export declare function whoami(root: string): string;
16
16
  * other two point at their worked-example artifacts; `memory` carries a note
17
17
  * because there is no de-facto standard for it yet.
18
18
  */
19
- export declare function trinityMeta(): {
19
+ export declare function serverCardMeta(): {
20
20
  readonly "io.github.wolfe-jam.mcp-context-card/context": {
21
21
  readonly source: "AGENTS.md";
22
22
  readonly mediaType: "text/markdown";
package/dist/identity.js CHANGED
@@ -61,7 +61,7 @@ export function whoami(root) {
61
61
  * other two point at their worked-example artifacts; `memory` carries a note
62
62
  * because there is no de-facto standard for it yet.
63
63
  */
64
- export function trinityMeta() {
64
+ export function serverCardMeta() {
65
65
  return {
66
66
  [`${META_NS}/context`]: {
67
67
  source: "AGENTS.md",
@@ -12,7 +12,7 @@
12
12
  import { join } from "node:path";
13
13
  import { parseAgentsMd } from "./agents-md.js";
14
14
  import { parseFafm } from "./memory.js";
15
- import { resolveIdentity, trinityMeta, META_NS } from "./identity.js";
15
+ import { resolveIdentity, serverCardMeta, META_NS } from "./identity.js";
16
16
  import { NAME, SERVER_CARD_URI } from "./constants.js";
17
17
  import { escapeHtml, renderInline, renderMarkdown, slug } from "./md.js";
18
18
  /** AAIF brand orange (aaif.io). The default accent. */
@@ -92,7 +92,7 @@ export function renderCard(root, opts = {}) {
92
92
  const agents = parseAgentsMd(join(root, "AGENTS.md"));
93
93
  const mem = parseFafm(join(root, "project.fafm"));
94
94
  const id = resolveIdentity(root);
95
- const meta = trinityMeta();
95
+ const meta = serverCardMeta();
96
96
  const name = id?.displayName ?? id?.name ?? NAME;
97
97
  const pills = [
98
98
  id?.vendor && id.vendor !== id.status && `<span class="pill">${escapeHtml(id.vendor)}</span>`,
package/dist/server.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  * mcp-context-card server — makes a project's context, memory, and identity
3
3
  * discoverable to any MCP client.
4
4
  *
5
- * context — read_agents_md · list_agents_md_sections (this project's AGENTS.md)
6
- * memory — remember · recall · forget (a .fafm file)
7
- * identity — whoami (this server's .fafa)
8
- * discovery — list_context_sources (what's published, and how)
5
+ * context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
6
+ * memory — remember · recall · forget (a .fafm file)
7
+ * identity — whoami (this server's .fafa)
8
+ * discovery — list_context_sources · render_context_card (what's published, and how)
9
9
  *
10
10
  * ...exposed through the two mechanisms already in the ecosystem:
11
11
  *
package/dist/server.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * mcp-context-card server — makes a project's context, memory, and identity
3
3
  * discoverable to any MCP client.
4
4
  *
5
- * context — read_agents_md · list_agents_md_sections (this project's AGENTS.md)
6
- * memory — remember · recall · forget (a .fafm file)
7
- * identity — whoami (this server's .fafa)
8
- * discovery — list_context_sources (what's published, and how)
5
+ * context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
6
+ * memory — remember · recall · forget (a .fafm file)
7
+ * identity — whoami (this server's .fafa)
8
+ * discovery — list_context_sources · render_context_card (what's published, and how)
9
9
  *
10
10
  * ...exposed through the two mechanisms already in the ecosystem:
11
11
  *
@@ -22,7 +22,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
22
22
  import { findSection, parseAgentsMd } from "./agents-md.js";
23
23
  import { authorAgentsMd } from "./author.js";
24
24
  import { forget, parseFafm, recall, remember } from "./memory.js";
25
- import { identity, trinityMeta, whoami } from "./identity.js";
25
+ import { identity, serverCardMeta, whoami } from "./identity.js";
26
26
  import { renderCard, safeAccent } from "./render-card.js";
27
27
  export { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
28
28
  import { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
@@ -36,7 +36,7 @@ export const ROOT = join(here, "..");
36
36
  * `/.well-known/mcp/server-card`.
37
37
  */
38
38
  export function serverCard() {
39
- return { name: NAME, version: VERSION, _meta: trinityMeta() };
39
+ return { name: NAME, version: VERSION, _meta: serverCardMeta() };
40
40
  }
41
41
  const text = (s) => ({ content: [{ type: "text", text: s }] });
42
42
  /**
@@ -88,7 +88,7 @@ export function createServer(root = ROOT) {
88
88
  },
89
89
  {
90
90
  name: "author_agents_md",
91
- description: "Author an AGENTS.md for this project from its repo facts (via agents-md-facts) and return the draft — a managed block, ready to drop in. Detects real build/test commands, entry points, and toolchain conventions; nothing invented. Does not write a file.",
91
+ description: "Author an AGENTS.md for this project and return the draft — BETTER from repo facts alone (via agents-md-facts: real build/test commands, entry points, toolchain conventions, nothing invented), or BEST when a project.faf exists (facts plus its structured goal/who/why as a second managed block ahead of them). Does not write a file.",
92
92
  inputSchema: { type: "object", properties: {} },
93
93
  },
94
94
  {
@@ -170,9 +170,10 @@ export function createServer(root = ROOT) {
170
170
  }
171
171
  case "author_agents_md": {
172
172
  const a = authorAgentsMd(root);
173
+ const tier = a.tier === "best" ? "BEST (project.faf + facts)" : "BETTER (facts only)";
173
174
  const note = a.exists
174
- ? "AGENTS.md already exists — diff this managed block in, don't overwrite"
175
- : "no AGENTS.md yet — write this, then `npx agents-md-facts --check` keeps it true";
175
+ ? `${tier} — AGENTS.md already exists, diff this in, don't overwrite`
176
+ : `${tier} — no AGENTS.md yet, write this, then \`npx agents-md-facts --check\` keeps the facts block true`;
176
177
  return text(`<!-- ${note} -->\n\n${a.markdown}`);
177
178
  }
178
179
  case "remember": {
@@ -4,14 +4,14 @@
4
4
  * A Hono app. `POST /mcp` is the MCP endpoint, run **stateless**: a fresh
5
5
  * server + transport per request, `sessionIdGenerator: undefined`, and
6
6
  * `enableJsonResponse` so every response is a complete JSON body (no SSE
7
- * stream, nothing to keep open). That's the right default for a reference
8
- * server — it scales horizontally, needs no sticky sessions, and there's
9
- * no per-connection state to leak. A server that needs server-streamed
7
+ * stream, nothing to keep open). That's the right default here — it scales
8
+ * horizontally, needs no sticky sessions, and there's no per-connection
9
+ * state to leak. A server that needs server-streamed
10
10
  * notifications or resumability would set a `sessionIdGenerator` and hold
11
11
  * transports in a map; this one deliberately does not.
12
12
  *
13
13
  * Alongside the MCP endpoint it serves the discovery documents:
14
- * GET /.well-known/mcp/server-card — the Server Card + _meta trinity
14
+ * GET /.well-known/mcp/server-card — the Server Card + _meta block
15
15
  * GET /.well-known/ai-catalog.json — the three sibling entries
16
16
  * GET /.well-known/fafa — the agent identity card
17
17
  */
@@ -5,7 +5,7 @@ mechanisms that already exist in the MCP ecosystem. This is the wire‑level
5
5
  detail.
6
6
 
7
7
  The **context** concern points at `AGENTS.md` (`text/markdown`). Memory and
8
- identity have no de‑facto standard, so the reference points them at `.fafm` and
8
+ identity have no de‑facto standard, so this server points them at `.fafm` and
9
9
  `.fafa`. Everything below is about the *shape* — swap the artifacts and the
10
10
  mechanism is unchanged.
11
11
 
@@ -29,7 +29,7 @@ Both return:
29
29
  ```jsonc
30
30
  {
31
31
  "name": "mcp-context-card",
32
- "version": "0.2.0",
32
+ "version": "0.5.2",
33
33
  "_meta": {
34
34
  "io.github.wolfe-jam.mcp-context-card/context": {
35
35
  "source": "AGENTS.md",
@@ -39,7 +39,7 @@ Both return:
39
39
  "source": "project.fafm",
40
40
  "mediaType": "application/vnd.fafm+yaml",
41
41
  "iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml",
42
- "note": "no de-facto standard for agent memory yet — one instantiation"
42
+ "note": "no de-facto standard for agent memory yet — this is one instantiation"
43
43
  },
44
44
  "io.github.wolfe-jam.mcp-context-card/identity": {
45
45
  "source": ".well-known/fafa",
@@ -64,7 +64,7 @@ Both return:
64
64
  is for instructions; the block says so rather than implying `.fafm` is a
65
65
  standard.
66
66
 
67
- Built by `trinityMeta()` in [`src/identity.ts`](../src/identity.ts).
67
+ Built by `serverCardMeta()` in [`src/identity.ts`](../src/identity.ts).
68
68
 
69
69
  ---
70
70
 
@@ -129,7 +129,7 @@ project.fafm ─┼─→ Server Card _meta (context · memory · identity)
129
129
  fafa
130
130
  ```
131
131
 
132
- `catalog-gen.ts` reads exactly the files `trinityMeta()` names. The CI job
132
+ `catalog-gen.ts` reads exactly the files `serverCardMeta()` names. The CI job
133
133
  `npm run catalog:check` regenerates `ai-catalog.json` and fails on any drift —
134
134
  change a source, both surfaces move together.
135
135
 
package/docs/TRANSPORT.md CHANGED
@@ -41,7 +41,7 @@ the wire, so all logging goes to `stderr`.
41
41
  ```
42
42
  GET / → index (endpoints)
43
43
  POST /mcp → MCP (initialize, tools/list, tools/call, …)
44
- GET /.well-known/mcp/server-card → the Server Card + _meta trinity block
44
+ GET /.well-known/mcp/server-card → the Server Card + _meta block
45
45
  GET /.well-known/ai-catalog.json → the three sibling entries
46
46
  GET /.well-known/fafa → the agent identity card
47
47
  ```
@@ -81,6 +81,6 @@ streaming tools would flip this. See `src/transport/http.ts`.
81
81
 
82
82
  ### DNS-rebinding protection
83
83
 
84
- Off by default (a reference server should run anywhere with no config). For
85
- a real deployment, pass `allowedHosts` / `allowedOrigins` to the transport
86
- and set `enableDnsRebindingProtection: true`.
84
+ Off by default (the server should run anywhere with no config). For a real
85
+ deployment, pass `allowedHosts` / `allowedOrigins` to the transport and set
86
+ `enableDnsRebindingProtection: true`.
package/docs/WIRING.md CHANGED
@@ -26,6 +26,13 @@
26
26
  - **`MCP_CONTEXT_CARD_ROOT`** — directory holding `AGENTS.md`, `project.fafm`, and
27
27
  `.well-known/fafa`. Omit it and the server uses its own bundled copies.
28
28
  - `stdout` is the JSON‑RPC wire; logging is on `stderr`.
29
+ - **`command: "npx"` fails to spawn on some hosts** (`spawn npx ENOENT`) — the
30
+ host's process spawn doesn't inherit a shell `PATH` that has `npx` on it,
31
+ even though a login shell does. Observed with Cursor. Fix: point `command`
32
+ at an absolute path to `node`, with the installed package's `dist/bin.js` as
33
+ the arg — e.g. `command: "node"`, `args: ["/path/to/node_modules/mcp-context-card/dist/bin.js"]`
34
+ (or wherever `npm install -g` / your package manager put it; find it with
35
+ `npm root -g` or `which mcp-context-card` after a global install).
29
36
 
30
37
  ### Streamable HTTP (remote)
31
38
 
@@ -72,7 +79,10 @@ And to discover what a server offers before committing to it:
72
79
  await client.callTool({ name: "list_context_sources", arguments: {} });
73
80
  // → { context: { source: "AGENTS.md", mediaType: "text/markdown", present: true, sections: 9 },
74
81
  // memory: { … }, identity: { … },
75
- // surfaces: { serverCard: [...], aiCatalog: [...] } }
82
+ // surfaces: { mcp: { serverCard: "resource mcp-context-card://server-card" },
83
+ // http: { serverCard: "GET /.well-known/mcp/server-card",
84
+ // aiCatalog: "GET /.well-known/ai-catalog.json",
85
+ // card: "GET /card" } } }
76
86
  ```
77
87
 
78
88
  ---
@@ -84,11 +94,11 @@ To serve *your* artifacts:
84
94
  1. **Replace the three files** — `AGENTS.md`, `project.fafm`, `.well-known/fafa`
85
95
  — with your own, or point `MCP_CONTEXT_CARD_ROOT` at a directory that has them.
86
96
  `AGENTS.md` is the one with a real standard; the other two are swappable.
87
- 2. **Rename the namespace.** `trinityMeta()` in `src/identity.ts` uses
97
+ 2. **Rename the namespace.** `serverCardMeta()` in `src/identity.ts` uses
88
98
  `io.github.wolfe-jam.mcp-context-card/*` keys, and `buildCatalog()` in
89
99
  `src/catalog-gen.ts` uses `urn:air:mcp-context-card:*` identifiers. Change both to
90
100
  a domain or GitHub identity you control ([MECHANISMS.md](./MECHANISMS.md)).
91
- 3. **Swap the media types** in `trinityMeta()` if your memory / identity
101
+ 3. **Swap the media types** in `serverCardMeta()` if your memory / identity
92
102
  artifacts aren't `.fafm` / `.fafa`. Drop the `iana` field for any that isn't
93
103
  a registered type.
94
104
  4. `npm run catalog` to regenerate, `npm run demo` to confirm all three still
package/docs/card.html CHANGED
@@ -73,11 +73,11 @@ section:last-child{border-bottom:0}
73
73
  <main class="card">
74
74
  <div class="top">
75
75
  <h1>mcp-context-card</h1>
76
- <div class="pills"><span class="pill">v0.5.0</span><span class="pill accent">reference</span><span class="pill">MIT</span></div>
76
+ <div class="pills"><span class="pill">io.github.wolfe-jam</span><span class="pill">v0.5.2</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
77
77
  </div>
78
78
  <section>
79
79
  <p class="label">Context — AGENTS.md</p>
80
- <ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><div class="md"><p><code>mcp-context-card</code> is an MCP server that makes a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> discoverable to any MCP client — through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
80
+ <ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><div class="md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
81
81
  <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
82
82
  <h2 id="setup">Setup</h2>
83
83
  <pre><code class="language-bash">npm ci</code></pre>
@@ -91,7 +91,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
91
91
  npm run demo # end to end: all tools over stdio, then over stateless HTTP</code></pre>
92
92
  <p>CI runs <code>typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>).</p>
93
93
  <h2 id="layout">Layout</h2>
94
- <table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — wraps <code>agents-md-facts</code> (the AGENTS.md authoring engine)</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
94
+ <table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
95
95
  <h2 id="conventions">Conventions</h2>
96
96
  <ul><li>TypeScript strict, ESM only (<code>&quot;type&quot;: &quot;module&quot;</code>, <code>.js</code> import specifiers).</li><li>Tests use <code>node:test</code> + <code>node:assert/strict</code> — no test framework.</li><li>Every source file opens with a comment stating what it is and why.</li><li>Conventional Commit messages (<code>feat:</code>, <code>fix:</code>, <code>chore:</code>, <code>test:</code>, <code>docs:</code>).</li></ul>
97
97
  <h2 id="the-invariant">The invariant</h2>
@@ -101,11 +101,11 @@ npm run demo # end to end: all tools over stdio, then over stateless HT
101
101
  <h2 id="definition-of-done">Definition of done</h2>
102
102
  <p><code>npm run typecheck &amp;&amp; npm run build &amp;&amp; npm test &amp;&amp; npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>.</p>
103
103
  <h2 id="authoring-this-file">Authoring this file</h2>
104
- <p><code>AGENTS.md</code> here is maintained by hand. It can also be generated from the repo's <code>project.faf</code> with <code>faf export --agents</code> — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
104
+ <p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
105
105
  </section>
106
106
  <section>
107
- <p class="label">Memory — 3 facts</p>
108
- <div class="fact"><p>The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so the reference uses .fafm and .fafa as one instantiation each.</p><div class="meta"><span class="tag">scope</span><span class="tag">agents-md</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart.</p><div class="meta"><span class="tag">mcp</span><span class="tag">server-card</span><span class="tag">ai-catalog</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Distribution: a published npm package (bin <code>mcp-context-card</code>, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project.</p><div class="meta"><span class="tag">distribution</span><span class="tag">mit</span><span class="tag">npm</span><span class="dot" title="verified"></span></div></div>
107
+ <p class="label">Memory — 4 facts</p>
108
+ <div class="fact"><p>The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so this server uses .fafm and .fafa as one instantiation each.</p><div class="meta"><span class="tag">scope</span><span class="tag">agents-md</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart.</p><div class="meta"><span class="tag">mcp</span><span class="tag">server-card</span><span class="tag">ai-catalog</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Distribution: a published npm package (bin <code>mcp-context-card</code>, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project.</p><div class="meta"><span class="tag">distribution</span><span class="tag">mit</span><span class="tag">npm</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>author_agents_md authors the best AGENTS.md the project has the material for, not a fixed floor. BETTER is the facts-only draft (via agents-md-facts: build/test commands, entry points, conventions — nothing invented). BEST is that plus a '## Project' section ahead of it, read straight from project.faf when one exists — goal, who it's for, why, and a start-here file list. The rule is concrete: project.faf present means BEST, absent means BETTER.</p><div class="meta"><span class="tag">agents-md</span><span class="tag">author_agents_md</span><span class="tag">faf</span><span class="dot" title="verified"></span></div></div>
109
109
  </section>
110
110
  <section>
111
111
  <p class="label">Discovery</p>
package/docs/img/card.png CHANGED
Binary file
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "mcp-context-card",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "mcpName": "io.github.wolfe-jam/mcp-context-card",
5
- "description": "Reference MCP server: project context, persistent memory, and agent identity — through the two exposure surfaces already in the ecosystem (Server Card _meta, ai-catalog sibling entries).",
5
+ "description": "The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server. Discoverable through the Server Card _meta block and ai-catalog.json sibling entries.",
6
6
  "keywords": [
7
7
  "mcp",
8
8
  "model-context-protocol",
9
+ "agents-md",
9
10
  "server-card",
10
11
  "ai-catalog",
11
12
  "project-context",
12
13
  "agent-memory",
13
14
  "agent-identity"
14
15
  ],
15
- "author": "wolfejam",
16
+ "author": "James Wolfe",
16
17
  "license": "MIT",
17
18
  "type": "module",
18
19
  "private": false,
package/project.faf CHANGED
@@ -1,7 +1,7 @@
1
1
  faf_version: "3.0"
2
2
  project:
3
3
  name: mcp-context-card
4
- goal: An MCP server that makes a project's context (its AGENTS.md), memory, and identity discoverable to any MCP client — through the Server Card _meta block and ai-catalog.json sibling entries, the two surfaces already in the ecosystem.
4
+ goal: The essential MCP server for a project's context (its AGENTS.md), memory, and identity — usable as a base MCP on its own, or as a drop-in extension for any existing MCP server. Discoverable to any MCP client through the Server Card _meta block and ai-catalog.json sibling entries, the two surfaces already in the ecosystem.
5
5
  main_language: TypeScript
6
6
  type: mcp
7
7
  stack:
@@ -16,13 +16,13 @@ stack:
16
16
  database: slotignored # memory is a file, not a DB
17
17
  connection: slotignored # no database
18
18
  hosting: Docker / any Node host — stdio for local, stateless Streamable HTTP for remote
19
- cicd: GitHub Actions (typecheck + build + test + demo, 3 OSes)
20
- tech_stack: [TypeScript, "@modelcontextprotocol/sdk", hono, yaml]
19
+ cicd: GitHub Actions — typecheck + build + test:coverage + demo on 3 OSes; catalog:check + card:check on Linux
20
+ tech_stack: [TypeScript, "@modelcontextprotocol/sdk", "agents-md-facts", hono, yaml]
21
21
  human_context:
22
22
  who: MCP host and server implementers who want a project's AGENTS.md, memory, and identity available over MCP without inventing an ad-hoc shape for each.
23
- what: An MCP server with seven tools — read_agents_md / list_agents_md_sections (context), remember / recall / forget (memory), whoami (identity), list_context_sources (discovery) — exposed through the Server Card _meta block and a self-published ai-catalog.json. Dual transport (stdio + stateless Streamable HTTP).
24
- why: AGENTS.md is the de-facto standard for agent instructions, but a client has to know the file exists and read it whole. There is no standard way for a server to publish "here is my AGENTS.md, here is what I remember, here is who I am". This does it through mechanisms that already exist.
23
+ what: The essential context, memory, and identity components for MCP — usable as a base MCP on its own, or dropped into any existing MCP server as an extension. Nine tools — read_agents_md / list_agents_md_sections / author_agents_md (context), remember / recall / forget (memory), whoami (identity), list_context_sources / render_context_card (discovery) — exposed through the Server Card _meta block and a self-published ai-catalog.json. Dual transport (stdio + stateless Streamable HTTP).
24
+ why: AGENTS.md is the de-facto standard for agent instructions, but a client has to know the file exists and read it whole. There is no standard way for a server to publish "here is my AGENTS.md, here is what I remember, here is who I am" — every server that wants this grows its own shape, or does without. This does it once, through mechanisms that already exist — as a base MCP, or dropped into what you've already built.
25
25
  where: github.com/Wolfe-Jam/mcp-context-card
26
26
  when: "2026-08-12"
27
27
  how: TypeScript on the MCP SDK. Dual transport in src/bin.ts. The Server Card _meta block and ai-catalog.json are generated from the same three sources (AGENTS.md, project.fafm, .well-known/fafa) — a CI check fails on drift. remember/recall are real file-backed reads/writes proven across a process boundary in demo.ts and the test suite. See docs/MECHANISMS.md, docs/WIRING.md, docs/TRANSPORT.md.
28
- key_files: [package.json, README.md, AGENTS.md, docs/MECHANISMS.md, src/server.ts, src/agents-md.ts, src/catalog-gen.ts, src/transport/http.ts]
28
+ key_files: [package.json, README.md, AGENTS.md, docs/MECHANISMS.md, src/server.ts, src/identity.ts, src/render-card.ts, src/author.ts, src/agents-md.ts, src/catalog-gen.ts, src/transport/http.ts]
package/project.fafm CHANGED
@@ -17,9 +17,9 @@ index:
17
17
 
18
18
  memory:
19
19
  facts:
20
- - text: "The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so the reference uses .fafm and .fafa as one instantiation each."
20
+ - text: "The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so this server uses .fafm and .fafa as one instantiation each."
21
21
  id: "mcp-context-card-scope"
22
- type: "reference"
22
+ type: "fact"
23
23
  priority: "high"
24
24
  tags: ["scope", "agents-md"]
25
25
  source: "README.md"
@@ -27,7 +27,7 @@ memory:
27
27
 
28
28
  - text: "Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart."
29
29
  id: "mechanisms-already-proven"
30
- type: "reference"
30
+ type: "fact"
31
31
  priority: "high"
32
32
  tags: ["mcp", "server-card", "ai-catalog"]
33
33
  links: ["mcp-context-card-scope"]
@@ -36,11 +36,20 @@ memory:
36
36
 
37
37
  - text: "Distribution: a published npm package (bin `mcp-context-card`, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project."
38
38
  id: "distribution-model"
39
- type: "reference"
39
+ type: "fact"
40
40
  priority: "standard"
41
41
  tags: ["distribution", "mit", "npm"]
42
42
  source: "README.md"
43
43
  verification_status: "verified"
44
+
45
+ - text: "author_agents_md authors the best AGENTS.md the project has the material for, not a fixed floor. BETTER is the facts-only draft (via agents-md-facts: build/test commands, entry points, conventions — nothing invented). BEST is that plus a '## Project' section ahead of it, read straight from project.faf when one exists — goal, who it's for, why, and a start-here file list. The rule is concrete: project.faf present means BEST, absent means BETTER."
46
+ id: "author-agents-md-best-not-just-better"
47
+ type: "fact"
48
+ priority: "high"
49
+ tags: ["agents-md", "author_agents_md", "faf"]
50
+ links: ["mcp-context-card-scope"]
51
+ source: "src/author.ts"
52
+ verification_status: "verified"
44
53
  sessions: []
45
54
  preferences: {}
46
55
  custom: {}
package/server.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.wolfe-jam/mcp-context-card",
4
4
  "title": "mcp-context-card",
5
- "description": "Reference MCP server that makes a project's context (AGENTS.md), memory, and identity discoverable to any MCP client — through the Server Card _meta block and ai-catalog.json sibling entries.",
6
- "version": "0.5.0",
5
+ "description": "The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server. Discoverable through the Server Card _meta block and ai-catalog.json sibling entries.",
6
+ "version": "0.5.2",
7
7
  "repository": {
8
8
  "url": "https://github.com/Wolfe-Jam/mcp-context-card",
9
9
  "source": "github"
@@ -13,7 +13,7 @@
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "mcp-context-card",
16
- "version": "0.5.0",
16
+ "version": "0.5.2",
17
17
  "runtimeHint": "npx",
18
18
  "transport": {
19
19
  "type": "stdio"
@@ -21,7 +21,7 @@
21
21
  "environmentVariables": [
22
22
  {
23
23
  "name": "MCP_CONTEXT_CARD_ROOT",
24
- "description": "Directory holding project.faf / project.fafm / .well-known/fafa. Omitted → the server's own bundled reference copies.",
24
+ "description": "Directory holding project.faf / project.fafm / .well-known/fafa. Omitted → the server's own bundled copies.",
25
25
  "isRequired": false
26
26
  }
27
27
  ]
@@ -37,7 +37,7 @@
37
37
  "source": "./project.fafm",
38
38
  "mediaType": "application/vnd.fafm+yaml",
39
39
  "iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml",
40
- "note": "no de-facto standard for agent memory yet — one instantiation"
40
+ "note": "no de-facto standard for agent memory yet — this is one instantiation"
41
41
  },
42
42
  "io.github.wolfe-jam.mcp-context-card/identity": {
43
43
  "source": "./.well-known/fafa",