mcp-context-card 1.7.1 → 1.8.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.
@@ -11,7 +11,7 @@
11
11
  "data": {
12
12
  "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
13
13
  "name": "io.github.Wolfe-Jam/mcp-context-card",
14
- "version": "1.7.1",
14
+ "version": "1.8.0",
15
15
  "title": "MCP Context Card",
16
16
  "description": "MCP server for a project's context (AGENTS.md), memory, and identity — base or drop-in extension.",
17
17
  "websiteUrl": "https://github.com/Wolfe-Jam/mcp-context-card",
package/.well-known/fafa CHANGED
@@ -13,7 +13,7 @@ agent:
13
13
  # a deployment for your own project uses your domain.
14
14
  id: "urn:air:faf.one:agent:mcp-context-card"
15
15
  vendor: "io.github.Wolfe-Jam"
16
- version: "1.7.1"
16
+ version: "1.8.0"
17
17
  description: >-
18
18
  The essential MCP components for a project's context (AGENTS.md),
19
19
  cross-session memory, and identity — a base MCP on its own, or a
package/AGENTS.md CHANGED
@@ -20,8 +20,8 @@ Node 22 or newer. No other system dependencies.
20
20
  ## Build
21
21
 
22
22
  ```bash
23
- npm run build # tsc -p tsconfig.build.json → dist/
24
- npm run typecheck # tsc --noEmit over src/ + test/
23
+ npm run build # tsc -p tsconfig.build.json, then copy the bundled card script → dist/
24
+ npm run typecheck # tsc --noEmit over src/ + test/, then the browser script
25
25
  ```
26
26
 
27
27
  ## Test
@@ -50,6 +50,8 @@ code's shape moved without `project.faf`) on Linux.
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 |
52
52
  | `src/render-card.ts` | the card — identity + this file + memory + discovery, as one HTML page |
53
+ | `src/browser/card-app.ts` | the card's MCP Apps script (size, inline view), inlined only into the `ui://` resource |
54
+ | `scripts/bundle-card-app.mjs` | bundles the script so the sandbox loads nothing from the network |
53
55
  | `src/memory.ts` → `src/faf/parse-fafm.ts` | file-backed `remember` / `recall` / `forget` |
54
56
  | `src/identity.ts` | `whoami` (`.fafa` → `package.json` fallback) + the `_meta` context block |
55
57
  | `src/catalog-gen.ts` | writes `.well-known/ai-catalog.json` from the same three sources |
@@ -70,7 +72,7 @@ code's shape moved without `project.faf`) on Linux.
70
72
  the **same three sources**: this file, `project.fafm`, `.well-known/fafa`.
71
73
  Change what one exposes and you must change the others. `npm run catalog:check`
72
74
  and `npm run card:check` enforce it in CI — each regenerates its surface and
73
- fails on any diff.
75
+ fails on any diff. `card:check` also fails if a plain card exceeds 64 KB.
74
76
 
75
77
  ## Safety
76
78
 
package/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
4
4
 
5
+ ## 1.8.0
6
+
7
+ Speaks MCP 2026-07-28 as well as 2025, on the MCP SDK v2, and the card fits a chat panel. Library users: see the breaking note at the end.
8
+
9
+ - **The card tells the host how big it is.** Hosts that support MCP Apps
10
+ read `ui://mcp-context-card/card.html`. That resource is the card plus
11
+ the start-up exchange (`ui/initialize`, then
12
+ `ui/notifications/initialized`) and `ui/notifications/size-changed`
13
+ when the document's size changes. The helper is
14
+ `@modelcontextprotocol/ext-apps` `App` with `autoResize: true`, bundled
15
+ at build time (`scripts/bundle-card-app.mjs`) into that resource only, so
16
+ the sandbox still has no CDN and no external request. The tool text for a
17
+ client without MCP Apps, `save_context_card`, `GET /card`, and the CLI
18
+ are the plain card, without that script. `card:check` fails if a plain
19
+ card exceeds 64 KB. The card still works with the script off.
20
+ `card --stdout` exits 0 when the reader closes the pipe early, and exits
21
+ 1 with a message on any other failed write.
22
+ - **You choose whether the host's card carries the helper.**
23
+ `MCP_CONTEXT_CARD_APP=helper` (the default) or `plain`. `plain` makes the
24
+ `ui://` card the plain card (~30 KB, no MCP Apps messages) for hosts where
25
+ the ~700 KB helper isn't worth it. Only that resource changes.
26
+ `list_context_sources` reports the active value. Any case is read; an
27
+ unknown value warns once on stderr and uses `helper`.
28
+ - **An inline view for chat panels.** Inside an MCP Apps host, display mode
29
+ `inline` or `pip` (`McpUiHostContext.displayMode`) shows a mini card:
30
+ monogram, name, kind · version, one line, and a counts strip (sections ·
31
+ facts · identity). One action, "Open full card", calls
32
+ `requestDisplayMode({ mode: "fullscreen" })` when `availableDisplayModes`
33
+ includes `fullscreen`. The full card shows when the host is fullscreen, or
34
+ when there is no host. A host that stays smaller points to
35
+ `save_context_card`, which writes the full card to `context-card.html`.
36
+ The card declares the display modes it supports (inline, pip,
37
+ fullscreen) when it starts, as the MCP Apps spec requires. The mini card
38
+ is part of the `ui://` resource only, hidden until the host says the
39
+ panel is inline. The plain card does not include it, and the script off
40
+ still shows the full card.
41
+ - **Both protocol eras, both transports.** A client that opens with
42
+ `server/discover` (Claude Code, goose) connects on 2026-07-28; a client
43
+ that opens with `initialize` gets 2025, unchanged. The Server Card lists
44
+ 2026-07-28 first. See [docs/TRANSPORT.md](docs/TRANSPORT.md#protocol-eras).
45
+ - **Roots on 2026-07-28** are asked in-band (`input_required`), once per
46
+ connection, since that revision has no server-to-client requests and no
47
+ `roots/list_changed`. Roots sent with a later call replace the first. A
48
+ client that declares `roots` but can't answer now fails the tool call on
49
+ 2026-07-28; on 2025 it still falls back to the start directory.
50
+ - **Breaking for library users** (the `mcp-context-card/server` export): it
51
+ is built on `@modelcontextprotocol/server` 2.x instead of
52
+ `@modelcontextprotocol/sdk` 1.x. `createServer()` returns a v2 `Server`, so
53
+ `setRequestHandler(SomeRequestSchema, …)` now throws; register by method
54
+ string (`setRequestHandler("prompts/list", …)`). The types come from
55
+ `@modelcontextprotocol/server`, and `zod` 4 comes with it. See the SDK's
56
+ [upgrade guide](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/migration/upgrade-to-v2.md).
57
+ New: `serveStdioServer()` serves stdio on both eras; `serve(transport)` is
58
+ kept and serves 2025. The CLI and the MCP surface are unchanged.
59
+
5
60
  ## 1.7.1
6
61
 
7
62
  The business card printer is now its own package.
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![CI](https://github.com/Wolfe-Jam/mcp-context-card/actions/workflows/ci.yml/badge.svg)](https://github.com/Wolfe-Jam/mcp-context-card/actions/workflows/ci.yml)
5
5
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
6
6
  [![mcp-context-card MCP server](https://glama.ai/mcp/servers/Wolfe-Jam/mcp-context-card/badges/score.svg)](https://glama.ai/mcp/servers/Wolfe-Jam/mcp-context-card)
7
+ [![Business card · Get yours →](https://wolfe-jam.github.io/agent-business-card/badge.svg)](https://wolfe-jam.github.io/agent-business-card/?repo=Wolfe-Jam/mcp-context-card)
7
8
 
8
9
  **Get one. Or add it to yours.** The essential MCP server for a project's
9
10
  context, memory, and identity — discoverable to any MCP client, and
@@ -95,8 +96,22 @@ people: read it, screenshot it, drop it in a PR, put it on a status page.
95
96
 
96
97
  Flip, tabs and the view switch are plain CSS, so they work with scripts off.
97
98
  The one small inline script adds Expand all, opens a `#section` link on the
98
- back, and opens every section for printing. `--expanded` / `?expand=all`
99
- renders both faces flat, every section open, for a screenshot or print.
99
+ back, and opens every section for printing. Hosts that support MCP Apps read
100
+ `ui://mcp-context-card/card.html`: this same page, plus a hidden inline view
101
+ and the helper bundled in (`scripts/bundle-card-app.mjs`), so the host can
102
+ fit its frame. Nothing is loaded from the network. The saved
103
+ `context-card.html`, `GET /card`, and the CLI are the plain page, without
104
+ that helper and without the inline view.
105
+
106
+ In a host, the inline view is a mini card for the panel: monogram, name,
107
+ kind · version, one line, and a strip of counts (sections · facts ·
108
+ identity), with one action, "Open full card". It shows when the host's
109
+ display mode is inline (or picture-in-picture). Fullscreen, and any page
110
+ with no host, is the full card. "Open full card" asks the host for
111
+ fullscreen; a host that stays smaller points to `save_context_card`, which
112
+ writes the full card to `context-card.html`.
113
+ `--expanded` / `?expand=all` renders both faces flat, every section open,
114
+ for a screenshot or print.
100
115
 
101
116
  ```
102
117
  npx mcp-context-card card # at a terminal: writes context-card.html and opens it
@@ -192,6 +207,13 @@ never serves or lists `project.fafm`, unless you set
192
207
  `MCP_CONTEXT_CARD_PUBLISH_MEMORY=1`. Details:
193
208
  [docs/TRANSPORT.md](./docs/TRANSPORT.md#security-local-by-default).
194
209
 
210
+ In a host that shows MCP Apps (goose, for one), the card comes with the
211
+ official MCP Apps helper, so it reports its size and fits its frame (about
212
+ 700 KB, loaded by the host, not the model). For the plain card instead
213
+ (about 30 KB, the host's default frame), set
214
+ `"env": { "MCP_CONTEXT_CARD_APP": "plain" }`. Everywhere else the card is
215
+ plain either way.
216
+
195
217
  If `command: "npx"` fails to spawn (`spawn npx ENOENT` — seen on Cursor, whose
196
218
  host process doesn't inherit a shell `PATH`), point `command` at `node` and
197
219
  the installed `dist/bin.js` instead — see
@@ -274,7 +296,7 @@ over both transports:
274
296
  4. **Discovery** — `list_context_sources()`, then the same server over stateless
275
297
  HTTP with its `.well-known` routes and `GET /card`.
276
298
 
277
- 210 tests on Linux, macOS, and Windows, coverage‑gated in CI.
299
+ 245 tests on Linux, macOS, and Windows, coverage‑gated in CI.
278
300
  `npm run wjttc` runs the WJTTC certification suite (seven tiers, from protocol
279
301
  and Server Card conformance to stdio/HTTP parity and the shipped package). Two spawn a real
280
302
  child process and check a remembered fact survives the restart — one against
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.7.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) --portrait --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 HOST HTTP bind address (default 127.0.0.1, this machine\n only); 0.0.0.0 exposes it, e.g. in a container\n MCP_CONTEXT_CARD_ALLOWED_HOSTS / _ALLOWED_ORIGINS\n comma-separated Host names / browser origins to\n accept besides this machine's own (reverse proxy, web app)\n MCP_CONTEXT_CARD_PUBLISH_MEMORY=1\n HTTP: serve project.fafm, list it in the AI Catalog,\n and show its facts on an exposed /card (off: memory\n is session data). HTTP has no auth\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.8.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) --portrait --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 HOST HTTP bind address (default 127.0.0.1, this machine\n only); 0.0.0.0 exposes it, e.g. in a container\n MCP_CONTEXT_CARD_ALLOWED_HOSTS / _ALLOWED_ORIGINS\n comma-separated Host names / browser origins to\n accept besides this machine's own (reverse proxy, web app)\n MCP_CONTEXT_CARD_PUBLISH_MEMORY=1\n HTTP: serve project.fafm, list it in the AI Catalog,\n and show its facts on an exposed /card (off: memory\n is session data). HTTP has no auth\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
  * The address the HTTP server binds: `HOST`, else 127.0.0.1. Local by default,
14
14
  * as the MCP transports spec recommends; a hosted deploy sets HOST=0.0.0.0.
package/dist/bin.js CHANGED
@@ -20,9 +20,8 @@
20
20
  import { realpathSync } from "node:fs";
21
21
  import { resolve } from "node:path";
22
22
  import { pathToFileURL } from "node:url";
23
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
23
  import { NAME, VERSION } from "./constants.js";
25
- import { ROOT, serve } from "./server.js";
24
+ import { ROOT, serveStdioServer } from "./server.js";
26
25
  /** what a bare `--help` / `help` prints. */
27
26
  export const HELP = `${NAME} ${VERSION}
28
27
  Serve a project's context (AGENTS.md), memory, and identity over MCP.
@@ -133,6 +132,16 @@ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
133
132
  // Piped / redirected (or --stdout) → raw HTML on stdout, unchanged.
134
133
  // A bare run at a terminal → the HTML is noise; write a file and open it.
135
134
  if (!process.stdout.isTTY || argv.includes("--stdout")) {
135
+ // A large project's card can be bigger than a pipe buffer. `head` closes
136
+ // after the first bytes; the rest of the write is EPIPE, which is the
137
+ // reader finishing. Any other error (disk full, bad descriptor) is a
138
+ // failed write: say so and exit 1.
139
+ process.stdout.on("error", (err) => {
140
+ if (err.code === "EPIPE")
141
+ process.exit(0);
142
+ process.stderr.write(`${NAME} · card --stdout: ${err.message}\n`);
143
+ process.exit(1);
144
+ });
136
145
  process.stdout.write(html);
137
146
  }
138
147
  else {
@@ -168,7 +177,7 @@ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
168
177
  // With no MCP_CONTEXT_CARD_ROOT, find the user's project: the host's MCP
169
178
  // roots, then the start directory. So a host needs no config to show yours.
170
179
  const { openInBrowser } = await import("./open.js");
171
- await serve(new StdioServerTransport(), root, {
180
+ serveStdioServer(root, {
172
181
  openFile: openInBrowser,
173
182
  detectRoot: !process.env.MCP_CONTEXT_CARD_ROOT,
174
183
  });