mcp-context-card 1.0.0 → 1.1.0

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.
package/.well-known/fafa CHANGED
@@ -9,7 +9,7 @@ agent:
9
9
  name: "mcp-context-card"
10
10
  displayName: "mcp-context-card"
11
11
  vendor: "io.github.Wolfe-Jam"
12
- version: "1.0.0"
12
+ version: "1.1.0"
13
13
  description: >-
14
14
  The essential MCP components for a project's context (AGENTS.md),
15
15
  cross-session memory, and identity — a base MCP on its own, or a
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
+ ## 1.1.0
6
+
7
+ The card scans in one screen — AGENTS.md sections collapse by default.
8
+
9
+ Every AGENTS.md section is now its own `<details>`, closed on load: the card
10
+ opens as identity → the section list → memory count → discovery, one screen,
11
+ scannable. Click a section to read it; the section index stays sticky at the
12
+ top so it's always one click away, not a scroll back up.
13
+
14
+ - **Expand all / Collapse all** — a control in the sticky nav, from one
15
+ ~16-line inline script (no external resources; the card is still one
16
+ self-contained file). It's a progressive enhancement: the button ships
17
+ `hidden` and the script reveals it, so with JavaScript off every section
18
+ still opens and closes on its own.
19
+ - **`--expanded` / `?expand=all` / `expanded: true`** — the full-page render,
20
+ for a screenshot or a PR. Available on the CLI (`npx mcp-context-card card
21
+ --expanded`), the HTTP transport (`GET /card?expand=all`), and the
22
+ `render_context_card` tool. This path renders `<details open>` server-side —
23
+ no script involved.
24
+ - **A section index link opens its section** — `#section` in the URL, or a
25
+ click in the nav.
26
+ - **Print / save-as-PDF** opens every section first, then restores.
27
+
28
+ No API change to the nine tools. `render_context_card` gains an optional
29
+ `expanded` boolean; everything else is unchanged.
30
+
31
+ ## 1.0.1
32
+
33
+ `npx mcp-context-card` now runs — it silently no-op'd when launched through
34
+ `npx` or a global install. Plus: `card` opens your context in a browser at a
35
+ terminal, and Node 20 is supported.
36
+
37
+ Once `npx` works, `npx mcp-context-card card` from a project directory is the
38
+ fastest way to see what an agent actually gets: at a terminal it writes
39
+ `context-card.html` and opens it in your browser — no MCP host, no redirect.
40
+ Piped or redirected output is unchanged (`> card.html`, scripts, CI);
41
+ `--stdout` forces raw HTML from a terminal too.
42
+
43
+ - **Node 20 supported.** `engines` was `>=22` with nothing in the code that
44
+ needed it — it runs identically on Node 20 (verified against the published
45
+ package). No more `npm warn EBADENGINE` on the current LTS. CI now runs the
46
+ full suite on Node 20, 22, and 24 across all three OSes.
47
+ - **`card` at a terminal.** A bare `npx mcp-context-card card` used to dump
48
+ raw HTML at the prompt — noise for anyone who just wanted to look. Now it
49
+ writes a file and opens it; the pipe/redirect path is untouched.
50
+ - **`npx` / global-install entry fixed.** The bin's "am I the entry point?"
51
+ guard compared `import.meta.url` (always resolved) against an unresolved
52
+ `process.argv[1]` — so when `npx`, a global install, or `./node_modules/.bin`
53
+ routed through the bin **symlink**, the check failed and the CLI **silently
54
+ did nothing** (exit 0, no output). `process.argv[1]` is now realpath'd first.
55
+ Direct `node dist/bin.js` was never affected, which is why CI and the client
56
+ conformance passes (which spawn `node <path>`) stayed green. CI now also
57
+ exercises the packaged `npx` entry.
58
+
59
+ No API change. Nine tools, three concerns, two transports, two discovery
60
+ mechanisms — all as 1.0.0.
61
+
5
62
  ## 1.0.0
6
63
 
7
64
  Stable surface. No functional change from 0.6.2 — this release declares
@@ -16,10 +73,12 @@ mechanisms** (the Server Card `_meta` block, a self-published
16
73
 
17
74
  Verified against three independent clients before the cut:
18
75
 
19
- - **Cursor** (3.18.25 / Grok 4.6) — the full behavioural matrix, 10/10.
20
- - **The MCP SDK `Client`** driving the server over stdio — the same
21
- client stack a host uses, 10/10, `resources/templates/list` issued
22
- directly on the wire.
76
+ - **Cursor** (3.18.25 / Grok 4.6) — the full behavioural matrix, **10/10**.
77
+ - **Claude Code protocol pass** — the 10-item matrix run through the
78
+ MCP SDK `Client` + `StdioClientTransport` (the client stack Claude
79
+ Code uses), over stdio. **`CLAUDE CODE PROTOCOL PASS: 10/10`** —
80
+ every check, and `resources/templates/list` issued directly on the
81
+ wire (`[]`, not `-32601`).
23
82
  - **`@modelcontextprotocol/inspector`** (2.5.0, the canonical
24
83
  conformance tool) — every method answers correctly; `tools/list
25
84
  --strict` reports zero schema-portability problems across all nine.
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # mcp-context-card
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/mcp-context-card.svg)](https://www.npmjs.com/package/mcp-context-card)
3
4
  [![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
5
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
6
+ [![mcp-context-card MCP server](https://glama.ai/mcp/servers/Wolfe-Jam/mcp-context-card/badges/score.svg)](https://glama.ai/mcp/servers/Wolfe-Jam/mcp-context-card)
5
7
 
6
8
  **Get one. Or add it to yours.** The essential MCP server for a project's
7
9
  context, memory, and identity — discoverable to any MCP client, and
@@ -68,13 +70,21 @@ file access, no shell, no search.
68
70
 
69
71
  The screenshot at the top of this page is exactly this — the same three
70
72
  sources rendered as one self‑contained HTML page: identity, `AGENTS.md`,
71
- memory, and how a machine fetches it. The view for people: screenshot it,
72
- drop it in a PR, put it on a status page.
73
+ memory, and how a machine fetches it. The view for people: read it, screenshot
74
+ it, drop it in a PR, put it on a status page.
75
+
76
+ `AGENTS.md` sections are collapsed by default, so the card scans in one screen;
77
+ a sticky index jumps to any section, **Expand all** opens everything. Sections
78
+ toggle natively — the one small inline script only adds the bulk button and the
79
+ print handler. `--expanded` / `?expand=all` renders it fully open, script-free,
80
+ for a screenshot.
73
81
 
74
82
  ```
75
- GET /card # live, on the HTTP transport
76
- GET /card?theme=light&accent=%230066cc
77
- npx mcp-context-card card # or: npm run card → docs/card.html
83
+ npx mcp-context-card card # at a terminal: writes context-card.html and opens it
84
+ npx mcp-context-card card --expanded # every section open
85
+ npx mcp-context-card card > x.html # piped/redirected: raw HTML to stdout
86
+ GET /card # live, on the HTTP transport
87
+ GET /card?expand=all&theme=light&accent=%230066cc
78
88
  ```
79
89
 
80
90
  Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
@@ -104,12 +114,16 @@ npx agents-md-facts --check # fail if missing or stale (CI, pre-commit)
104
114
 
105
115
  ### See the card
106
116
 
107
- One command, no host, no config:
117
+ One command, no host, no config — from your project directory:
108
118
 
109
119
  ```bash
110
- npx mcp-context-card card > card.html
120
+ npx mcp-context-card card
111
121
  ```
112
122
 
123
+ At a terminal it writes `context-card.html` and opens it in your browser. Piped
124
+ or redirected (`> card.html`, a script, CI) it writes raw HTML to stdout instead;
125
+ `--stdout` forces that from a terminal too. `--expanded` opens every section.
126
+
113
127
  ### Wire it into a host
114
128
 
115
129
  Claude Desktop, Cursor, or any stdio host:
@@ -128,7 +142,7 @@ Claude Desktop, Cursor, or any stdio host:
128
142
 
129
143
  `MCP_CONTEXT_CARD_ROOT` points at the directory with your `AGENTS.md`. The
130
144
  memory tools work with or without it; identity is optional. Over HTTP instead:
131
- `PORT=8080 npx mcp-context-card`. Requires Node ≥22.
145
+ `PORT=8080 npx mcp-context-card`. Requires Node ≥20.
132
146
 
133
147
  If `command: "npx"` fails to spawn (`spawn npx ENOENT` — seen on Cursor, whose
134
148
  host process doesn't inherit a shell `PATH`), point `command` at `node` and
package/dist/bin.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface Launch {
8
8
  root: string;
9
9
  }
10
10
  /** what a bare `--help` / `help` prints. */
11
- export declare const HELP = "mcp-context-card 1.0.0\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";
11
+ export declare const HELP = "mcp-context-card 1.1.0\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 this dir's context card \u2014 opens it in your browser\n at a terminal; HTML to stdout when piped ( > f.html )\n --theme light|dark --accent #hex\n --expanded (all sections open) --stdout\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` (opens your context in a browser) or `--http`.\nhttps://github.com/Wolfe-Jam/mcp-context-card\n";
12
12
  /**
13
13
  * Decide how to launch, from argv + env. Pure — so the mode matrix is unit
14
14
  * tested without spawning a process.
package/dist/bin.js CHANGED
@@ -6,14 +6,18 @@
6
6
  * mcp-context-card --http → stateless Streamable HTTP on PORT (default 3000)
7
7
  * PORT=8080 mcp-context-card → HTTP too (a hosted deploy sets PORT)
8
8
  * mcp-context-card --stdio → force stdio even when PORT is set
9
- * mcp-context-card card → render THIS directory's context card to stdout
10
- * ( > card.html · --theme light|dark · --accent #hex )
9
+ * mcp-context-card card → this directory's context card. At a terminal:
10
+ * writes context-card.html and opens it. Piped
11
+ * or redirected: HTML to stdout ( > card.html ).
12
+ * --theme light|dark · --accent #hex
13
+ * --expanded (all sections open) · --stdout
11
14
  * mcp-context-card --help → usage
12
15
  * mcp-context-card --version → version
13
16
  *
14
17
  * MCP_CONTEXT_CARD_ROOT=/path/to/project → read AGENTS.md / project.fafm /
15
18
  * .well-known/ from there instead of the package's own bundled copies.
16
19
  */
20
+ import { realpathSync } from "node:fs";
17
21
  import { resolve } from "node:path";
18
22
  import { pathToFileURL } from "node:url";
19
23
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -27,8 +31,10 @@ USAGE
27
31
  mcp-context-card stdio MCP server — what an MCP host spawns (default)
28
32
  mcp-context-card --http stateless Streamable HTTP on PORT (default 3000)
29
33
  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
34
+ mcp-context-card card this dir's context card — opens it in your browser
35
+ at a terminal; HTML to stdout when piped ( > f.html )
36
+ --theme light|dark --accent #hex
37
+ --expanded (all sections open) --stdout
32
38
  mcp-context-card --help this text
33
39
  mcp-context-card --version print version
34
40
 
@@ -37,7 +43,7 @@ ENV
37
43
  PORT if set, run HTTP instead of stdio
38
44
 
39
45
  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.
46
+ so it looks idle at a terminal. Try \`card\` (opens your context in a browser) or \`--http\`.
41
47
  https://github.com/Wolfe-Jam/mcp-context-card
42
48
  `;
43
49
  /**
@@ -76,8 +82,21 @@ export function flagValue(argv, flag) {
76
82
  const i = argv.indexOf(flag);
77
83
  return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined;
78
84
  }
79
- /** Direct run only — importing this module (e.g. from a test) must not launch. */
80
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
85
+ /**
86
+ * Direct run only — importing this module (e.g. from a test) must not launch.
87
+ * `process.argv[1]` can be a bin symlink (`npx`, a global install, `.bin/…`)
88
+ * while `import.meta.url` is always the resolved file, so realpath argv[1]
89
+ * before comparing — otherwise the CLI silently no-ops when run via npx.
90
+ */
91
+ const entryPath = (() => {
92
+ try {
93
+ return process.argv[1] ? realpathSync(process.argv[1]) : undefined;
94
+ }
95
+ catch {
96
+ return process.argv[1];
97
+ }
98
+ })();
99
+ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
81
100
  const argv = process.argv.slice(2);
82
101
  const { mode, port, root } = resolveLaunch(argv);
83
102
  if (mode === "help") {
@@ -89,10 +108,32 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
89
108
  else if (mode === "card") {
90
109
  const { renderCard, safeAccent } = await import("./render-card.js");
91
110
  const theme = flagValue(argv, "--theme");
92
- process.stdout.write(renderCard(root, {
111
+ const html = renderCard(root, {
93
112
  theme: theme === "light" || theme === "dark" ? theme : "auto",
94
113
  accent: safeAccent(flagValue(argv, "--accent")),
95
- }));
114
+ expanded: argv.includes("--expanded"),
115
+ });
116
+ // Piped / redirected (or --stdout) → raw HTML on stdout, unchanged.
117
+ // A bare run at a terminal → the HTML is noise; write a file and open it.
118
+ if (!process.stdout.isTTY || argv.includes("--stdout")) {
119
+ process.stdout.write(html);
120
+ }
121
+ else {
122
+ const { writeFileSync } = await import("node:fs");
123
+ const { join } = await import("node:path");
124
+ const { spawn } = await import("node:child_process");
125
+ const out = join(process.cwd(), "context-card.html");
126
+ writeFileSync(out, html);
127
+ const opener = process.platform === "darwin"
128
+ ? ["open", [out]]
129
+ : process.platform === "win32"
130
+ ? ["cmd", ["/c", "start", "", out]]
131
+ : ["xdg-open", [out]];
132
+ spawn(opener[0], opener[1], { stdio: "ignore", detached: true })
133
+ .on("error", () => { })
134
+ .unref();
135
+ process.stderr.write(`${NAME} · wrote ${out} — opening in your browser (--stdout for raw HTML)\n`);
136
+ }
96
137
  }
97
138
  else if (mode === "http") {
98
139
  const { httpApp } = await import("./transport/http.js");
@@ -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 = "1.0.0";
4
+ export declare const VERSION = "1.1.0";
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 = "1.0.0";
4
+ export const VERSION = "1.1.0";
5
5
  export const SERVER_CARD_URI = "mcp-context-card://server-card";
@@ -3,6 +3,12 @@ export interface CardOptions {
3
3
  theme?: Theme;
4
4
  /** CSS hex colour for the accent. Validated; invalid falls back to AAIF. */
5
5
  accent?: string;
6
+ /**
7
+ * Render every AGENTS.md section open. Default: sections collapse to their
8
+ * headings (`<details>`), click one to read it — the card scans in one screen.
9
+ * `expanded` is the whole-page render, for a screenshot or a PR.
10
+ */
11
+ expanded?: boolean;
6
12
  }
7
13
  /** AAIF brand orange (aaif.io). The default accent. */
8
14
  export declare const AAIF_ACCENT = "#FF702D";
@@ -6,8 +6,9 @@
6
6
  * or drop into a PR. Same three sources as the Server Card _meta block and
7
7
  * ai-catalog; this is the view for people.
8
8
  *
9
- * Self-contained: inline CSS, no JS, no external fonts. Renders anywhere,
10
- * including as a data: URI.
9
+ * Self-contained: inline CSS, no external fonts or resources. The only script
10
+ * is the expand-all / print helper (TOGGLE_SCRIPT) — a progressive enhancement;
11
+ * every section still opens on its own without it. Renders anywhere.
11
12
  */
12
13
  import { join } from "node:path";
13
14
  import { parseAgentsMd } from "./agents-md.js";
@@ -47,7 +48,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
47
48
  font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
48
49
  padding:40px 18px}
49
50
  .card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
50
- border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
51
+ border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
51
52
  .card>*{padding:26px 30px}
52
53
  .top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
53
54
  h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
@@ -58,9 +59,31 @@ section{border-bottom:1px solid var(--line)}
58
59
  section:last-child{border-bottom:0}
59
60
  .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
60
61
  color:var(--accent);margin:0 0 14px}
61
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
62
+ .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
62
63
  .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
63
64
  .toc a:hover{color:var(--accent)}
65
+ /* ── collapsible context ─────────────────────────────────────────── */
66
+ .ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
67
+ margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
68
+ display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
69
+ .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
70
+ white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
71
+ background:var(--chip);color:var(--muted);cursor:pointer}
72
+ .xall:hover{color:var(--accent);border-color:var(--accent)}
73
+ .ctx-preamble{padding-bottom:4px}
74
+ details.ctx-section{border-top:1px solid var(--line)}
75
+ details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
76
+ font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
77
+ details.ctx-section>summary::-webkit-details-marker{display:none}
78
+ details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
79
+ transition:transform .15s ease}
80
+ details.ctx-section[open]>summary::before{transform:rotate(90deg)}
81
+ details.ctx-section>.md{padding:0 0 16px}
82
+ @media print{
83
+ .ctx-nav{display:none}
84
+ details.ctx-section:not([open])>.md{display:block!important}
85
+ details.ctx-section>summary::before{content:""}
86
+ }
64
87
  .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
65
88
  .md h1{font-size:1.15rem}
66
89
  .md p{margin:8px 0}
@@ -107,21 +130,28 @@ export function renderCard(root, opts = {}) {
107
130
  ]
108
131
  .filter(Boolean)
109
132
  .join("");
110
- // CONTEXT — drop the redundant top-level "# AGENTS.md" heading, keep its intro
133
+ // CONTEXT — one <details> per AGENTS.md section, collapsed by default (the card
134
+ // scans in one screen); `expanded` renders them all open. The "# AGENTS.md"
135
+ // top-level heading is dropped; its intro rides above the sections.
111
136
  const bodySections = agents?.sections.filter((s) => s.level > 1) ?? [];
112
137
  const toc = bodySections.length
113
138
  ? `<ul class="toc">${bodySections
114
139
  .map((s) => `<li><a href="#${slug(s.heading)}">${escapeHtml(s.heading)}</a></li>`)
115
140
  .join("")}</ul>`
116
141
  : "";
142
+ const preamble = [agents?.preamble, agents?.sections.find((s) => s.level === 1)?.body ?? ""]
143
+ .filter(Boolean)
144
+ .join("\n\n");
145
+ const openAttr = opts.expanded ? " open" : "";
146
+ const sections = bodySections
147
+ .map((s) => `<details class="ctx-section"${openAttr} id="${slug(s.heading)}"><summary>${escapeHtml(s.heading)}</summary><div class="md">${renderMarkdown(s.body)}</div></details>`)
148
+ .join("");
117
149
  const contextBody = agents
118
- ? `${toc}<div class="md">${renderMarkdown([
119
- agents.preamble,
120
- agents.sections.find((s) => s.level === 1)?.body ?? "",
121
- ...bodySections.map((s) => `${"#".repeat(s.level)} ${s.heading}\n\n${s.body}`),
122
- ]
123
- .filter(Boolean)
124
- .join("\n\n"))}</div>`
150
+ ? `<div class="ctx-nav">${toc}${bodySections.length
151
+ ? `<button type="button" class="xall" hidden>${opts.expanded ? "Collapse all" : "Expand all"}</button>`
152
+ : ""}</div>
153
+ ${preamble ? `<div class="ctx-preamble md">${renderMarkdown(preamble)}</div>` : ""}
154
+ <div class="ctx-body">${sections}</div>`
125
155
  : `<p class="none">No AGENTS.md in this project.</p>`;
126
156
  // MEMORY
127
157
  const memoryBody = mem.facts.length
@@ -174,7 +204,35 @@ export function renderCard(root, opts = {}) {
174
204
  </section>
175
205
  <div class="foot">${escapeHtml(name)} · context card</div>
176
206
  </main>
207
+ ${bodySections.length ? TOGGLE_SCRIPT : ""}
177
208
  </body>
178
209
  </html>
179
210
  `;
180
211
  }
212
+ /**
213
+ * Expand-all / Collapse-all. The only script in the card — a progressive
214
+ * enhancement: with it off, every section still opens and closes on its own
215
+ * (native `<details>`), just without the bulk button. It also opens every
216
+ * section for printing, since browsers don't agree on whether a closed
217
+ * `<details>` prints its content.
218
+ */
219
+ const TOGGLE_SCRIPT = `<script>
220
+ (function(){
221
+ var btn=document.querySelector(".xall");
222
+ var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
223
+ if(!btn||!secs.length)return;
224
+ var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
225
+ btn.hidden=false;
226
+ btn.addEventListener("click",function(){
227
+ var open=!secs.every(function(d){return d.open});
228
+ secs.forEach(function(d){d.open=open});sync();
229
+ });
230
+ secs.forEach(function(d){d.addEventListener("toggle",sync)});
231
+ var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
232
+ addEventListener("hashchange",openHash);openHash();
233
+ var pre=[];
234
+ addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
235
+ addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
236
+ sync();
237
+ })();
238
+ </script>`;
package/dist/server.js CHANGED
@@ -161,12 +161,13 @@ export function createServer(root = ROOT) {
161
161
  },
162
162
  {
163
163
  name: "render_context_card",
164
- description: "Render the whole card — identity, AGENTS.md, memory, discovery — as one self-contained HTML page a person can read or screenshot. Also served at GET /card over the HTTP transport.",
164
+ description: "Render the whole card — identity, AGENTS.md, memory, discovery — as one self-contained HTML page a person can read or screenshot. AGENTS.md sections collapse by default; pass expanded:true for the full render. Also served at GET /card (?expand=all) over the HTTP transport.",
165
165
  inputSchema: {
166
166
  type: "object",
167
167
  properties: {
168
168
  theme: { type: "string", enum: ["light", "dark", "auto"], description: "default: auto" },
169
169
  accent: { type: "string", description: "CSS hex colour, e.g. #FF702D (default: the AAIF palette)" },
170
+ expanded: { type: "boolean", description: "render every AGENTS.md section open (default: collapsed)" },
170
171
  },
171
172
  },
172
173
  },
@@ -215,7 +216,8 @@ export function createServer(root = ROOT) {
215
216
  }
216
217
  case "whoami":
217
218
  return text(whoami(root));
218
- case "render_context_card":
219
+ case "render_context_card": {
220
+ const rawExpanded = args.expanded;
219
221
  return {
220
222
  content: [
221
223
  {
@@ -223,10 +225,12 @@ export function createServer(root = ROOT) {
223
225
  text: renderCard(root, {
224
226
  theme: (["light", "dark", "auto"].includes(args.theme) ? args.theme : "auto"),
225
227
  accent: safeAccent(args.accent),
228
+ expanded: rawExpanded === true || rawExpanded === "true",
226
229
  }),
227
230
  },
228
231
  ],
229
232
  };
233
+ }
230
234
  case "list_context_sources": {
231
235
  const doc = parseAgentsMd(AGENTS);
232
236
  const mem = parseFafm(FAFM);
@@ -56,7 +56,7 @@ export function httpApp(root = ROOT) {
56
56
  const q = c.req.query();
57
57
  const theme = (["light", "dark", "auto"].includes(q.theme ?? "") ? q.theme : "auto");
58
58
  c.header("content-type", "text/html; charset=utf-8");
59
- return c.body(renderCard(root, { theme, accent: safeAccent(q.accent) }));
59
+ return c.body(renderCard(root, { theme, accent: safeAccent(q.accent), expanded: q.expand === "all" }));
60
60
  });
61
61
  // ── Index ───────────────────────────────────────────────────────────
62
62
  app.get("/", (c) => c.json({
@@ -29,7 +29,7 @@ Both return:
29
29
  ```jsonc
30
30
  {
31
31
  "name": "mcp-context-card",
32
- "version": "1.0.0",
32
+ "version": "1.1.0",
33
33
  "_meta": {
34
34
  "io.github.Wolfe-Jam.mcp-context-card/context": {
35
35
  "source": "AGENTS.md",
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
30
30
  font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
31
31
  padding:40px 18px}
32
32
  .card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
33
- border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
33
+ border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
34
34
  .card>*{padding:26px 30px}
35
35
  .top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
36
36
  h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
41
41
  section:last-child{border-bottom:0}
42
42
  .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
43
43
  color:var(--accent);margin:0 0 14px}
44
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
44
+ .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
45
45
  .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
46
46
  .toc a:hover{color:var(--accent)}
47
+ /* ── collapsible context ─────────────────────────────────────────── */
48
+ .ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
49
+ margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
50
+ display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
51
+ .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
52
+ white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
53
+ background:var(--chip);color:var(--muted);cursor:pointer}
54
+ .xall:hover{color:var(--accent);border-color:var(--accent)}
55
+ .ctx-preamble{padding-bottom:4px}
56
+ details.ctx-section{border-top:1px solid var(--line)}
57
+ details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
58
+ font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
59
+ details.ctx-section>summary::-webkit-details-marker{display:none}
60
+ details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
61
+ transition:transform .15s ease}
62
+ details.ctx-section[open]>summary::before{transform:rotate(90deg)}
63
+ details.ctx-section>.md{padding:0 0 16px}
64
+ @media print{
65
+ .ctx-nav{display:none}
66
+ details.ctx-section:not([open])>.md{display:block!important}
67
+ details.ctx-section>summary::before{content:""}
68
+ }
47
69
  .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
48
70
  .md h1{font-size:1.15rem}
49
71
  .md p{margin:8px 0}
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
78
100
  <main class="card">
79
101
  <div class="top">
80
102
  <h1>mcp-context-card</h1>
81
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.0.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
103
+ <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
82
104
  </div>
83
105
  <section>
84
106
  <p class="label">Context — AGENTS.md</p>
85
- <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>
86
- <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
87
- <h2 id="setup">Setup</h2>
88
- <pre><code class="language-bash">npm ci</code></pre>
89
- <p>Node 22 or newer. No other system dependencies.</p>
90
- <h2 id="build">Build</h2>
91
- <pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
92
- npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
93
- <h2 id="test">Test</h2>
94
- <pre><code class="language-bash">npm test # node:test — every test/*.test.ts
107
+ <div class="ctx-nav"><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><button type="button" class="xall" hidden>Expand all</button></div>
108
+ <div class="ctx-preamble 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>
109
+ <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
110
+ <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
111
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
112
+ npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
95
113
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
96
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
97
115
  npm run version:check # every version-bearing spot agrees with package.json
98
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
99
- <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
100
- <h2 id="layout">Layout</h2>
101
- <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>
102
- <h2 id="conventions">Conventions</h2>
103
- <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>
104
- <h2 id="the-invariant">The invariant</h2>
105
- <p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
106
- <h2 id="safety">Safety</h2>
107
- <ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
108
- <h2 id="definition-of-done">Definition of done</h2>
109
- <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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
110
- <h2 id="authoring-this-file">Authoring this file</h2>
111
- <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>
117
+ <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><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></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><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></div></details><details class="ctx-section" id="the-invariant"><summary>The invariant</summary><div class="md"><p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p></div></details><details class="ctx-section" id="safety"><summary>Safety</summary><div class="md"><ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul></div></details><details class="ctx-section" id="definition-of-done"><summary>Definition of done</summary><div class="md"><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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><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></details></div>
112
118
  </section>
113
119
  <section>
114
120
  <p class="label">Memory — 4 facts</p>
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
124
130
  </section>
125
131
  <div class="foot">mcp-context-card · context card</div>
126
132
  </main>
133
+ <script>
134
+ (function(){
135
+ var btn=document.querySelector(".xall");
136
+ var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
137
+ if(!btn||!secs.length)return;
138
+ var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
139
+ btn.hidden=false;
140
+ btn.addEventListener("click",function(){
141
+ var open=!secs.every(function(d){return d.open});
142
+ secs.forEach(function(d){d.open=open});sync();
143
+ });
144
+ secs.forEach(function(d){d.addEventListener("toggle",sync)});
145
+ var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
146
+ addEventListener("hashchange",openHash);openHash();
147
+ var pre=[];
148
+ addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
149
+ addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
150
+ sync();
151
+ })();
152
+ </script>
127
153
  </body>
128
154
  </html>
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
30
30
  font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
31
31
  padding:40px 18px}
32
32
  .card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
33
- border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
33
+ border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
34
34
  .card>*{padding:26px 30px}
35
35
  .top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
36
36
  h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
41
41
  section:last-child{border-bottom:0}
42
42
  .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
43
43
  color:var(--accent);margin:0 0 14px}
44
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
44
+ .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
45
45
  .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
46
46
  .toc a:hover{color:var(--accent)}
47
+ /* ── collapsible context ─────────────────────────────────────────── */
48
+ .ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
49
+ margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
50
+ display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
51
+ .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
52
+ white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
53
+ background:var(--chip);color:var(--muted);cursor:pointer}
54
+ .xall:hover{color:var(--accent);border-color:var(--accent)}
55
+ .ctx-preamble{padding-bottom:4px}
56
+ details.ctx-section{border-top:1px solid var(--line)}
57
+ details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
58
+ font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
59
+ details.ctx-section>summary::-webkit-details-marker{display:none}
60
+ details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
61
+ transition:transform .15s ease}
62
+ details.ctx-section[open]>summary::before{transform:rotate(90deg)}
63
+ details.ctx-section>.md{padding:0 0 16px}
64
+ @media print{
65
+ .ctx-nav{display:none}
66
+ details.ctx-section:not([open])>.md{display:block!important}
67
+ details.ctx-section>summary::before{content:""}
68
+ }
47
69
  .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
48
70
  .md h1{font-size:1.15rem}
49
71
  .md p{margin:8px 0}
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
78
100
  <main class="card">
79
101
  <div class="top">
80
102
  <h1>mcp-context-card</h1>
81
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.0.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
103
+ <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
82
104
  </div>
83
105
  <section>
84
106
  <p class="label">Context — AGENTS.md</p>
85
- <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>
86
- <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
87
- <h2 id="setup">Setup</h2>
88
- <pre><code class="language-bash">npm ci</code></pre>
89
- <p>Node 22 or newer. No other system dependencies.</p>
90
- <h2 id="build">Build</h2>
91
- <pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
92
- npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
93
- <h2 id="test">Test</h2>
94
- <pre><code class="language-bash">npm test # node:test — every test/*.test.ts
107
+ <div class="ctx-nav"><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><button type="button" class="xall" hidden>Expand all</button></div>
108
+ <div class="ctx-preamble 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>
109
+ <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
110
+ <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
111
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
112
+ npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
95
113
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
96
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
97
115
  npm run version:check # every version-bearing spot agrees with package.json
98
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
99
- <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
100
- <h2 id="layout">Layout</h2>
101
- <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>
102
- <h2 id="conventions">Conventions</h2>
103
- <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>
104
- <h2 id="the-invariant">The invariant</h2>
105
- <p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
106
- <h2 id="safety">Safety</h2>
107
- <ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
108
- <h2 id="definition-of-done">Definition of done</h2>
109
- <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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
110
- <h2 id="authoring-this-file">Authoring this file</h2>
111
- <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>
117
+ <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><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></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><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></div></details><details class="ctx-section" id="the-invariant"><summary>The invariant</summary><div class="md"><p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p></div></details><details class="ctx-section" id="safety"><summary>Safety</summary><div class="md"><ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul></div></details><details class="ctx-section" id="definition-of-done"><summary>Definition of done</summary><div class="md"><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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><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></details></div>
112
118
  </section>
113
119
  <section>
114
120
  <p class="label">Memory — 4 facts</p>
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
124
130
  </section>
125
131
  <div class="foot">mcp-context-card · context card</div>
126
132
  </main>
133
+ <script>
134
+ (function(){
135
+ var btn=document.querySelector(".xall");
136
+ var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
137
+ if(!btn||!secs.length)return;
138
+ var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
139
+ btn.hidden=false;
140
+ btn.addEventListener("click",function(){
141
+ var open=!secs.every(function(d){return d.open});
142
+ secs.forEach(function(d){d.open=open});sync();
143
+ });
144
+ secs.forEach(function(d){d.addEventListener("toggle",sync)});
145
+ var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
146
+ addEventListener("hashchange",openHash);openHash();
147
+ var pre=[];
148
+ addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
149
+ addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
150
+ sync();
151
+ })();
152
+ </script>
127
153
  </body>
128
154
  </html>
package/docs/card.html CHANGED
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
30
30
  font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
31
31
  padding:40px 18px}
32
32
  .card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
33
- border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
33
+ border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
34
34
  .card>*{padding:26px 30px}
35
35
  .top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
36
36
  h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
41
41
  section:last-child{border-bottom:0}
42
42
  .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
43
43
  color:var(--accent);margin:0 0 14px}
44
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
44
+ .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
45
45
  .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
46
46
  .toc a:hover{color:var(--accent)}
47
+ /* ── collapsible context ─────────────────────────────────────────── */
48
+ .ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
49
+ margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
50
+ display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
51
+ .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
52
+ white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
53
+ background:var(--chip);color:var(--muted);cursor:pointer}
54
+ .xall:hover{color:var(--accent);border-color:var(--accent)}
55
+ .ctx-preamble{padding-bottom:4px}
56
+ details.ctx-section{border-top:1px solid var(--line)}
57
+ details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
58
+ font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
59
+ details.ctx-section>summary::-webkit-details-marker{display:none}
60
+ details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
61
+ transition:transform .15s ease}
62
+ details.ctx-section[open]>summary::before{transform:rotate(90deg)}
63
+ details.ctx-section>.md{padding:0 0 16px}
64
+ @media print{
65
+ .ctx-nav{display:none}
66
+ details.ctx-section:not([open])>.md{display:block!important}
67
+ details.ctx-section>summary::before{content:""}
68
+ }
47
69
  .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
48
70
  .md h1{font-size:1.15rem}
49
71
  .md p{margin:8px 0}
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
78
100
  <main class="card">
79
101
  <div class="top">
80
102
  <h1>mcp-context-card</h1>
81
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.0.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
103
+ <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
82
104
  </div>
83
105
  <section>
84
106
  <p class="label">Context — AGENTS.md</p>
85
- <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>
86
- <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
87
- <h2 id="setup">Setup</h2>
88
- <pre><code class="language-bash">npm ci</code></pre>
89
- <p>Node 22 or newer. No other system dependencies.</p>
90
- <h2 id="build">Build</h2>
91
- <pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
92
- npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
93
- <h2 id="test">Test</h2>
94
- <pre><code class="language-bash">npm test # node:test — every test/*.test.ts
107
+ <div class="ctx-nav"><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><button type="button" class="xall" hidden>Expand all</button></div>
108
+ <div class="ctx-preamble 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>
109
+ <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
110
+ <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
111
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
112
+ npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
95
113
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
96
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
97
115
  npm run version:check # every version-bearing spot agrees with package.json
98
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
99
- <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
100
- <h2 id="layout">Layout</h2>
101
- <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>
102
- <h2 id="conventions">Conventions</h2>
103
- <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>
104
- <h2 id="the-invariant">The invariant</h2>
105
- <p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
106
- <h2 id="safety">Safety</h2>
107
- <ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
108
- <h2 id="definition-of-done">Definition of done</h2>
109
- <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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
110
- <h2 id="authoring-this-file">Authoring this file</h2>
111
- <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>
117
+ <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><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></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><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></div></details><details class="ctx-section" id="the-invariant"><summary>The invariant</summary><div class="md"><p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p></div></details><details class="ctx-section" id="safety"><summary>Safety</summary><div class="md"><ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul></div></details><details class="ctx-section" id="definition-of-done"><summary>Definition of done</summary><div class="md"><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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><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></details></div>
112
118
  </section>
113
119
  <section>
114
120
  <p class="label">Memory — 4 facts</p>
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
124
130
  </section>
125
131
  <div class="foot">mcp-context-card · context card</div>
126
132
  </main>
133
+ <script>
134
+ (function(){
135
+ var btn=document.querySelector(".xall");
136
+ var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
137
+ if(!btn||!secs.length)return;
138
+ var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
139
+ btn.hidden=false;
140
+ btn.addEventListener("click",function(){
141
+ var open=!secs.every(function(d){return d.open});
142
+ secs.forEach(function(d){d.open=open});sync();
143
+ });
144
+ secs.forEach(function(d){d.addEventListener("toggle",sync)});
145
+ var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
146
+ addEventListener("hashchange",openHash);openHash();
147
+ var pre=[];
148
+ addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
149
+ addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
150
+ sync();
151
+ })();
152
+ </script>
127
153
  </body>
128
154
  </html>
package/docs/index.html CHANGED
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
30
30
  font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
31
31
  padding:40px 18px}
32
32
  .card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
33
- border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
33
+ border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
34
34
  .card>*{padding:26px 30px}
35
35
  .top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
36
36
  h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
41
41
  section:last-child{border-bottom:0}
42
42
  .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
43
43
  color:var(--accent);margin:0 0 14px}
44
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
44
+ .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
45
45
  .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
46
46
  .toc a:hover{color:var(--accent)}
47
+ /* ── collapsible context ─────────────────────────────────────────── */
48
+ .ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
49
+ margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
50
+ display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
51
+ .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
52
+ white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
53
+ background:var(--chip);color:var(--muted);cursor:pointer}
54
+ .xall:hover{color:var(--accent);border-color:var(--accent)}
55
+ .ctx-preamble{padding-bottom:4px}
56
+ details.ctx-section{border-top:1px solid var(--line)}
57
+ details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
58
+ font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
59
+ details.ctx-section>summary::-webkit-details-marker{display:none}
60
+ details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
61
+ transition:transform .15s ease}
62
+ details.ctx-section[open]>summary::before{transform:rotate(90deg)}
63
+ details.ctx-section>.md{padding:0 0 16px}
64
+ @media print{
65
+ .ctx-nav{display:none}
66
+ details.ctx-section:not([open])>.md{display:block!important}
67
+ details.ctx-section>summary::before{content:""}
68
+ }
47
69
  .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
48
70
  .md h1{font-size:1.15rem}
49
71
  .md p{margin:8px 0}
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
78
100
  <main class="card">
79
101
  <div class="top">
80
102
  <h1>mcp-context-card</h1>
81
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.0.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
103
+ <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
82
104
  </div>
83
105
  <section>
84
106
  <p class="label">Context — AGENTS.md</p>
85
- <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>
86
- <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
87
- <h2 id="setup">Setup</h2>
88
- <pre><code class="language-bash">npm ci</code></pre>
89
- <p>Node 22 or newer. No other system dependencies.</p>
90
- <h2 id="build">Build</h2>
91
- <pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
92
- npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
93
- <h2 id="test">Test</h2>
94
- <pre><code class="language-bash">npm test # node:test — every test/*.test.ts
107
+ <div class="ctx-nav"><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><button type="button" class="xall" hidden>Expand all</button></div>
108
+ <div class="ctx-preamble 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>
109
+ <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
110
+ <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
111
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
112
+ npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
95
113
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
96
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
97
115
  npm run version:check # every version-bearing spot agrees with package.json
98
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
99
- <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
100
- <h2 id="layout">Layout</h2>
101
- <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>
102
- <h2 id="conventions">Conventions</h2>
103
- <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>
104
- <h2 id="the-invariant">The invariant</h2>
105
- <p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
106
- <h2 id="safety">Safety</h2>
107
- <ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
108
- <h2 id="definition-of-done">Definition of done</h2>
109
- <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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
110
- <h2 id="authoring-this-file">Authoring this file</h2>
111
- <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>
117
+ <p>CI runs <code>version:check → faf:check → 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>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><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></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><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></div></details><details class="ctx-section" id="the-invariant"><summary>The invariant</summary><div class="md"><p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p></div></details><details class="ctx-section" id="safety"><summary>Safety</summary><div class="md"><ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul></div></details><details class="ctx-section" id="definition-of-done"><summary>Definition of done</summary><div class="md"><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>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><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></details></div>
112
118
  </section>
113
119
  <section>
114
120
  <p class="label">Memory — 4 facts</p>
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
124
130
  </section>
125
131
  <div class="foot">mcp-context-card · context card</div>
126
132
  </main>
133
+ <script>
134
+ (function(){
135
+ var btn=document.querySelector(".xall");
136
+ var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
137
+ if(!btn||!secs.length)return;
138
+ var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
139
+ btn.hidden=false;
140
+ btn.addEventListener("click",function(){
141
+ var open=!secs.every(function(d){return d.open});
142
+ secs.forEach(function(d){d.open=open});sync();
143
+ });
144
+ secs.forEach(function(d){d.addEventListener("toggle",sync)});
145
+ var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
146
+ addEventListener("hashchange",openHash);openHash();
147
+ var pre=[];
148
+ addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
149
+ addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
150
+ sync();
151
+ })();
152
+ </script>
127
153
  </body>
128
154
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-context-card",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "mcpName": "io.github.Wolfe-Jam/mcp-context-card",
5
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": [
@@ -28,7 +28,7 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "engines": {
31
- "node": ">=22"
31
+ "node": ">=20"
32
32
  },
33
33
  "files": [
34
34
  "dist",
@@ -46,9 +46,10 @@
46
46
  "build": "tsc -p tsconfig.build.json",
47
47
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
48
48
  "version:check": "node scripts/check-versions.mjs",
49
+ "engines:check": "node scripts/check-engines.mjs",
49
50
  "faf:check": "node scripts/check-faf-consistency.mjs",
50
51
  "faf:nudge": "node scripts/faf-drift-nudge.mjs",
51
- "prepublishOnly": "npm run clean && npm run version:check && npm run faf:check && npm run build && npm run typecheck && npm test",
52
+ "prepublishOnly": "npm run clean && npm run version:check && npm run engines:check && npm run faf:check && npm run build && npm run typecheck && npm test",
52
53
  "start": "node dist/bin.js",
53
54
  "start:http": "node dist/bin.js --http",
54
55
  "dev": "tsx src/bin.ts",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.Wolfe-Jam/mcp-context-card",
4
4
  "title": "mcp-context-card",
5
5
  "description": "MCP server for a project's context (AGENTS.md), memory, and identity — base or drop-in extension.",
6
- "version": "1.0.0",
6
+ "version": "1.1.0",
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": "1.0.0",
16
+ "version": "1.1.0",
17
17
  "runtimeHint": "npx",
18
18
  "transport": {
19
19
  "type": "stdio"