mcp-context-card 1.1.1 → 1.3.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.1.1"
12
+ version: "1.3.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/AGENTS.md CHANGED
@@ -45,7 +45,7 @@ code's shape moved without `project.faf`) on Linux.
45
45
 
46
46
  | Path | What |
47
47
  |---|---|
48
- | `src/server.ts` | the MCP server — the nine tools + the Server Card resource |
48
+ | `src/server.ts` | the MCP server — the ten tools + the Server Card and card resources |
49
49
  | `src/agents-md.ts` | reads and section-splits this file |
50
50
  | `src/author.ts` | `author_agents_md` — BETTER via `agents-md-facts`, BEST when `project.faf` exists |
51
51
  | `src/md.ts` | a minimal dependency-free Markdown → HTML renderer |
package/CHANGELOG.md CHANGED
@@ -2,6 +2,73 @@
2
2
 
3
3
  All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
4
4
 
5
+ ## 1.3.0
6
+
7
+ Your project, with nothing to configure.
8
+
9
+ - **Finds your project from the host.** With no `MCP_CONTEXT_CARD_ROOT`, a
10
+ local (stdio) server asks the host which project you're in, through MCP
11
+ roots (goose sends its session's working directory), and follows it when
12
+ it changes. It falls back to the directory it was started in if that has
13
+ an `AGENTS.md`, then to its own folder, as before. An explicit
14
+ `MCP_CONTEXT_CARD_ROOT` always wins; HTTP is unchanged.
15
+ - **`list_context_sources`** reports `project: { path, from }`: which
16
+ project the server is reading, and how it found it.
17
+ - **`save_context_card`** opens its reply with what it did, as a plain fact:
18
+ `New file:` (with one line on what the file is) or `Updated:`, and the
19
+ path.
20
+ - **An empty project gets next steps, not dead ends,** on both the HTML and
21
+ the text card: no `AGENTS.md` yet → ask your agent to draft one
22
+ (`author_agents_md`, from the repo's real build and test commands); no
23
+ facts yet → ask it to remember something. The placeholder "MCP context
24
+ card" pill is gone.
25
+ - **A project with no identity file** (no `.well-known/fafa`, no
26
+ `package.json`) is named after its folder on the card, not after this
27
+ server.
28
+
29
+ - **HTML comments in `AGENTS.md` are hidden** on the card, as GitHub hides
30
+ them. `agents-md-facts` marks its managed block with comments, and the
31
+ card showed them as text. Comments inside code stay, as content.
32
+
33
+ No API change. 134 tests, all green.
34
+
35
+ ## 1.2.0
36
+
37
+ The card reaches people in any host: inline where the host supports MCP
38
+ Apps, and as text in the chat plus the full card in the browser everywhere
39
+ else.
40
+
41
+ - **MCP App.** `render_context_card` links a `ui://mcp-context-card/card.html`
42
+ resource (`text/html;profile=mcp-app`). Hosts that support MCP Apps render
43
+ the card inline, and the model gets a one-line summary instead of the
44
+ whole HTML page. Hosts without MCP Apps get the full HTML, as before.
45
+ - **New tool: `save_context_card`.** Writes the card to `context-card.html`
46
+ in the project and replies with:
47
+ - the card as Markdown: identity, `AGENTS.md` section headings, memory,
48
+ discovery. About 1.2k characters for this repo, instead of about 17k of
49
+ HTML;
50
+ - a link to the full card, plus its `file://` address in a code block,
51
+ which hosts give a copy button (many won't follow a `file://` link).
52
+
53
+ When the server runs locally (stdio), it also opens the saved card in the
54
+ browser; `open: false` skips that, and over HTTP it never opens anything.
55
+ Same `theme`, `accent` and `expanded` inputs as `render_context_card`.
56
+ Marked `destructiveHint: true`, because it replaces an earlier
57
+ `context-card.html`.
58
+ - **A tl;dr by default.** The Markdown shows five facts, each cut to its
59
+ first sentence exactly as stored (or a word-boundary cut marked … when
60
+ that sentence is long), and counts the rest. It stays under about 3k
61
+ characters however much a project remembers. `detail: "full"` lists
62
+ every fact whole. The saved file always has everything.
63
+ - **Server instructions.** Sent at initialize: when the host can't display
64
+ the card, save it and show the user the Markdown card and its link,
65
+ not paste HTML into the chat.
66
+ - **`list_context_sources`** now lists the card resource under
67
+ `surfaces.mcp`.
68
+
69
+ Ten tools now. The nine existing tools keep their names, inputs and
70
+ behaviour. 117 tests, all green.
71
+
5
72
  ## 1.1.1
6
73
 
7
74
  Every tool now says what it is and what it does to your project.
package/README.md CHANGED
@@ -13,6 +13,13 @@ rendered as one card you can read.
13
13
  |---|---|
14
14
  | ![the context card, light theme](./docs/img/card-light.png) | ![the context card, dark theme](./docs/img/card-dark.png) |
15
15
 
16
+ **See your own project's card** — run this in its folder. It writes
17
+ `context-card.html` and opens it in your browser:
18
+
19
+ ```
20
+ npx mcp-context-card card
21
+ ```
22
+
16
23
  **context** — the project's `AGENTS.md`, served whole or one section at a time.
17
24
 
18
25
  ![the card's context section — AGENTS.md, section nav, read_agents_md](./docs/img/card-context.png)
@@ -52,7 +59,7 @@ say what it is. `mcp-context-card` is those three, done once:
52
59
  gains context, memory, and identity discovery it didn't have. Nothing to
53
60
  migrate; it composes.
54
61
 
55
- Nine tools, two discovery surfaces already in the ecosystem (Server Card
62
+ Ten tools, two discovery surfaces already in the ecosystem (Server Card
56
63
  `_meta`, `ai-catalog.json`), and a rendered [card](#the-card). MIT, on npm.
57
64
 
58
65
  It composes:
@@ -63,8 +70,9 @@ It composes:
63
70
 
64
71
  Vendor-free — context is plain Markdown (`AGENTS.md`); the memory and
65
72
  identity formats are swappable examples. It reads and writes only its own
66
- three files (`AGENTS.md`, `project.fafm`, `.well-known/fafa`) — no general
67
- file access, no shell, no search.
73
+ three files (`AGENTS.md`, `project.fafm`, `.well-known/fafa`), plus the
74
+ `context-card.html` it saves on request — no general file access, no shell,
75
+ no search.
68
76
 
69
77
  ## The card
70
78
 
@@ -87,6 +95,18 @@ GET /card # live, on the HTTP transport
87
95
  GET /card?expand=all&theme=light&accent=%230066cc
88
96
  ```
89
97
 
98
+ In a chat, hosts that support [MCP Apps](https://modelcontextprotocol.io/extensions/apps)
99
+ show the card inline when `render_context_card` runs; the model gets a short
100
+ summary instead of the page. Everywhere else, `save_context_card` writes
101
+ `context-card.html` into the project, opens it in your browser when the
102
+ server runs locally, and replies with the card as Markdown (identity, the
103
+ `AGENTS.md` sections, memory, discovery), a link to the full card, and its
104
+ address to copy. The Markdown is a tl;dr by default: five facts, each cut to
105
+ its first sentence as stored, so it stays small however much a project
106
+ remembers. `detail: "full"` lists every fact whole. The server's
107
+ instructions tell the model to show that rather than paste the HTML into
108
+ the chat.
109
+
90
110
  Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
91
111
  This repo's own card, live: [auto](https://wolfe-jam.github.io/mcp-context-card/) ·
92
112
  [light](https://wolfe-jam.github.io/mcp-context-card/card-light.html) ·
@@ -126,22 +146,25 @@ or redirected (`> card.html`, a script, CI) it writes raw HTML to stdout instead
126
146
 
127
147
  ### Wire it into a host
128
148
 
129
- Claude Desktop, Cursor, or any stdio host:
149
+ goose, Claude Desktop, Cursor, or any stdio host:
130
150
 
131
151
  ```jsonc
132
152
  {
133
153
  "mcpServers": {
134
154
  "context-card": {
135
155
  "command": "npx",
136
- "args": ["-y", "mcp-context-card"],
137
- "env": { "MCP_CONTEXT_CARD_ROOT": "/abs/path/to/your/project" }
156
+ "args": ["-y", "mcp-context-card"]
138
157
  }
139
158
  }
140
159
  }
141
160
  ```
142
161
 
143
- `MCP_CONTEXT_CARD_ROOT` points at the directory with your `AGENTS.md`. The
144
- memory tools work with or without it; identity is optional. Over HTTP instead:
162
+ No path to configure: the server asks the host which project you're in (MCP
163
+ roots — goose sends its session's working directory), then falls back to the
164
+ directory it was started in if that has an `AGENTS.md`. `list_context_sources`
165
+ reports which project it picked and how. To pin one project instead, set
166
+ `"env": { "MCP_CONTEXT_CARD_ROOT": "/abs/path/to/your/project" }`; that always
167
+ wins. Identity is optional. Over HTTP instead:
145
168
  `PORT=8080 npx mcp-context-card`. Requires Node ≥20.
146
169
 
147
170
  If `command: "npx"` fails to spawn (`spawn npx ENOENT` — seen on Cursor, whose
@@ -191,15 +214,18 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
191
214
  | `forget` | drop or correct a stale fact |
192
215
  | `whoami` | this server's name, vendor, version, status, license |
193
216
  | `list_context_sources` | what this project publishes, in what media types, via which surface |
194
- | `render_context_card` | the whole card as one self‑contained HTML page (also `GET /card`) |
217
+ | `render_context_card` | the whole card as one self‑contained HTML page (also `GET /card`); hosts that support MCP Apps show it inline |
218
+ | `save_context_card` | write the card to `context-card.html` in the project and open it in your browser; returns the card as Markdown plus a link to the full version |
195
219
 
196
- Seven tools only read. `remember` and `forget` write the memory file, so they're
197
- marked destructive and a host can ask before running them. Every tool carries a
220
+ Seven tools only read. `remember` and `forget` write the memory file, and
221
+ `save_context_card` writes `context-card.html`, so those three are marked
222
+ destructive and a host can ask before running them. Every tool carries a
198
223
  title and MCP tool annotations.
199
224
 
200
225
  ## The demo
201
226
 
202
- `npm run demo` runs every tool over both transports:
227
+ `npm run demo` walks through context, memory, identity and discovery, live,
228
+ over both transports:
203
229
 
204
230
  1. **Context** — list the `AGENTS.md` sections, then pull just `## Test`.
205
231
  2. **Memory** — `remember()` a fact, stop the server process, start a new one,
@@ -209,7 +235,7 @@ title and MCP tool annotations.
209
235
  4. **Discovery** — `list_context_sources()`, then the same server over stateless
210
236
  HTTP with its `.well-known` routes and `GET /card`.
211
237
 
212
- 106 tests on Linux, macOS, and Windows, coverage‑gated in CI. Two spawn a real
238
+ 134 tests on Linux, macOS, and Windows, coverage‑gated in CI. Two spawn a real
213
239
  child process and check a remembered fact survives the restart — one against
214
240
  an existing `project.fafm`, one starting from a project that has never had
215
241
  one; another checks the stdio and HTTP tool surfaces match, and another checks
@@ -219,7 +245,7 @@ every tool's title and behaviour hints against what it actually does.
219
245
 
220
246
  | Path | What |
221
247
  |---|---|
222
- | `src/server.ts` | the nine tools + the Server Card resource |
248
+ | `src/server.ts` | the ten tools + the Server Card and card resources |
223
249
  | `src/agents-md.ts` | reads and section‑splits `AGENTS.md` |
224
250
  | `src/author.ts` | `author_agents_md` — BETTER via [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts), BEST when `project.faf` exists |
225
251
  | `src/md.ts` | a minimal dependency‑free Markdown → HTML renderer |
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.1.1\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";
11
+ export declare const HELP = "mcp-context-card 1.3.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
@@ -121,17 +121,10 @@ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
121
121
  else {
122
122
  const { writeFileSync } = await import("node:fs");
123
123
  const { join } = await import("node:path");
124
- const { spawn } = await import("node:child_process");
124
+ const { openInBrowser } = await import("./open.js");
125
125
  const out = join(process.cwd(), "context-card.html");
126
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();
127
+ openInBrowser(out);
135
128
  process.stderr.write(`${NAME} · wrote ${out} — opening in your browser (--stdout for raw HTML)\n`);
136
129
  }
137
130
  }
@@ -146,6 +139,13 @@ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
146
139
  // stderr so it never touches the JSON-RPC wire on stdout; a bare run at a
147
140
  // terminal otherwise looks hung.
148
141
  console.error(`${NAME} · stdio · waiting for an MCP host on stdin (--help for usage · Ctrl-C to exit)`);
149
- await serve(new StdioServerTransport(), root);
142
+ // stdio = a host on this machine, so save_context_card can open the card.
143
+ // With no MCP_CONTEXT_CARD_ROOT, find the user's project: the host's MCP
144
+ // roots, then the start directory. So a host needs no config to show yours.
145
+ const { openInBrowser } = await import("./open.js");
146
+ await serve(new StdioServerTransport(), root, {
147
+ openFile: openInBrowser,
148
+ detectRoot: !process.env.MCP_CONTEXT_CARD_ROOT,
149
+ });
150
150
  }
151
151
  }
@@ -1,5 +1,11 @@
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.1.1";
4
+ export declare const VERSION = "1.3.0";
5
5
  export declare const SERVER_CARD_URI = "mcp-context-card://server-card";
6
+ /** MCP Apps (io.modelcontextprotocol/ui): the card as an inline UI resource.
7
+ * A host that supports MCP Apps fetches this resource and renders it in a
8
+ * sandboxed iframe next to the conversation. */
9
+ export declare const CARD_UI_URI = "ui://mcp-context-card/card.html";
10
+ export declare const MCP_APP_MIME = "text/html;profile=mcp-app";
11
+ export declare const UI_EXTENSION = "io.modelcontextprotocol/ui";
package/dist/constants.js CHANGED
@@ -1,5 +1,11 @@
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.1.1";
4
+ export const VERSION = "1.3.0";
5
5
  export const SERVER_CARD_URI = "mcp-context-card://server-card";
6
+ /** MCP Apps (io.modelcontextprotocol/ui): the card as an inline UI resource.
7
+ * A host that supports MCP Apps fetches this resource and renders it in a
8
+ * sandboxed iframe next to the conversation. */
9
+ export const CARD_UI_URI = "ui://mcp-context-card/card.html";
10
+ export const MCP_APP_MIME = "text/html;profile=mcp-app";
11
+ export const UI_EXTENSION = "io.modelcontextprotocol/ui";
package/dist/md.js CHANGED
@@ -58,8 +58,70 @@ const TABLE_SEP = /^\s*\|?[\s:|-]*-[\s:|-]*\|?\s*$/;
58
58
  function tableRow(line) {
59
59
  return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
60
60
  }
61
+ /**
62
+ * Drop HTML comments, as GitHub does when it renders Markdown: tools such as
63
+ * agents-md-facts mark their managed blocks with them. A comment may span
64
+ * lines. Inside a fenced block or an inline `code` span it's content, so kept.
65
+ */
66
+ function stripComments(src) {
67
+ const out = [];
68
+ let inFence = null;
69
+ let inComment = false;
70
+ for (const line of src.split("\n")) {
71
+ if (inFence) {
72
+ out.push(line);
73
+ if (inFence.test(line))
74
+ inFence = null;
75
+ continue;
76
+ }
77
+ const fence = !inComment && line.match(FENCE);
78
+ if (fence) {
79
+ inFence = fence[2][0] === "`" ? /^\s*```+\s*$/ : /^\s*~~~+\s*$/;
80
+ out.push(line);
81
+ continue;
82
+ }
83
+ // outside code: split on inline code spans, strip comments only between them
84
+ let kept = "";
85
+ const parts = line.split(/(`+[^`]*`+)/);
86
+ for (let k = 0; k < parts.length; k++) {
87
+ let part = parts[k];
88
+ if (k % 2 === 1 && !inComment) {
89
+ kept += part;
90
+ continue;
91
+ }
92
+ while (part.length) {
93
+ if (inComment) {
94
+ const end = part.indexOf("-->");
95
+ if (end < 0) {
96
+ part = "";
97
+ }
98
+ else {
99
+ part = part.slice(end + 3);
100
+ inComment = false;
101
+ }
102
+ }
103
+ else {
104
+ const start = part.indexOf("<!--");
105
+ if (start < 0) {
106
+ kept += part;
107
+ part = "";
108
+ }
109
+ else {
110
+ kept += part.slice(0, start);
111
+ part = part.slice(start + 4);
112
+ inComment = true;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ // a line that held only a comment disappears, rather than leaving a blank gap
118
+ if (kept.trim() || !line.includes("<!--") && !line.includes("-->"))
119
+ out.push(kept);
120
+ }
121
+ return out.join("\n");
122
+ }
61
123
  export function renderMarkdown(src) {
62
- const lines = src.replace(/\r\n/g, "\n").split("\n");
124
+ const lines = stripComments(src.replace(/\r\n/g, "\n")).split("\n");
63
125
  const out = [];
64
126
  let i = 0;
65
127
  const flushPara = (buf) => {
package/dist/open.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function openInBrowser(path: string): void;
package/dist/open.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Open a local file in the default browser — what `mcp-context-card card`
3
+ * does at a terminal, and what save_context_card does when the server runs
4
+ * locally over stdio. Fire and forget: no display (SSH, CI) just means
5
+ * nothing opens, never an error.
6
+ */
7
+ import { spawn } from "node:child_process";
8
+ export function openInBrowser(path) {
9
+ const [cmd, args] = process.platform === "darwin"
10
+ ? ["open", [path]]
11
+ : process.platform === "win32"
12
+ ? ["cmd", ["/c", "start", "", path]]
13
+ : ["xdg-open", [path]];
14
+ spawn(cmd, args, { stdio: "ignore", detached: true })
15
+ .on("error", () => { })
16
+ .unref();
17
+ }
@@ -14,3 +14,24 @@ export interface CardOptions {
14
14
  export declare const AAIF_ACCENT = "#FF702D";
15
15
  export declare function safeAccent(a?: string): string;
16
16
  export declare function renderCard(root: string, opts?: CardOptions): string;
17
+ /** tl;dr: the first few facts, each cut to about a line. `full`: every fact, whole. */
18
+ export type Detail = "tldr" | "full";
19
+ /**
20
+ * Shorten a fact for the tl;dr without rewording it. The whole first sentence
21
+ * when it fits in `max` (a stored sentence, verbatim, so a model has no ragged
22
+ * end to "tidy"); otherwise a word-boundary cut marked with …. A dot inside a
23
+ * word (AGENTS.md, v1.2) is not a sentence end: it must be followed by space.
24
+ */
25
+ export declare function clip(s: string, max: number): string;
26
+ /**
27
+ * The same card as Markdown, for chats that can't display HTML: identity,
28
+ * the AGENTS.md section headings (bodies stay in the full card), memory,
29
+ * and the discovery table. Same sources as renderCard.
30
+ *
31
+ * The default tl;dr stays small however much memory a project holds: five
32
+ * facts, each cut short, and a count of the rest. `detail: "full"` lists
33
+ * every fact whole. The saved HTML card always has everything.
34
+ */
35
+ export declare function renderCardText(root: string, opts?: {
36
+ detail?: Detail;
37
+ }): string;
@@ -10,11 +10,11 @@
10
10
  * is the expand-all / print helper (TOGGLE_SCRIPT) — a progressive enhancement;
11
11
  * every section still opens on its own without it. Renders anywhere.
12
12
  */
13
- import { join } from "node:path";
13
+ import { basename, join, resolve } from "node:path";
14
14
  import { parseAgentsMd } from "./agents-md.js";
15
15
  import { parseFafm } from "./memory.js";
16
16
  import { resolveIdentity, serverCardMeta, META_NS } from "./identity.js";
17
- import { NAME, SERVER_CARD_URI } from "./constants.js";
17
+ import { SERVER_CARD_URI } from "./constants.js";
18
18
  import { escapeHtml, renderInline, renderMarkdown, slug } from "./md.js";
19
19
  /** AAIF brand orange (aaif.io). The default accent. */
20
20
  export const AAIF_ACCENT = "#FF702D";
@@ -121,7 +121,7 @@ export function renderCard(root, opts = {}) {
121
121
  const mem = parseFafm(join(root, "project.fafm"));
122
122
  const id = resolveIdentity(root);
123
123
  const meta = serverCardMeta();
124
- const name = id?.displayName ?? id?.name ?? NAME;
124
+ const name = id?.displayName ?? id?.name ?? basename(resolve(root));
125
125
  const pills = [
126
126
  id?.vendor && id.vendor !== id.status && `<span class="pill">${escapeHtml(id.vendor)}</span>`,
127
127
  id?.agentVersion && `<span class="pill">v${escapeHtml(id.agentVersion)}</span>`,
@@ -152,7 +152,7 @@ export function renderCard(root, opts = {}) {
152
152
  : ""}</div>
153
153
  ${preamble ? `<div class="ctx-preamble md">${renderMarkdown(preamble)}</div>` : ""}
154
154
  <div class="ctx-body">${sections}</div>`
155
- : `<p class="none">No AGENTS.md in this project.</p>`;
155
+ : `<p class="none">No AGENTS.md yet. Ask your agent to draft one: <code>author_agents_md</code> builds it from this repo's real build and test commands, nothing invented.</p>`;
156
156
  // MEMORY
157
157
  const memoryBody = mem.facts.length
158
158
  ? mem.facts
@@ -164,7 +164,7 @@ export function renderCard(root, opts = {}) {
164
164
  return `<div class="fact"><p>${renderInline(f.text)}</p><div class="meta">${tags}<span class="dot${verified ? "" : " pending"}" title="${verified ? "verified" : f.verification_status ?? "unverified"}"></span></div></div>`;
165
165
  })
166
166
  .join("")
167
- : `<p class="none">No facts yet.</p>`;
167
+ : `<p class="none">No facts yet. Ask your agent to remember something, and it lands here.</p>`;
168
168
  // DISCOVERY
169
169
  const rows = Object.entries(meta)
170
170
  .map(([k, v]) => {
@@ -184,7 +184,7 @@ export function renderCard(root, opts = {}) {
184
184
  <main class="card">
185
185
  <div class="top">
186
186
  <h1>${escapeHtml(name)}</h1>
187
- <div class="pills">${pills || '<span class="pill">MCP context card</span>'}</div>
187
+ ${pills ? `<div class="pills">${pills}</div>` : ""}
188
188
  </div>
189
189
  <section>
190
190
  <p class="label">Context — AGENTS.md</p>
@@ -236,3 +236,64 @@ const TOGGLE_SCRIPT = `<script>
236
236
  sync();
237
237
  })();
238
238
  </script>`;
239
+ const TLDR_FACTS = 5;
240
+ const TLDR_CHARS = 160;
241
+ /**
242
+ * Shorten a fact for the tl;dr without rewording it. The whole first sentence
243
+ * when it fits in `max` (a stored sentence, verbatim, so a model has no ragged
244
+ * end to "tidy"); otherwise a word-boundary cut marked with …. A dot inside a
245
+ * word (AGENTS.md, v1.2) is not a sentence end: it must be followed by space.
246
+ */
247
+ export function clip(s, max) {
248
+ if (s.length <= max)
249
+ return s;
250
+ const first = /^(.+?[.!?])(?=\s)/.exec(s)?.[1];
251
+ if (first && first.length <= max)
252
+ return first;
253
+ const cut = s.slice(0, max);
254
+ const space = cut.lastIndexOf(" ");
255
+ return `${(space > max / 2 ? cut.slice(0, space) : cut).replace(/[\s,;:.—-]+$/, "")}…`;
256
+ }
257
+ /**
258
+ * The same card as Markdown, for chats that can't display HTML: identity,
259
+ * the AGENTS.md section headings (bodies stay in the full card), memory,
260
+ * and the discovery table. Same sources as renderCard.
261
+ *
262
+ * The default tl;dr stays small however much memory a project holds: five
263
+ * facts, each cut short, and a count of the rest. `detail: "full"` lists
264
+ * every fact whole. The saved HTML card always has everything.
265
+ */
266
+ export function renderCardText(root, opts = {}) {
267
+ const agents = parseAgentsMd(join(root, "AGENTS.md"));
268
+ const mem = parseFafm(join(root, "project.fafm"));
269
+ const id = resolveIdentity(root);
270
+ const meta = serverCardMeta();
271
+ const name = id?.displayName ?? id?.name ?? basename(resolve(root));
272
+ const plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
273
+ const out = [`### ${name} — context card`];
274
+ const pills = [
275
+ id?.vendor && id.vendor !== id.status ? id.vendor : null,
276
+ id?.agentVersion ? `v${id.agentVersion}` : null,
277
+ id?.status,
278
+ id?.license,
279
+ ].filter(Boolean);
280
+ if (pills.length)
281
+ out.push(pills.join(" · "));
282
+ if (id?.description)
283
+ out.push(id.description);
284
+ const sections = agents?.sections.filter((s) => s.level > 1) ?? [];
285
+ out.push(agents
286
+ ? `**Context — AGENTS.md** · ${plural(sections.length, "section")}\n${sections.map((s) => s.heading).join(" · ")}`
287
+ : "**Context — AGENTS.md** · none yet. `author_agents_md` drafts one from this repo's real build and test commands, nothing invented.");
288
+ const full = opts.detail === "full";
289
+ const shown = full ? mem.facts : mem.facts.slice(0, TLDR_FACTS);
290
+ const rest = mem.facts.length - shown.length;
291
+ out.push(mem.facts.length
292
+ ? `**Memory** · ${plural(mem.facts.length, "fact")}\n${shown
293
+ .map((f) => `- ${full ? f.text : clip(f.text, TLDR_CHARS)}${f.verification_status === "verified" ? " ✓" : ""}`)
294
+ .join("\n")}${rest ? `\n\n…and ${plural(rest, "more fact")}, in the full card` : ""}`
295
+ : "**Memory** · no facts yet. Ask your agent to remember something, and it lands here.");
296
+ const rows = Object.entries(meta).map(([k, v]) => `| ${k.slice(META_NS.length + 1)} | \`${v.source}\` | \`${v.mediaType}\` |`);
297
+ out.push(["**Discovery**", "| concern | source | media type |", "|---|---|---|", ...rows].join("\n"));
298
+ return out.join("\n\n");
299
+ }
package/dist/server.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
6
6
  * memory — remember · recall · forget (a .fafm file)
7
7
  * identity — whoami (this server's .fafa)
8
- * discovery — list_context_sources · render_context_card (what's published, and how)
8
+ * discovery — list_context_sources · render_context_card · save_context_card (what's published, and how)
9
9
  *
10
10
  * ...exposed through the two mechanisms already in the ecosystem:
11
11
  *
@@ -46,11 +46,20 @@ export declare function serverCard(): {
46
46
  };
47
47
  };
48
48
  };
49
- /**
50
- * @param root directory holding `AGENTS.md`, `project.fafm`, `.well-known/`.
51
- * Defaults to the package root; a deploy points `MCP_CONTEXT_CARD_ROOT`
52
- * at a real project, a test points it at a fixture.
53
- */
54
- export declare function createServer(root?: string): Server;
49
+ /** Sent to every client at initialize. Hosts that support MCP Apps show the
50
+ * card inline; for the rest, this steers the model to save the card as a
51
+ * file instead of pasting a whole HTML page into the chat. */
52
+ export declare const INSTRUCTIONS: string;
53
+ export interface ServerOptions {
54
+ /** Open a saved file for the person. Set only for a local (stdio) server;
55
+ * over HTTP the browser would open on the server, so it stays unset. */
56
+ openFile?: (path: string) => void;
57
+ /** No root was configured: find the user's project instead — the client's
58
+ * MCP roots, then `cwd` if it holds an AGENTS.md, then `root`. Local only. */
59
+ detectRoot?: boolean;
60
+ /** The directory the server was started in (default: process.cwd()). */
61
+ cwd?: string;
62
+ }
63
+ export declare function createServer(root?: string, opts?: ServerOptions): Server;
55
64
  /** Connect a server instance to a transport (stdio or http). */
56
- export declare function serve(transport: Transport, root?: string): Promise<Server>;
65
+ export declare function serve(transport: Transport, root?: string, opts?: ServerOptions): Promise<Server>;
package/dist/server.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
6
6
  * memory — remember · recall · forget (a .fafm file)
7
7
  * identity — whoami (this server's .fafa)
8
- * discovery — list_context_sources · render_context_card (what's published, and how)
8
+ * discovery — list_context_sources · render_context_card · save_context_card (what's published, and how)
9
9
  *
10
10
  * ...exposed through the two mechanisms already in the ecosystem:
11
11
  *
@@ -16,16 +16,17 @@
16
16
  */
17
17
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
18
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
- import { CallToolRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
20
- import { dirname, join } from "node:path";
19
+ import { CallToolRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, RootsListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
20
+ import { existsSync, statSync, writeFileSync } from "node:fs";
21
+ import { basename, dirname, join } from "node:path";
21
22
  import { fileURLToPath, pathToFileURL } from "node:url";
22
23
  import { findSection, parseAgentsMd } from "./agents-md.js";
23
24
  import { authorAgentsMd } from "./author.js";
24
25
  import { forget, parseFafm, recall, remember } from "./memory.js";
25
- import { identity, serverCardMeta, whoami } from "./identity.js";
26
- import { renderCard, safeAccent } from "./render-card.js";
26
+ import { identity, resolveIdentity, serverCardMeta, whoami } from "./identity.js";
27
+ import { renderCard, renderCardText, safeAccent } from "./render-card.js";
27
28
  export { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
28
- import { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
29
+ import { NAME, VERSION, SERVER_CARD_URI, CARD_UI_URI, MCP_APP_MIME, UI_EXTENSION } from "./constants.js";
29
30
  const here = dirname(fileURLToPath(import.meta.url));
30
31
  /** Default package root — `dist/` at runtime, `src/` under tsx. Both are one up. */
31
32
  export const ROOT = join(here, "..");
@@ -39,16 +40,95 @@ export function serverCard() {
39
40
  return { name: NAME, version: VERSION, _meta: serverCardMeta() };
40
41
  }
41
42
  const text = (s) => ({ content: [{ type: "text", text: s }] });
43
+ /** Sent to every client at initialize. Hosts that support MCP Apps show the
44
+ * card inline; for the rest, this steers the model to save the card as a
45
+ * file instead of pasting a whole HTML page into the chat. */
46
+ export const INSTRUCTIONS = "This server publishes a project's context (AGENTS.md), memory (project.fafm) and identity (.well-known/fafa). " +
47
+ "Read them with read_agents_md, recall and whoami; list_context_sources says what is published and where. " +
48
+ "When the user wants to see the context card: hosts that support MCP Apps display it inline from render_context_card. " +
49
+ "Otherwise, don't paste the card's HTML into the conversation. Call save_context_card: it writes context-card.html " +
50
+ "into the project, opens it in the user's browser when this server runs locally, and returns the card as Markdown " +
51
+ "with a link to the saved file. Show the user that Markdown as returned, including the link, so they see the card " +
52
+ "in the chat and can open the full version in a browser.";
53
+ /** Theme / accent / expanded from tool arguments, shared by render and save. */
54
+ function cardOptions(args) {
55
+ const theme = args.theme;
56
+ return {
57
+ theme: (["light", "dark", "auto"].includes(theme) ? theme : "auto"),
58
+ accent: safeAccent(args.accent),
59
+ expanded: args.expanded === true || args.expanded === "true",
60
+ };
61
+ }
62
+ const CARD_ARGS = {
63
+ theme: { type: "string", enum: ["light", "dark", "auto"], description: "default: auto" },
64
+ accent: { type: "string", description: "CSS hex colour, e.g. #FF702D (default: the AAIF palette)" },
65
+ expanded: { type: "boolean", description: "render every AGENTS.md section open (default: collapsed)" },
66
+ };
42
67
  /**
43
68
  * @param root directory holding `AGENTS.md`, `project.fafm`, `.well-known/`.
44
69
  * Defaults to the package root; a deploy points `MCP_CONTEXT_CARD_ROOT`
45
70
  * at a real project, a test points it at a fixture.
46
71
  */
47
- export function createServer(root = ROOT) {
48
- const AGENTS = join(root, "AGENTS.md");
49
- const FAFM = join(root, "project.fafm");
50
- const FAFA = join(root, ".well-known/fafa");
51
- const server = new Server({ name: NAME, version: VERSION }, { capabilities: { tools: {}, resources: {} } });
72
+ /** True when the connected client declared MCP Apps support
73
+ * (capabilities.extensions["io.modelcontextprotocol/ui"].mimeTypes). */
74
+ function hostRendersApps(server) {
75
+ const ext = server.getClientCapabilities()?.extensions?.[UI_EXTENSION];
76
+ return Array.isArray(ext?.mimeTypes) && ext.mimeTypes.includes(MCP_APP_MIME);
77
+ }
78
+ export function createServer(root = ROOT, opts = {}) {
79
+ const server = new Server({ name: NAME, version: VERSION }, { capabilities: { tools: {}, resources: {} }, instructions: INSTRUCTIONS });
80
+ // ── Which project? ────────────────────────────────────────────────────
81
+ // Resolved per call, not at startup: a client's roots are only known once
82
+ // it has connected, and they can change (goose sends its session's working
83
+ // directory, and notifies when it moves).
84
+ let found;
85
+ server.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
86
+ found = undefined;
87
+ });
88
+ const isDir = (p) => {
89
+ try {
90
+ return statSync(p).isDirectory();
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ };
96
+ async function fromClientRoots() {
97
+ if (!server.getClientCapabilities()?.roots)
98
+ return undefined;
99
+ try {
100
+ const { roots } = await server.listRoots(undefined, { timeout: 5000 });
101
+ for (const r of roots) {
102
+ if (!r.uri.startsWith("file:"))
103
+ continue;
104
+ const dir = fileURLToPath(r.uri);
105
+ if (isDir(dir))
106
+ return dir;
107
+ }
108
+ }
109
+ catch {
110
+ // a client that declares roots but doesn't answer: fall through
111
+ }
112
+ return undefined;
113
+ }
114
+ async function project() {
115
+ if (!opts.detectRoot)
116
+ return { root, from: root === ROOT ? "package" : "configured" };
117
+ if (found)
118
+ return found;
119
+ const fromRoots = await fromClientRoots();
120
+ const cwd = opts.cwd ?? process.cwd();
121
+ found = fromRoots
122
+ ? { root: fromRoots, from: "client roots" }
123
+ : existsSync(join(cwd, "AGENTS.md"))
124
+ ? { root: cwd, from: "start directory" }
125
+ : { root, from: "package" };
126
+ return found;
127
+ }
128
+ const files = (dir) => ({
129
+ AGENTS: join(dir, "AGENTS.md"),
130
+ FAFM: join(dir, "project.fafm"),
131
+ });
52
132
  // ── Mechanism 1: the Server Card resource + its _meta context block ───
53
133
  server.setRequestHandler(ListResourcesRequestSchema, async () => ({
54
134
  resources: [
@@ -58,9 +138,23 @@ export function createServer(root = ROOT) {
58
138
  description: "This server's identity + the _meta context block.",
59
139
  mimeType: "application/json",
60
140
  },
141
+ {
142
+ uri: CARD_UI_URI,
143
+ name: "Context Card",
144
+ description: "The context card as an MCP App: identity, AGENTS.md, memory and discovery, rendered inline by hosts that support MCP Apps.",
145
+ mimeType: MCP_APP_MIME,
146
+ },
61
147
  ],
62
148
  }));
63
149
  server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
150
+ if (req.params.uri === CARD_UI_URI) {
151
+ // Rendered at read time from the project's own files. The card is
152
+ // self-contained (inline CSS, no external requests), and its one script
153
+ // is progressive enhancement, so it still works in a strict sandbox.
154
+ return {
155
+ contents: [{ uri: CARD_UI_URI, mimeType: MCP_APP_MIME, text: renderCard((await project()).root, { theme: "auto" }) }],
156
+ };
157
+ }
64
158
  if (req.params.uri !== SERVER_CARD_URI) {
65
159
  throw new Error(`unknown resource: ${req.params.uri}`);
66
160
  }
@@ -178,14 +272,31 @@ export function createServer(root = ROOT) {
178
272
  {
179
273
  name: "render_context_card",
180
274
  title: "Render Context Card",
275
+ // MCP Apps: hosts that support it render the card inline from this
276
+ // resource. Both key forms, as the official ext-apps helper writes them.
277
+ _meta: { ui: { resourceUri: CARD_UI_URI }, "ui/resourceUri": CARD_UI_URI },
181
278
  annotations: { title: "Render Context Card", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
182
279
  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.",
280
+ inputSchema: { type: "object", properties: CARD_ARGS },
281
+ },
282
+ {
283
+ name: "save_context_card",
284
+ title: "Save Context Card",
285
+ annotations: { title: "Save Context Card", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
286
+ description: "Write the context card to context-card.html in the project and, when this server runs locally, open it in the person's browser. Returns the card as Markdown (identity, AGENTS.md sections, memory, discovery) plus a clickable link to the saved file. Use this instead of pasting render_context_card's HTML into a chat that can't display it. Replaces any earlier context-card.html.",
183
287
  inputSchema: {
184
288
  type: "object",
185
289
  properties: {
186
- theme: { type: "string", enum: ["light", "dark", "auto"], description: "default: auto" },
187
- accent: { type: "string", description: "CSS hex colour, e.g. #FF702D (default: the AAIF palette)" },
188
- expanded: { type: "boolean", description: "render every AGENTS.md section open (default: collapsed)" },
290
+ ...CARD_ARGS,
291
+ open: {
292
+ type: "boolean",
293
+ description: "open the saved card in the person's browser when the server runs locally (default: true)",
294
+ },
295
+ detail: {
296
+ type: "string",
297
+ enum: ["tldr", "full"],
298
+ description: "the Markdown reply: tldr (default) shows five facts, each cut short; full shows every fact whole. The saved file always has everything.",
299
+ },
189
300
  },
190
301
  },
191
302
  },
@@ -193,6 +304,8 @@ export function createServer(root = ROOT) {
193
304
  }));
194
305
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
195
306
  const args = (req.params.arguments ?? {});
307
+ const { root, from } = await project();
308
+ const { AGENTS, FAFM } = files(root);
196
309
  switch (req.params.name) {
197
310
  case "read_agents_md": {
198
311
  const doc = parseAgentsMd(AGENTS);
@@ -235,24 +348,45 @@ export function createServer(root = ROOT) {
235
348
  case "whoami":
236
349
  return text(whoami(root));
237
350
  case "render_context_card": {
238
- const rawExpanded = args.expanded;
239
- return {
240
- content: [
241
- {
242
- type: "text",
243
- text: renderCard(root, {
244
- theme: (["light", "dark", "auto"].includes(args.theme) ? args.theme : "auto"),
245
- accent: safeAccent(args.accent),
246
- expanded: rawExpanded === true || rawExpanded === "true",
247
- }),
248
- },
249
- ],
250
- };
351
+ if (hostRendersApps(server)) {
352
+ // The host renders the card itself from CARD_UI_URI, so the model
353
+ // gets a short summary instead of a whole HTML page.
354
+ const doc = parseAgentsMd(AGENTS);
355
+ const mem = parseFafm(FAFM);
356
+ const sections = doc?.sections.length ?? 0;
357
+ const facts = mem.facts.length;
358
+ return text(`Showing the context card for ${resolveIdentity(root)?.name ?? basename(root)}: AGENTS.md with ${sections} section${sections === 1 ? "" : "s"}, ` +
359
+ `${facts} remembered fact${facts === 1 ? "" : "s"}, and this server's identity. ` +
360
+ "The card is displayed to the user; call read_agents_md or recall for the text itself.");
361
+ }
362
+ return text(renderCard(root, cardOptions(args)));
363
+ }
364
+ case "save_context_card": {
365
+ const out = join(root, "context-card.html");
366
+ const existed = existsSync(out);
367
+ writeFileSync(out, renderCard(root, cardOptions(args)));
368
+ // First line, plain fact: models tend to rewrite the end of a reply, not the start.
369
+ const saved = existed
370
+ ? `**Updated:** \`context-card.html\` in your project, at ${out}.`
371
+ : `**New file:** \`context-card.html\` in your project, at ${out}. A snapshot of the context your agent reads.`;
372
+ // Many hosts won't follow a file:// link, so a local server opens it.
373
+ const raw = args.open;
374
+ const opened = !!opts.openFile && raw !== false && raw !== "false";
375
+ if (opened)
376
+ opts.openFile(out);
377
+ return text(`${saved}\n\n` +
378
+ `${renderCardText(root, { detail: args.detail === "full" ? "full" : "tldr" })}\n\n` +
379
+ "_In a host that supports MCP Apps, this card shows inline._\n\n---\n\n" +
380
+ (opened ? "Opened the full card in your browser.\n\n" : "") +
381
+ `**[Open the full card in your browser](${pathToFileURL(out).href})**\n\n` +
382
+ // Some hosts won't follow a file:// link; a code block gets a copy button.
383
+ `Or copy this into your browser's address bar:\n\n\`\`\`\n${pathToFileURL(out).href}\n\`\`\``);
251
384
  }
252
385
  case "list_context_sources": {
253
386
  const doc = parseAgentsMd(AGENTS);
254
387
  const mem = parseFafm(FAFM);
255
388
  return text(JSON.stringify({
389
+ project: { path: root, from },
256
390
  context: {
257
391
  source: "AGENTS.md",
258
392
  mediaType: "text/markdown",
@@ -271,7 +405,10 @@ export function createServer(root = ROOT) {
271
405
  present: identity(root) !== null,
272
406
  },
273
407
  surfaces: {
274
- mcp: { serverCard: `resource ${SERVER_CARD_URI}` },
408
+ mcp: {
409
+ serverCard: `resource ${SERVER_CARD_URI}`,
410
+ card: `resource ${CARD_UI_URI} (MCP App, ${MCP_APP_MIME})`,
411
+ },
275
412
  http: {
276
413
  serverCard: "GET /.well-known/mcp/server-card",
277
414
  aiCatalog: "GET /.well-known/ai-catalog.json",
@@ -287,13 +424,15 @@ export function createServer(root = ROOT) {
287
424
  return server;
288
425
  }
289
426
  /** Connect a server instance to a transport (stdio or http). */
290
- export async function serve(transport, root = ROOT) {
291
- const server = createServer(root);
427
+ export async function serve(transport, root = ROOT, opts = {}) {
428
+ const server = createServer(root, opts);
292
429
  await server.connect(transport);
293
430
  return server;
294
431
  }
295
432
  // Direct run (incl. the demo's spawned child) → stdio. pathToFileURL keeps
296
433
  // this correct on Windows, where argv[1] is a `C:\...` path.
297
434
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
298
- await serve(new StdioServerTransport());
435
+ const { openInBrowser } = await import("./open.js");
436
+ const pinned = process.env.MCP_CONTEXT_CARD_ROOT;
437
+ await serve(new StdioServerTransport(), pinned ?? ROOT, { openFile: openInBrowser, detectRoot: !pinned });
299
438
  }
@@ -29,7 +29,7 @@ Both return:
29
29
  ```jsonc
30
30
  {
31
31
  "name": "mcp-context-card",
32
- "version": "1.1.1",
32
+ "version": "1.3.0",
33
33
  "_meta": {
34
34
  "io.github.Wolfe-Jam.mcp-context-card/context": {
35
35
  "source": "AGENTS.md",
@@ -118,7 +118,9 @@ GET /.well-known/ai-catalog.json
118
118
 
119
119
  The same three sources also render as **the card** — `GET /card` /
120
120
  `render_context_card` / `docs/card.html` — the human view of exactly what a
121
- machine reads below.
121
+ machine reads below. Hosts that support MCP Apps show it inline from the
122
+ `ui://mcp-context-card/card.html` resource; elsewhere `save_context_card`
123
+ writes it to `context-card.html` and returns it as Markdown.
122
124
 
123
125
  The same three sources back **both** discovery mechanisms:
124
126
 
package/docs/WIRING.md CHANGED
@@ -16,15 +16,20 @@
16
16
  "mcpServers": {
17
17
  "context-card": {
18
18
  "command": "npx",
19
- "args": ["-y", "mcp-context-card"],
20
- "env": { "MCP_CONTEXT_CARD_ROOT": "/abs/path/to/your/project" }
19
+ "args": ["-y", "mcp-context-card"]
21
20
  }
22
21
  }
23
22
  }
24
23
  ```
25
24
 
26
- - **`MCP_CONTEXT_CARD_ROOT`** — directory holding `AGENTS.md`, `project.fafm`, and
27
- `.well-known/fafa`. Omit it and the server uses its own bundled copies.
25
+ - **Which project.** Unset, a stdio server finds it per call: the host's first
26
+ MCP root (a `file://` directory), then the start directory if it holds an
27
+ `AGENTS.md`, then the server's own bundled copies. A `roots/list_changed`
28
+ notification makes the next call look again. `list_context_sources` reports
29
+ `project: { path, from }`.
30
+ - **`MCP_CONTEXT_CARD_ROOT`** — pins the project: a directory holding
31
+ `AGENTS.md`, `project.fafm`, and `.well-known/fafa`. Always wins over roots.
32
+ Over HTTP there are no roots, so it's the only way to pick a project there.
28
33
  - `stdout` is the JSON‑RPC wire; logging is on `stderr`.
29
34
  - **`command: "npx"` fails to spawn on some hosts** (`spawn npx ENOENT`) — the
30
35
  host's process spawn doesn't inherit a shell `PATH` that has `npx` on it,
@@ -83,7 +88,8 @@ And to discover what a server offers before committing to it:
83
88
  await client.callTool({ name: "list_context_sources", arguments: {} });
84
89
  // → { context: { source: "AGENTS.md", mediaType: "text/markdown", present: true, sections: 10 },
85
90
  // memory: { … }, identity: { … },
86
- // surfaces: { mcp: { serverCard: "resource mcp-context-card://server-card" },
91
+ // surfaces: { mcp: { serverCard: "resource mcp-context-card://server-card",
92
+ // card: "resource ui://mcp-context-card/card.html (MCP App, text/html;profile=mcp-app)" },
87
93
  // http: { serverCard: "GET /.well-known/mcp/server-card",
88
94
  // aiCatalog: "GET /.well-known/ai-catalog.json",
89
95
  // card: "GET /card" } } }
@@ -100,7 +100,7 @@ details.ctx-section>.md{padding:0 0 16px}
100
100
  <main class="card">
101
101
  <div class="top">
102
102
  <h1>mcp-context-card</h1>
103
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.1</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.3.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
104
104
  </div>
105
105
  <section>
106
106
  <p class="label">Context — AGENTS.md</p>
@@ -114,7 +114,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
114
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
115
115
  npm run version:check # every version-bearing spot agrees with package.json
116
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
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>
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 ten tools + the Server Card and card resources</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>
118
118
  </section>
119
119
  <section>
120
120
  <p class="label">Memory — 4 facts</p>
@@ -100,7 +100,7 @@ details.ctx-section>.md{padding:0 0 16px}
100
100
  <main class="card">
101
101
  <div class="top">
102
102
  <h1>mcp-context-card</h1>
103
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.1</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.3.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
104
104
  </div>
105
105
  <section>
106
106
  <p class="label">Context — AGENTS.md</p>
@@ -114,7 +114,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
114
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
115
115
  npm run version:check # every version-bearing spot agrees with package.json
116
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
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>
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 ten tools + the Server Card and card resources</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>
118
118
  </section>
119
119
  <section>
120
120
  <p class="label">Memory — 4 facts</p>
package/docs/card.html CHANGED
@@ -100,7 +100,7 @@ details.ctx-section>.md{padding:0 0 16px}
100
100
  <main class="card">
101
101
  <div class="top">
102
102
  <h1>mcp-context-card</h1>
103
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.1</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.3.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
104
104
  </div>
105
105
  <section>
106
106
  <p class="label">Context — AGENTS.md</p>
@@ -114,7 +114,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
114
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
115
115
  npm run version:check # every version-bearing spot agrees with package.json
116
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
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>
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 ten tools + the Server Card and card resources</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>
118
118
  </section>
119
119
  <section>
120
120
  <p class="label">Memory — 4 facts</p>
Binary file
Binary file
Binary file
package/docs/index.html CHANGED
@@ -100,7 +100,7 @@ details.ctx-section>.md{padding:0 0 16px}
100
100
  <main class="card">
101
101
  <div class="top">
102
102
  <h1>mcp-context-card</h1>
103
- <div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.1.1</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.3.0</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
104
104
  </div>
105
105
  <section>
106
106
  <p class="label">Context — AGENTS.md</p>
@@ -114,7 +114,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
114
114
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
115
115
  npm run version:check # every version-bearing spot agrees with package.json
116
116
  npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
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>
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 ten tools + the Server Card and card resources</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>
118
118
  </section>
119
119
  <section>
120
120
  <p class="label">Memory — 4 facts</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-context-card",
3
- "version": "1.1.1",
3
+ "version": "1.3.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": [
package/project.faf CHANGED
@@ -20,7 +20,7 @@ stack:
20
20
  tech_stack: [TypeScript, "@modelcontextprotocol/sdk", "agents-md-facts", hono, "@hono/node-server", yaml]
21
21
  human_context:
22
22
  who: MCP host and server implementers who want a project's AGENTS.md, memory, and identity available over MCP without inventing an ad-hoc shape for each.
23
- what: The essential context, memory, and identity components for MCP — usable as a base MCP on its own, or dropped into any existing MCP server as an extension. Nine tools — read_agents_md / list_agents_md_sections / author_agents_md (context), remember / recall / forget (memory), whoami (identity), list_context_sources / render_context_card (discovery) — exposed through the Server Card _meta block and a self-published ai-catalog.json. Dual transport (stdio + stateless Streamable HTTP).
23
+ what: The essential context, memory, and identity components for MCP — usable as a base MCP on its own, or dropped into any existing MCP server as an extension. Ten tools — read_agents_md / list_agents_md_sections / author_agents_md (context), remember / recall / forget (memory), whoami (identity), list_context_sources / render_context_card / save_context_card (discovery) — exposed through the Server Card _meta block and a self-published ai-catalog.json. Dual transport (stdio + stateless Streamable HTTP).
24
24
  why: AGENTS.md is the de-facto standard for agent instructions, but a client has to know the file exists and read it whole. There is no standard way for a server to publish "here is my AGENTS.md, here is what I remember, here is who I am" — every server that wants this grows its own shape, or does without. This does it once, through mechanisms that already exist — as a base MCP, or dropped into what you've already built.
25
25
  where: github.com/Wolfe-Jam/mcp-context-card
26
26
  when: "2026-08-12"
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.1.1",
6
+ "version": "1.3.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.1.1",
16
+ "version": "1.3.0",
17
17
  "runtimeHint": "npx",
18
18
  "transport": {
19
19
  "type": "stdio"