mcp-context-card 1.6.1 → 1.7.1

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.6.1",
14
+ "version": "1.7.1",
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.6.1"
16
+ version: "1.7.1"
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
@@ -23,6 +23,8 @@ agent:
23
23
  license: "MIT"
24
24
  metadata:
25
25
  cards:
26
+ # The card's colour: AAIF orange. Without one, a card is drawn in ink.
27
+ accent: "#FF702D"
26
28
  packages:
27
29
  - registryType: "npm"
28
30
  identifier: "mcp-context-card"
package/AGENTS.md CHANGED
@@ -15,7 +15,7 @@ connection.
15
15
  npm ci
16
16
  ```
17
17
 
18
- Node 20 or newer. No other system dependencies.
18
+ Node 22 or newer. No other system dependencies.
19
19
 
20
20
  ## Build
21
21
 
package/CHANGELOG.md CHANGED
@@ -2,6 +2,42 @@
2
2
 
3
3
  All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
4
4
 
5
+ ## 1.7.1
6
+
7
+ The business card printer is now its own package.
8
+
9
+ - [agent-business-card](https://www.npmjs.com/package/agent-business-card)
10
+ renders the business card and prints it to screen. It is a new
11
+ dependency. Printing a business card no longer needs an MCP server: the
12
+ renderer has no dependencies and runs in the browser, so any page or tool
13
+ can print the same business card from its own facts (an A2A Agent Card,
14
+ an MCP Server Card, a `.fafa`). mcp-context-card is one reader that
15
+ supplies them.
16
+ - Same code, moved unchanged. The business cards are byte-identical to
17
+ 1.7.0.
18
+ - `renderBusinessCard`, `cardInitials`, `safeAccent` and the `BusinessCard`
19
+ types are still exported from `render-card`, so nothing changes for
20
+ callers.
21
+
22
+ ## 1.7.0
23
+
24
+ A card's colour is the owner's.
25
+
26
+ - **No colour declared = ink.** A card is drawn in its own ink, black on a
27
+ light card and white on a dark one, unless a colour is declared. Nothing
28
+ is guessed. The monogram's letter takes the card colour, so it stays
29
+ readable. Before, every card defaulted to the AAIF orange.
30
+ - **The owner declares it in the `.fafa`:** `metadata.cards.accent: "#0066cc"`.
31
+ A colour passed in (`--accent`, `?accent`, the tools' `accent`) still
32
+ wins.
33
+ - A bad value, passed or declared, is dropped and the card falls back to
34
+ ink. `safeAccent` now returns `undefined` for anything that isn't a hex
35
+ (it used to return the AAIF orange).
36
+ - This project's own `.fafa` declares the AAIF orange, so its card looks
37
+ the same.
38
+ - Docs: Node 22 or newer (README and AGENTS.md said 20; `engines` has
39
+ required `>=22`).
40
+
5
41
  ## 1.6.1
6
42
 
7
43
  The logo is the first letter.
package/README.md CHANGED
@@ -119,11 +119,14 @@ remembers. `detail: "full"` lists every fact whole. The server's
119
119
  instructions tell the model to show that rather than paste the HTML into
120
120
  the chat.
121
121
 
122
- Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
122
+ Light, dark, or auto. The colour is the owner's: set it in the project's
123
+ `.fafa` (`metadata.cards.accent: "#0066cc"`), or pass any hex with `--accent`
124
+ or `?accent`. With none, the card is drawn in ink, black or white; no colour
125
+ is guessed.
123
126
  This repo's own card, live: [auto](https://wolfe-jam.github.io/mcp-context-card/) ·
124
127
  [light](https://wolfe-jam.github.io/mcp-context-card/card-light.html) ·
125
128
  [dark](https://wolfe-jam.github.io/mcp-context-card/card-dark.html)
126
- (all in the AAIF accent shown here — pass any hex to change it).
129
+ (in the AAIF orange its `.fafa` declares).
127
130
 
128
131
  ## Add it to your setup
129
132
 
@@ -177,7 +180,7 @@ directory it was started in if that has an `AGENTS.md`. `list_context_sources`
177
180
  reports which project it picked and how. To pin one project instead, set
178
181
  `"env": { "MCP_CONTEXT_CARD_ROOT": "/abs/path/to/your/project" }`; that always
179
182
  wins. Identity is optional. Over HTTP instead:
180
- `PORT=8080 npx mcp-context-card`. Requires Node ≥20.
183
+ `PORT=8080 npx mcp-context-card`. Requires Node ≥22.
181
184
 
182
185
  HTTP mode is local by default, as the MCP transports spec asks: it binds
183
186
  `127.0.0.1`, refuses foreign browser origins with 403, and refuses DNS names
@@ -271,7 +274,7 @@ over both transports:
271
274
  4. **Discovery** — `list_context_sources()`, then the same server over stateless
272
275
  HTTP with its `.well-known` routes and `GET /card`.
273
276
 
274
- 209 tests on Linux, macOS, and Windows, coverage‑gated in CI.
277
+ 210 tests on Linux, macOS, and Windows, coverage‑gated in CI.
275
278
  `npm run wjttc` runs the WJTTC certification suite (seven tiers, from protocol
276
279
  and Server Card conformance to stdio/HTTP parity and the shipped package). Two spawn a real
277
280
  child process and check a remembered fact survives the restart — one against
@@ -289,7 +292,7 @@ transport security against the specs, one MUST or SHOULD at a time.
289
292
  | `src/agents-md.ts` | reads and section‑splits `AGENTS.md` |
290
293
  | `src/author.ts` | `author_agents_md` — BETTER via [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts), BEST when `project.faf` exists |
291
294
  | `src/md.ts` | a minimal dependency‑free Markdown → HTML renderer |
292
- | `src/render-card.ts` | the card — identity + `AGENTS.md` + memory + discovery, as one HTML page |
295
+ | `src/render-card.ts` | the card — reads identity + `AGENTS.md` + memory + discovery into a card; [`agent-business-card`](https://github.com/Wolfe-Jam/agent-business-card) draws it as one HTML page |
293
296
  | `src/memory.ts` | file‑backed `remember` / `recall` / `forget` |
294
297
  | `src/identity.ts` | `whoami` (`.fafa` → `package.json` fallback) + the `_meta` block |
295
298
  | `src/server-card.ts` | the MCP Server Card (SEP-2127, schema v1) |
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.6.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.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";
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.
@@ -1,7 +1,7 @@
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.6.1";
4
+ export declare const VERSION = "1.7.1";
5
5
  export declare const SERVER_CARD_URI = "mcp-context-card://server-card";
6
6
  /** The server's registry identity: reverse-DNS, the same as server.json `name`.
7
7
  * It is also `serverInfo.name`, so a Server Card never contradicts the live
package/dist/constants.js CHANGED
@@ -1,7 +1,7 @@
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.6.1";
4
+ export const VERSION = "1.7.1";
5
5
  export const SERVER_CARD_URI = "mcp-context-card://server-card";
6
6
  /** The server's registry identity: reverse-DNS, the same as server.json `name`.
7
7
  * It is also `serverInfo.name`, so a Server Card never contradicts the live
@@ -50,5 +50,6 @@ function extras(doc) {
50
50
  ...(endpoints.length ? { endpoints } : {}),
51
51
  ...(skills.length ? { skills } : {}),
52
52
  ...(packages.length ? { packages } : {}),
53
+ ...(typeof cards.accent === "string" && cards.accent.trim() ? { accent: cards.accent.trim() } : {}),
53
54
  };
54
55
  }
@@ -48,4 +48,6 @@ export interface AgentIdentity {
48
48
  registryType: string;
49
49
  identifier: string;
50
50
  }[];
51
+ /** The owner's card colour (`.fafa` `metadata.cards.accent`), a hex. Validated when drawn. */
52
+ accent?: string;
51
53
  }
@@ -1,8 +1,13 @@
1
1
  import type { AgentIdentity } from "./faf/types.js";
2
- export type Theme = "light" | "dark" | "auto";
2
+ import { type BusinessCard, type Theme } from "agent-business-card";
3
+ export { cardInitials, renderBusinessCard, safeAccent } from "agent-business-card";
4
+ export type { BusinessCard, RenderOptions, Theme } from "agent-business-card";
3
5
  export interface CardOptions {
4
6
  theme?: Theme;
5
- /** CSS hex colour for the accent. Validated; invalid falls back to AAIF. */
7
+ /**
8
+ * CSS hex colour for the accent. Validated; invalid is ignored. Wins over the
9
+ * owner's colour; with neither, the card is drawn in ink (black or white).
10
+ */
6
11
  accent?: string;
7
12
  /**
8
13
  * Render every AGENTS.md section open. Default: sections collapse to their
@@ -18,58 +23,18 @@ export interface CardOptions {
18
23
  /** Business-card view. Default `landscape`; the reader can switch it too. */
19
24
  layout?: "landscape" | "portrait";
20
25
  }
21
- /** AAIF brand orange (aaif.io). The default accent. */
26
+ /** AAIF brand orange (aaif.io): this project's own card colour, declared in its `.fafa`. */
22
27
  export declare const AAIF_ACCENT = "#FF702D";
23
- export declare function safeAccent(a?: string): string;
24
28
  /** What the front calls this thing, from where it runs: "MCP server", "A2A agent", or both. */
25
29
  export declare function cardKind(id: AgentIdentity | null): string[];
26
30
  /** The front's title line: what it is, then its version. Empty when nothing is known. */
27
31
  export declare function cardTitle(id: AgentIdentity | null): string;
28
- /**
29
- * The front's logo: the first letter of the name's first meaningful word
30
- * (generic words like "mcp", "server", "sdk" skipped), plus a second letter
31
- * only when it's obvious: a known name (github → GH, typescript → TS) or a
32
- * word written with two capitals (GitHub, TypeScript). Never more than two.
33
- */
34
- export declare function cardInitials(name: string): string;
35
32
  /** The front's one-liner: the first sentence of the description. */
36
33
  export declare function cardOneLiner(id: AgentIdentity | null, max?: number): string;
37
- /**
38
- * A business card, independent of where its facts came from: everything the
39
- * renderer draws. `readCard` builds one from a project's files; another reader
40
- * (an A2A Agent Card, an MCP Server Card, a person's card) can build one too,
41
- * and `renderBusinessCard` draws any of them the same way.
42
- */
43
- export interface BusinessCard {
44
- name: string;
45
- /** What it is (and its version): "MCP server · v1.5.0", or a person's role. */
46
- title?: string;
47
- oneLiner?: string;
48
- /** Shown bottom-left on the front, e.g. the publisher domain. */
49
- domain?: string;
50
- /** Footer chips; `accent` highlights one (e.g. the status). Plain text. */
51
- chips: {
52
- text: string;
53
- accent?: boolean;
54
- }[];
55
- /** The back's tabs, in order. `key` is [a-z0-9-]; `html` is already-safe markup. */
56
- tabs: {
57
- key: string;
58
- label: string;
59
- heading: string;
60
- html: string;
61
- }[];
62
- /** The (i) panel, as already-safe markup. */
63
- about: string;
64
- }
65
- /** How to draw a card: the owner's colour and accent, the view, and the flat (print) layout. */
66
- export type RenderOptions = Pick<CardOptions, "theme" | "accent" | "layout" | "expanded">;
67
34
  /** The project's card: read its files, then draw. */
68
35
  export declare function renderCard(root: string, opts?: CardOptions): string;
69
36
  /** Read a project's AGENTS.md, memory and identity into a business card. */
70
37
  export declare function readCard(root: string, opts?: Pick<CardOptions, "expanded" | "memory">): BusinessCard;
71
- /** Draw any business card as one self-contained HTML page. */
72
- export declare function renderBusinessCard(card: BusinessCard, opts?: RenderOptions): string;
73
38
  /** tl;dr: the first few facts, each cut to about a line. `full`: every fact, whole. */
74
39
  export type Detail = "tldr" | "full";
75
40
  /**
@@ -16,192 +16,11 @@ import { parseFafm } from "./memory.js";
16
16
  import { resolveIdentity, serverCardMeta, META_NS } from "./identity.js";
17
17
  import { PUBLISH_MEMORY_ENV, SERVER_CARD_URI } from "./constants.js";
18
18
  import { escapeHtml, renderInline, renderMarkdown, slug } from "./md.js";
19
- /** AAIF brand orange (aaif.io). The default accent. */
19
+ import { renderBusinessCard } from "agent-business-card";
20
+ // The renderer lives in agent-business-card; these readers build the card from a project's files.
21
+ export { cardInitials, renderBusinessCard, safeAccent } from "agent-business-card";
22
+ /** AAIF brand orange (aaif.io): this project's own card colour, declared in its `.fafa`. */
20
23
  export const AAIF_ACCENT = "#FF702D";
21
- const ACCENT_OK = /^#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3}(?:[0-9a-fA-F]{2})?)?$/;
22
- export function safeAccent(a) {
23
- return a && ACCENT_OK.test(a) ? a : AAIF_ACCENT;
24
- }
25
- const CSS = (accent) => `
26
- /* The page and the card are themed independently. The page follows the
27
- viewer's OS. The card is the owner's choice: body[data-theme] (light | dark;
28
- none = follow the OS), and the reader can switch it with the ◐ toggle (#ink). */
29
- :root{
30
- --accent:${accent};
31
- --page-bg:#f4f4f5;--page-muted:#6b6b70;--page-line:rgba(0,0,0,.09);--page-chip:rgba(0,0,0,.05);
32
- }
33
- @media (prefers-color-scheme:dark){
34
- :root{--page-bg:#000;--page-muted:#9a9aa0;--page-line:rgba(255,255,255,.13);--page-chip:rgba(255,255,255,.07)}
35
- }
36
- .bcard{--card:#fff;--fg:#0a0a0a;--muted:#6b6b70;--line:rgba(0,0,0,.09);--chip:rgba(0,0,0,.05);--card-shadow:0 1px 3px rgba(0,0,0,.06),0 12px 32px rgba(0,0,0,.10)}
37
- body[data-theme="dark"] .bcard,
38
- body[data-theme="light"] #ink:checked~.stage .bcard{--card:#0d0d0d;--fg:#fafafa;--muted:#9a9aa0;--line:rgba(255,255,255,.13);--chip:rgba(255,255,255,.07);--card-shadow:0 0 0 1px rgba(255,255,255,.16),0 8px 40px color-mix(in srgb,var(--accent) 20%,transparent)}
39
- body[data-theme="dark"] #ink:checked~.stage .bcard{--card:#fff;--fg:#0a0a0a;--muted:#6b6b70;--line:rgba(0,0,0,.09);--chip:rgba(0,0,0,.05);--card-shadow:0 1px 3px rgba(0,0,0,.06),0 12px 32px rgba(0,0,0,.10)}
40
- @media (prefers-color-scheme:dark){
41
- body:not([data-theme]) .bcard{--card:#0d0d0d;--fg:#fafafa;--muted:#9a9aa0;--line:rgba(255,255,255,.13);--chip:rgba(255,255,255,.07);--card-shadow:0 0 0 1px rgba(255,255,255,.16),0 8px 40px color-mix(in srgb,var(--accent) 20%,transparent)}
42
- body:not([data-theme]) #ink:checked~.stage .bcard{--card:#fff;--fg:#0a0a0a;--muted:#6b6b70;--line:rgba(0,0,0,.09);--chip:rgba(0,0,0,.05);--card-shadow:0 1px 3px rgba(0,0,0,.06),0 12px 32px rgba(0,0,0,.10)}
43
- }
44
- @media (prefers-color-scheme:light){
45
- body:not([data-theme]) #ink:checked~.stage .bcard{--card:#0d0d0d;--fg:#fafafa;--muted:#9a9aa0;--line:rgba(255,255,255,.13);--chip:rgba(255,255,255,.07);--card-shadow:0 0 0 1px rgba(255,255,255,.16),0 8px 40px color-mix(in srgb,var(--accent) 20%,transparent)}
46
- }
47
- .bcard{color:var(--fg)}
48
- *{box-sizing:border-box}
49
- body{margin:0;background:var(--page-bg);color:var(--page-muted);
50
- font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
51
- padding:40px 16px}
52
- /* ── the business card: two faces, flip, two views ─────────────────── */
53
- .sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
54
- .stage{max-width:760px;margin:0 auto}
55
- .views{display:flex;justify-content:flex-end;margin:0 0 10px}
56
- .view,.hint label{cursor:pointer}
57
- .view{font-size:.78rem;font-weight:600;padding:3px 11px;border-radius:20px;border:1px solid var(--page-line);
58
- background:var(--page-chip);color:var(--page-muted);letter-spacing:.2em}
59
- .views{gap:8px}
60
- .view:hover,.hint label:hover{color:var(--accent);border-color:var(--accent)}
61
- .bcard{margin:0 auto;width:100%;aspect-ratio:7/4;perspective:1600px}
62
- #portrait:checked~.stage{max-width:480px}
63
- #portrait:checked~.stage .bcard{aspect-ratio:4/7}
64
- .faces{position:relative;width:100%;height:100%;transform-style:preserve-3d;transition:transform .6s ease}
65
- #flip:checked~.stage .faces{transform:rotateY(180deg)}
66
- .face{position:absolute;inset:0;background:var(--card);border:1px solid var(--line);border-radius:16px;
67
- box-shadow:var(--card-shadow);backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:hidden}
68
- .back{transform:rotateY(180deg) translateZ(1px);display:flex;flex-direction:column}
69
- /* The face turned away takes no pointer or wheel events, so the visible face
70
- scrolls (a hidden backface can still win hit-testing, notably in Chrome/Safari on macOS). */
71
- #flip:checked~.stage .front,#flip:not(:checked)~.stage .back{pointer-events:none;visibility:hidden;transition:visibility 0s .3s}
72
- #flip:checked~.stage .back,#flip:not(:checked)~.stage .front{visibility:visible;transition:visibility 0s .3s}
73
- .panes{overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
74
- .front{display:flex;flex-direction:column;justify-content:center;padding:34px 44px;
75
- border-top:5px solid var(--accent);
76
- background:linear-gradient(135deg,color-mix(in srgb,var(--accent) 10%,var(--card)) 0%,var(--card) 55%)}
77
- .front .id{max-width:34em}
78
- h1{margin:0;font-size:2.1rem;line-height:1.15;letter-spacing:-.025em}
79
- .title{margin:8px 0 0;font-size:.82rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}
80
- .oneliner{margin:16px 0 0;font-size:1.05rem;color:var(--muted);line-height:1.5}
81
- .foot-front{position:absolute;left:44px;right:130px;bottom:22px;display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px}
82
- .domain{font:.8rem ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}
83
- .corner{position:absolute;width:30px;height:30px;border-radius:50%;display:grid;place-items:center;
84
- cursor:pointer;font-weight:700;font-size:.9rem;color:var(--muted);background:var(--chip);border:1px solid var(--line);z-index:4}
85
- .corner:hover{color:var(--accent);border-color:var(--accent)}
86
- .corner.tr{top:16px;right:16px;font-family:Georgia,serif;font-style:italic}
87
- .logo{position:absolute;top:34px;left:44px;width:84px;height:84px;border-radius:50%;display:grid;place-items:center;
88
- color:#fff;font-weight:800;font-size:2rem;letter-spacing:-.02em;line-height:1;
89
- background:radial-gradient(circle at 30% 25%,color-mix(in srgb,var(--accent) 80%,#fff),var(--accent) 45%,color-mix(in srgb,var(--accent) 50%,#000));
90
- box-shadow:0 0 0 3px var(--card),0 0 0 4px color-mix(in srgb,var(--accent) 45%,transparent),0 6px 20px color-mix(in srgb,var(--accent) 30%,transparent)}
91
- .front .id{margin-top:70px}
92
- .corner.br{bottom:16px;right:16px}
93
- .flipbtn{position:absolute;right:18px;bottom:16px;z-index:4;cursor:pointer;width:42px;height:42px;border-radius:50%;
94
- display:grid;place-items:center;color:var(--fg);background:transparent;box-shadow:inset 0 0 0 2px var(--fg);
95
- transition:transform .2s ease}
96
- .flipbtn span{font-size:1.3rem;line-height:1;font-weight:700}
97
-
98
- /* the back's button: same spot and outline as the front's; ↺ instead of ↻. Over
99
- scrolling text it takes the card's colour, so the arrow stays readable. */
100
- .flipbtn.back-btn{background:var(--card)}
101
- /* fast tooltip: shows at once on hover or keyboard focus (a title tooltip waits ~1 s) */
102
- .flipbtn[data-tip]::after{content:attr(data-tip);position:absolute;right:0;bottom:calc(100% + 8px);white-space:nowrap;
103
- font:600 .74rem/1 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;letter-spacing:0;padding:6px 9px;border-radius:7px;
104
- color:var(--card);background:var(--fg);opacity:0;transform:translateY(3px);pointer-events:none;transition:opacity .08s,transform .08s}
105
- .flipbtn[data-tip]:hover::after,#flip:focus-visible~.stage .flipbtn[data-tip]::after{opacity:1;transform:none}
106
- .flipbtn:hover{transform:none}.flipbtn:hover span{transform:rotate(-25deg)}.flipbtn span{transition:transform .2s ease}
107
- .whatis{position:absolute;top:16px;right:16px;z-index:5}
108
- .whatis>summary{position:static;list-style:none}
109
- .whatis>summary::-webkit-details-marker{display:none}
110
- .whatis[open]>summary{color:var(--accent);border-color:var(--accent)}
111
- .whatis-panel{position:absolute;right:0;top:38px;width:min(320px,70vw);padding:14px 16px;border-radius:12px;
112
- background:var(--card);border:1px solid var(--line);box-shadow:var(--card-shadow);font-size:.84rem;line-height:1.5}
113
- .whatis-panel p{margin:0 0 8px}.whatis-head{font-weight:800;color:var(--accent);letter-spacing:-.01em;font-size:.95rem}
114
- .whatis-foot{color:var(--muted);margin:0!important}.whatis-panel code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
115
- .tabbar{display:flex;flex-wrap:wrap;gap:4px;padding:14px 60px 0 18px;border-bottom:1px solid var(--line);border-top:5px solid var(--accent)}
116
- .tabbar label{cursor:pointer;font-size:.8rem;font-weight:600;color:var(--muted);padding:6px 11px;border-radius:8px 8px 0 0}
117
- .tabbar label:hover{color:var(--fg)}
118
- .panes{flex:1;overflow:auto;padding:20px 26px 72px}
119
- .pane{display:none}
120
- .lead{margin:0 0 14px;font-size:1rem;line-height:1.6}
121
- .kv{border-collapse:collapse;font-size:.86rem;width:100%}
122
- .kv th{text-align:left;font-weight:600;color:var(--muted);padding:6px 14px 6px 0;white-space:nowrap;vertical-align:top}
123
- .kv td{padding:6px 0;border-bottom:1px solid var(--line)}
124
- .kv code,.lead code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
125
- .hint{text-align:center;color:var(--page-muted);font-size:.78rem;margin:14px 0 0}
126
- .hint label{color:var(--accent)}
127
- #flip:focus-visible~.stage .flipbtn,#portrait:focus-visible~.stage .view[for=portrait],#ink:focus-visible~.stage .view[for=ink]{outline:2px solid var(--accent);outline-offset:2px}
128
- @media (max-width:640px){
129
- .bcard,#portrait:checked~.stage .bcard{aspect-ratio:auto;height:min(78vh,720px)}
130
- .front{padding:28px 26px}.foot-front{left:26px}
131
- .logo{top:24px;left:26px;width:64px;height:64px;font-size:1.5rem}.front .id{margin-top:56px}
132
- h1{font-size:1.7rem}
133
- }
134
- /* flat: expanded render and print — both faces, every tab, no flip */
135
- .flat .faces,.flat .face{position:static;transform:none!important;height:auto}
136
- .flat .bcard{aspect-ratio:auto;perspective:none}
137
- .flat .face{margin:0 0 18px}.flat .front{min-height:260px;position:relative}
138
- .flat .pane{display:block;margin:0 0 22px}.flat .bcard{color:var(--fg)}.flat .tabbar,.flat .views,.flat .hint,.flat .corner,.flat .flipbtn,.flat .whatis{display:none}
139
- .flat .panes{overflow:visible}
140
- @media print{
141
- .faces,.face{position:static!important;transform:none!important;height:auto!important}
142
- .bcard{aspect-ratio:auto!important}.face{margin:0 0 18px;box-shadow:none}
143
- .pane{display:block!important;margin:0 0 22px}.tabbar,.views,.hint,.corner,.flipbtn,.whatis{display:none!important}
144
- .panes{overflow:visible}
145
- }
146
- .pills{display:flex;flex-wrap:wrap;gap:6px}
147
- .pill{font-size:.74rem;font-weight:600;padding:3px 9px;border-radius:20px;background:var(--chip);color:var(--muted)}
148
- .pill.accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent)}
149
- .label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
150
- color:var(--accent);margin:0 0 14px}
151
- .toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
152
- .toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
153
- .toc a:hover{color:var(--accent)}
154
- /* ── collapsible context ─────────────────────────────────────────── */
155
- .ctx-nav{position:sticky;top:-20px;z-index:3;background:var(--card);
156
- margin:0 -26px 16px;padding:11px 26px;border-bottom:1px solid var(--line);
157
- display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
158
- .xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
159
- white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
160
- background:var(--chip);color:var(--muted);cursor:pointer}
161
- .xall:hover{color:var(--accent);border-color:var(--accent)}
162
- .ctx-preamble{padding-bottom:4px}
163
- details.ctx-section{border-top:1px solid var(--line)}
164
- details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
165
- font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
166
- details.ctx-section>summary::-webkit-details-marker{display:none}
167
- details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
168
- transition:transform .15s ease}
169
- details.ctx-section[open]>summary::before{transform:rotate(90deg)}
170
- details.ctx-section>.md{padding:0 0 16px}
171
- @media print{
172
- .ctx-nav{display:none}
173
- details.ctx-section:not([open])>.md{display:block!important}
174
- details.ctx-section>summary::before{content:""}
175
- }
176
- .md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
177
- .md h1{font-size:1.15rem}
178
- .md p{margin:8px 0}
179
- .md ul,.md ol{margin:8px 0;padding-left:22px}
180
- .md li{margin:3px 0}
181
- .md code{background:var(--chip);padding:1px 5px;border-radius:5px;
182
- font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
183
- .md pre{background:var(--chip);padding:14px 16px;border-radius:9px;overflow:auto}
184
- .md pre code{background:none;padding:0}
185
- .md table{border-collapse:collapse;width:100%;margin:12px 0;font-size:.88rem;display:block;overflow:auto}
186
- .md th,.md td{border:1px solid var(--line);padding:6px 10px;text-align:left}
187
- .md blockquote{margin:10px 0;padding-left:14px;border-left:3px solid var(--line);color:var(--muted)}
188
- .md a{color:var(--accent)}
189
- .fact{padding:12px 0;border-bottom:1px solid var(--line)}
190
- .fact:last-child{border-bottom:0}
191
- .fact p{margin:0 0 7px}
192
- .meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
193
- .tag{font-size:.72rem;padding:2px 8px;border-radius:5px;background:var(--chip);color:var(--muted)}
194
- .dot{width:7px;height:7px;border-radius:50%;background:var(--accent);display:inline-block}
195
- .dot.pending{background:var(--muted)}
196
- .disc{width:100%;border-collapse:collapse;font-size:.84rem}
197
- .disc th,.disc td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--line)}
198
- .disc th{color:var(--muted);font-weight:600}
199
- .disc code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}
200
- .fetch{margin:14px 0 0;font-size:.82rem;color:var(--muted)}
201
- .fetch code{background:var(--chip);padding:1px 5px;border-radius:5px}
202
- .none{color:var(--muted);font-style:italic}
203
- `;
204
- const htmlAttr = (theme) => theme === "auto" ? "" : ` data-theme="${theme}"`;
205
24
  /** What the front calls this thing, from where it runs: "MCP server", "A2A agent", or both. */
206
25
  export function cardKind(id) {
207
26
  const kinds = [];
@@ -216,28 +35,6 @@ export function cardKind(id) {
216
35
  export function cardTitle(id) {
217
36
  return [cardKind(id).join(" · "), id?.agentVersion ? `v${id.agentVersion}` : ""].filter(Boolean).join(" · ");
218
37
  }
219
- /** The front's logo: the first letters of the name's first two words ("mcp-context-card" → "MC"). */
220
- /** Words that say what kind of thing it is, not whose: never the logo ("mcp-context-card" → C, not M). */
221
- const GENERIC_WORDS = new Set(["mcp", "server", "servers", "sdk", "agent", "agents", "api", "cli", "app", "tool", "tools", "plugin", "core", "the"]);
222
- /** Names whose two-letter mark is obvious. */
223
- const OBVIOUS_MARKS = { github: "GH", gitlab: "GL", typescript: "TS", javascript: "JS" };
224
- /**
225
- * The front's logo: the first letter of the name's first meaningful word
226
- * (generic words like "mcp", "server", "sdk" skipped), plus a second letter
227
- * only when it's obvious: a known name (github → GH, typescript → TS) or a
228
- * word written with two capitals (GitHub, TypeScript). Never more than two.
229
- */
230
- export function cardInitials(name) {
231
- const words = name.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
232
- const first = words.find((w) => !GENERIC_WORDS.has(w.toLowerCase())) ?? words[0] ?? "";
233
- const known = OBVIOUS_MARKS[first.toLowerCase()];
234
- if (known)
235
- return known;
236
- const capitals = first.match(/\p{Lu}/gu) ?? [];
237
- if (capitals.length === 2 && /^\p{Lu}/u.test(first) && /\p{Ll}/u.test(first))
238
- return capitals.join("");
239
- return (Array.from(first)[0] ?? "").toUpperCase();
240
- }
241
38
  /** The front's one-liner: the first sentence of the description. */
242
39
  export function cardOneLiner(id, max = 140) {
243
40
  const d = id?.description;
@@ -368,112 +165,9 @@ export function readCard(root, opts = {}) {
368
165
  chips,
369
166
  tabs: tabs.map(([key, label, heading, html]) => ({ key, label, heading, html })),
370
167
  about: AGENT_ABOUT,
168
+ ...(id?.accent ? { accent: id.accent } : {}),
371
169
  };
372
170
  }
373
- /** Draw any business card as one self-contained HTML page. */
374
- export function renderBusinessCard(card, opts = {}) {
375
- const theme = opts.theme ?? "auto";
376
- const accent = safeAccent(opts.accent);
377
- const portrait = opts.layout === "portrait";
378
- const flat = !!opts.expanded;
379
- const { name, title, oneLiner, domain } = card;
380
- const tabs = card.tabs.map((t) => ({ ...t, key: t.key.replace(/[^a-z0-9-]/gi, "").toLowerCase() || "tab" }));
381
- const pills = card.chips
382
- .map((c) => `<span class="pill${c.accent ? " accent" : ""}">${escapeHtml(c.text)}</span>`)
383
- .join("");
384
- const radios = tabs
385
- .map((t, i) => `<input type="radio" name="tab" id="t-${t.key}" class="sr"${i === 0 ? " checked" : ""}>`)
386
- .join("");
387
- const tabbar = tabs.map((t) => `<label for="t-${t.key}">${escapeHtml(t.label)}</label>`).join("");
388
- const panes = tabs
389
- .map((t) => `<div class="pane p-${t.key}"><p class="label">${escapeHtml(t.heading)}</p>${t.html}</div>`)
390
- .join("");
391
- // One CSS rule pair per tab: its pane shows, its label lights, when its radio is checked.
392
- const tabCss = tabs
393
- .map((t) => `#t-${t.key}:checked~.panes .p-${t.key}{display:block}#t-${t.key}:checked~.tabbar label[for=t-${t.key}]{color:var(--accent);background:var(--chip)}`)
394
- .join("");
395
- // The (i) panel: the same control, in the same spot, on both faces.
396
- const WHATIS = `<details class="whatis">
397
- <summary class="corner tr" title="About this card" aria-label="About this card">i</summary>
398
- <div class="whatis-panel">
399
- ${card.about}
400
- </div>
401
- </details>`;
402
- return `<!doctype html>
403
- <html lang="en">
404
- <head>
405
- <meta charset="utf-8">
406
- <meta name="viewport" content="width=device-width,initial-scale=1">
407
- <title>${escapeHtml(name)} — business card</title>
408
- <style>${CSS(accent)}${tabCss}</style>
409
- </head>
410
- <body${flat ? ` class="flat"` : ""}${htmlAttr(theme)}>
411
- <input type="checkbox" id="flip" class="sr" aria-label="Flip the card">
412
- <input type="checkbox" id="ink" class="sr" aria-label="Switch the card between light and dark">
413
- <input type="checkbox" id="portrait" class="sr" aria-label="Portrait view"${portrait ? " checked" : ""}>
414
- <div class="stage">
415
- <div class="views"><label for="ink" class="view" title="Card: light or dark">◐</label><label for="portrait" class="view" title="Landscape or portrait">▭ ▯</label></div>
416
- <main class="bcard">
417
- <div class="faces">
418
- <section class="face front">
419
- <div class="logo" aria-hidden="true">${escapeHtml(cardInitials(name))}</div>
420
- ${WHATIS}
421
- <div class="id">
422
- <h1>${escapeHtml(name)}</h1>
423
- ${title ? `<p class="title">${escapeHtml(title)}</p>` : ""}
424
- ${oneLiner ? `<p class="oneliner">${escapeHtml(oneLiner)}</p>` : ""}
425
- </div>
426
- <div class="foot-front">${domain ? `<span class="domain">${escapeHtml(domain)}</span>` : ""}${pills ? `<div class="pills">${pills}</div>` : ""}</div>
427
- <label for="flip" class="flipbtn" data-tip="Flip the card" aria-label="Flip the card"><span aria-hidden="true">↻</span></label>
428
- </section>
429
- <section class="face back">
430
- ${radios}
431
- ${WHATIS}
432
- <div class="tabbar">${tabbar}</div>
433
- <div class="panes">${panes}</div>
434
- <label for="flip" class="flipbtn back-btn" data-tip="Flip back" aria-label="Flip back"><span aria-hidden="true">↺</span></label>
435
- </section>
436
- </div>
437
- </main>
438
- <p class="hint">${escapeHtml(name)} · business card · <label for="flip">flip it over</label></p>
439
- </div>
440
- ${CARD_SCRIPT}
441
- </body>
442
- </html>
443
- `;
444
- }
445
- /**
446
- * The card's only script — a progressive enhancement. Flip, tabs and the view
447
- * toggle are CSS (checkbox and radio inputs) and work without it. It adds:
448
- * Expand all / Collapse all for the context sections, opening the section a
449
- * `#hash` names (flipping to the back and its Context tab first), and opening
450
- * every section for printing (browsers disagree on printing a closed
451
- * `<details>`).
452
- */
453
- const CARD_SCRIPT = `<script>
454
- (function(){
455
- var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
456
- var btn=document.querySelector(".xall");
457
- var sync=function(){if(btn)btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
458
- if(btn&&secs.length){
459
- btn.hidden=false;
460
- btn.addEventListener("click",function(){var open=!secs.every(function(d){return d.open});secs.forEach(function(d){d.open=open});sync()});
461
- secs.forEach(function(d){d.addEventListener("toggle",sync)});
462
- }
463
- var openHash=function(){
464
- var d=document.getElementById(decodeURIComponent(location.hash.slice(1)));
465
- if(!d||d.tagName!=="DETAILS")return;
466
- var f=document.getElementById("flip"),t=document.getElementById("t-context");
467
- if(f)f.checked=true;if(t)t.checked=true;d.open=true;sync();
468
- setTimeout(function(){d.scrollIntoView({block:"nearest"})},620);
469
- };
470
- addEventListener("hashchange",openHash);openHash();
471
- var pre=[];
472
- addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
473
- addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
474
- sync();
475
- })();
476
- </script>`;
477
171
  const TLDR_FACTS = 5;
478
172
  const TLDR_CHARS = 160;
479
173
  /**
package/dist/server.js CHANGED
@@ -62,7 +62,7 @@ function cardOptions(args) {
62
62
  }
63
63
  const CARD_ARGS = {
64
64
  theme: { type: "string", enum: ["light", "dark", "auto"], description: "default: auto" },
65
- accent: { type: "string", description: "CSS hex colour, e.g. #FF702D (default: the AAIF palette)" },
65
+ accent: { type: "string", description: "CSS hex colour, e.g. #0066cc (default: the .fafa metadata.cards.accent, else black/white ink)" },
66
66
  expanded: { type: "boolean", description: "render every AGENTS.md section open (default: collapsed)" },
67
67
  layout: { type: "string", enum: ["landscape", "portrait"], description: "business-card view (default: landscape)" },
68
68
  };
@@ -32,7 +32,7 @@ Streamable HTTP endpoint at `<origin>/mcp` and its protocol versions):
32
32
  {
33
33
  "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
34
34
  "name": "io.github.Wolfe-Jam/mcp-context-card",
35
- "version": "1.6.1",
35
+ "version": "1.7.1",
36
36
  "title": "MCP Context Card",
37
37
  "description": "MCP server for a project's context (AGENTS.md), memory, and identity — base or drop-in extension.",
38
38
  "websiteUrl": "https://github.com/Wolfe-Jam/mcp-context-card",
@@ -85,7 +85,7 @@ publisher lists artifacts, each entry keyed by its **media type** (`type`).
85
85
  GET /.well-known/ai-catalog.json
86
86
  ```
87
87
 
88
- Served from `https://ctx.example.com` (1.6.1, this repo's own files):
88
+ Served from `https://ctx.example.com` (1.7.1, this repo's own files):
89
89
 
90
90
  ```jsonc
91
91
  {
@@ -205,7 +205,7 @@ details.ctx-section>.md{padding:0 0 16px}
205
205
  </details>
206
206
  <div class="id">
207
207
  <h1>mcp-context-card</h1>
208
- <p class="title">MCP server · v1.6.1</p>
208
+ <p class="title">MCP server · v1.7.1</p>
209
209
  <p class="oneliner">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity</p>
210
210
  </div>
211
211
  <div class="foot-front"><span class="domain">faf.one</span><div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill accent">published</span><span class="pill">MIT</span></div></div>
@@ -223,11 +223,11 @@ details.ctx-section>.md{padding:0 0 16px}
223
223
  </div>
224
224
  </details>
225
225
  <div class="tabbar"><label for="t-about">About</label><label for="t-context">Context</label><label for="t-memory">Memory</label><label for="t-discovery">Discovery</label></div>
226
- <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.6.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
226
+ <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.7.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
227
227
  <div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
228
228
  <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
229
229
  <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
230
- <p>Node 20 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
230
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
231
231
  npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
232
232
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
233
233
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
@@ -205,7 +205,7 @@ details.ctx-section>.md{padding:0 0 16px}
205
205
  </details>
206
206
  <div class="id">
207
207
  <h1>mcp-context-card</h1>
208
- <p class="title">MCP server · v1.6.1</p>
208
+ <p class="title">MCP server · v1.7.1</p>
209
209
  <p class="oneliner">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity</p>
210
210
  </div>
211
211
  <div class="foot-front"><span class="domain">faf.one</span><div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill accent">published</span><span class="pill">MIT</span></div></div>
@@ -223,11 +223,11 @@ details.ctx-section>.md{padding:0 0 16px}
223
223
  </div>
224
224
  </details>
225
225
  <div class="tabbar"><label for="t-about">About</label><label for="t-context">Context</label><label for="t-memory">Memory</label><label for="t-discovery">Discovery</label></div>
226
- <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.6.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
226
+ <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.7.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
227
227
  <div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
228
228
  <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
229
229
  <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
230
- <p>Node 20 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
230
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
231
231
  npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
232
232
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
233
233
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
package/docs/card.html CHANGED
@@ -205,7 +205,7 @@ details.ctx-section>.md{padding:0 0 16px}
205
205
  </details>
206
206
  <div class="id">
207
207
  <h1>mcp-context-card</h1>
208
- <p class="title">MCP server · v1.6.1</p>
208
+ <p class="title">MCP server · v1.7.1</p>
209
209
  <p class="oneliner">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity</p>
210
210
  </div>
211
211
  <div class="foot-front"><span class="domain">faf.one</span><div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill accent">published</span><span class="pill">MIT</span></div></div>
@@ -223,11 +223,11 @@ details.ctx-section>.md{padding:0 0 16px}
223
223
  </div>
224
224
  </details>
225
225
  <div class="tabbar"><label for="t-about">About</label><label for="t-context">Context</label><label for="t-memory">Memory</label><label for="t-discovery">Discovery</label></div>
226
- <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.6.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
226
+ <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.7.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
227
227
  <div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
228
228
  <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
229
229
  <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
230
- <p>Node 20 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
230
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
231
231
  npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
232
232
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
233
233
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
Binary file
Binary file
Binary file
package/docs/index.html CHANGED
@@ -205,7 +205,7 @@ details.ctx-section>.md{padding:0 0 16px}
205
205
  </details>
206
206
  <div class="id">
207
207
  <h1>mcp-context-card</h1>
208
- <p class="title">MCP server · v1.6.1</p>
208
+ <p class="title">MCP server · v1.7.1</p>
209
209
  <p class="oneliner">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity</p>
210
210
  </div>
211
211
  <div class="foot-front"><span class="domain">faf.one</span><div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill accent">published</span><span class="pill">MIT</span></div></div>
@@ -223,11 +223,11 @@ details.ctx-section>.md{padding:0 0 16px}
223
223
  </div>
224
224
  </details>
225
225
  <div class="tabbar"><label for="t-about">About</label><label for="t-context">Context</label><label for="t-memory">Memory</label><label for="t-discovery">Discovery</label></div>
226
- <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.6.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
226
+ <div class="panes"><div class="pane p-about"><p class="label">About</p><p class="lead">The essential MCP components for a project's context (AGENTS.md), cross-session memory, and identity — a base MCP on its own, or a drop-in extension for any existing MCP server, discoverable through the Server Card _meta block and a self-published ai-catalog.json.</p><table class="kv"><tbody><tr><th>Agent ID</th><td><code>urn:air:faf.one:agent:mcp-context-card</code></td></tr><tr><th>Publisher</th><td>io.github.Wolfe-Jam</td></tr><tr><th>Version</th><td>v1.7.1</td></tr><tr><th>Status</th><td>published</td></tr><tr><th>License</th><td>MIT</td></tr><tr><th>Package (npm)</th><td><code>mcp-context-card</code></td></tr></tbody></table></div><div class="pane p-context"><p class="label">Context — AGENTS.md</p><div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
227
227
  <div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
228
228
  <p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
229
229
  <div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
230
- <p>Node 20 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
230
+ <p>Node 22 or newer. No other system dependencies.</p></div></details><details class="ctx-section" id="build"><summary>Build</summary><div class="md"><pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
231
231
  npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
232
232
  npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
233
233
  npm run demo # end to end: all tools over stdio, then over stateless HTTP
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-context-card",
3
- "version": "1.6.1",
3
+ "version": "1.7.1",
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": [
@@ -66,6 +66,7 @@
66
66
  "dependencies": {
67
67
  "@hono/node-server": "^1.19.17",
68
68
  "@modelcontextprotocol/sdk": "^1.31.0",
69
+ "agent-business-card": "^0.1.0",
69
70
  "agents-md-facts": "^0.1.0",
70
71
  "hono": "^4.13.7",
71
72
  "yaml": "^2.9.0"
package/project.faf CHANGED
@@ -24,7 +24,7 @@ stack:
24
24
  cache: slotignored
25
25
  search: slotignored
26
26
  storage: slotignored
27
- tech_stack: [TypeScript, "@modelcontextprotocol/sdk", "agents-md-facts", hono, "@hono/node-server", yaml]
27
+ tech_stack: [TypeScript, "@modelcontextprotocol/sdk", "agents-md-facts", "agent-business-card", hono, "@hono/node-server", yaml]
28
28
  human_context:
29
29
  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.
30
30
  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).
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.6.1",
6
+ "version": "1.7.1",
7
7
  "repository": {
8
8
  "url": "https://github.com/Wolfe-Jam/mcp-context-card",
9
9
  "source": "github"
@@ -14,7 +14,7 @@
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "mcp-context-card",
17
- "version": "1.6.1",
17
+ "version": "1.7.1",
18
18
  "runtimeHint": "npx",
19
19
  "transport": {
20
20
  "type": "stdio"