mcp-context-card 1.0.1 → 1.1.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.
- package/.well-known/fafa +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +49 -0
- package/README.md +20 -8
- package/dist/bin.d.ts +1 -1
- package/dist/bin.js +5 -2
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/render-card.d.ts +6 -0
- package/dist/render-card.js +70 -12
- package/dist/server.js +24 -2
- package/dist/transport/http.js +1 -1
- package/docs/MECHANISMS.md +1 -1
- package/docs/card-dark.html +52 -26
- package/docs/card-light.html +52 -26
- package/docs/card.html +52 -26
- package/docs/img/card-dark.png +0 -0
- package/docs/img/card-identity.png +0 -0
- package/docs/img/card-light.png +0 -0
- package/docs/index.html +52 -26
- package/package.json +1 -1
- package/server.json +2 -2
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.
|
|
12
|
+
version: "1.1.1"
|
|
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
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
|
|
4
4
|
|
|
5
|
+
## 1.1.1
|
|
6
|
+
|
|
7
|
+
Every tool now says what it is and what it does to your project.
|
|
8
|
+
|
|
9
|
+
Each of the nine tools carries a human-readable `title` and MCP tool
|
|
10
|
+
annotations, so a host can label it properly and decide whether to ask
|
|
11
|
+
before running it:
|
|
12
|
+
|
|
13
|
+
- **Read-only (7):** `read_agents_md`, `list_agents_md_sections`,
|
|
14
|
+
`author_agents_md` (returns a draft, writes nothing), `recall`, `whoami`,
|
|
15
|
+
`list_context_sources`, `render_context_card`.
|
|
16
|
+
- **Writes the memory file (2):** `remember` and `forget` are marked
|
|
17
|
+
`destructiveHint: true`. `remember` replaces a fact when an id is reused;
|
|
18
|
+
`forget` removes one.
|
|
19
|
+
- All nine are `idempotentHint: true` (repeating a call changes nothing more)
|
|
20
|
+
and `openWorldHint: false` (they only touch the local project).
|
|
21
|
+
|
|
22
|
+
A new test checks every tool's title and hints against what it actually does,
|
|
23
|
+
so a tool added later can't ship without them. 106 tests, all green on
|
|
24
|
+
Linux, macOS, and Windows.
|
|
25
|
+
|
|
26
|
+
No API change to the nine tools: same names, same inputs, same behaviour.
|
|
27
|
+
|
|
28
|
+
## 1.1.0
|
|
29
|
+
|
|
30
|
+
The card scans in one screen — AGENTS.md sections collapse by default.
|
|
31
|
+
|
|
32
|
+
Every AGENTS.md section is now its own `<details>`, closed on load: the card
|
|
33
|
+
opens as identity → the section list → memory count → discovery, one screen,
|
|
34
|
+
scannable. Click a section to read it; the section index stays sticky at the
|
|
35
|
+
top so it's always one click away, not a scroll back up.
|
|
36
|
+
|
|
37
|
+
- **Expand all / Collapse all** — a control in the sticky nav, from one
|
|
38
|
+
~16-line inline script (no external resources; the card is still one
|
|
39
|
+
self-contained file). It's a progressive enhancement: the button ships
|
|
40
|
+
`hidden` and the script reveals it, so with JavaScript off every section
|
|
41
|
+
still opens and closes on its own.
|
|
42
|
+
- **`--expanded` / `?expand=all` / `expanded: true`** — the full-page render,
|
|
43
|
+
for a screenshot or a PR. Available on the CLI (`npx mcp-context-card card
|
|
44
|
+
--expanded`), the HTTP transport (`GET /card?expand=all`), and the
|
|
45
|
+
`render_context_card` tool. This path renders `<details open>` server-side —
|
|
46
|
+
no script involved.
|
|
47
|
+
- **A section index link opens its section** — `#section` in the URL, or a
|
|
48
|
+
click in the nav.
|
|
49
|
+
- **Print / save-as-PDF** opens every section first, then restores.
|
|
50
|
+
|
|
51
|
+
No API change to the nine tools. `render_context_card` gains an optional
|
|
52
|
+
`expanded` boolean; everything else is unchanged.
|
|
53
|
+
|
|
5
54
|
## 1.0.1
|
|
6
55
|
|
|
7
56
|
`npx mcp-context-card` now runs — it silently no-op'd when launched through
|
package/README.md
CHANGED
|
@@ -70,14 +70,21 @@ file access, no shell, no search.
|
|
|
70
70
|
|
|
71
71
|
The screenshot at the top of this page is exactly this — the same three
|
|
72
72
|
sources rendered as one self‑contained HTML page: identity, `AGENTS.md`,
|
|
73
|
-
memory, and how a machine fetches it. The view for people:
|
|
74
|
-
drop it in a PR, put it on a status page.
|
|
73
|
+
memory, and how a machine fetches it. The view for people: read it, screenshot
|
|
74
|
+
it, drop it in a PR, put it on a status page.
|
|
75
|
+
|
|
76
|
+
`AGENTS.md` sections are collapsed by default, so the card scans in one screen;
|
|
77
|
+
a sticky index jumps to any section, **Expand all** opens everything. Sections
|
|
78
|
+
toggle natively — the one small inline script only adds the bulk button and the
|
|
79
|
+
print handler. `--expanded` / `?expand=all` renders it fully open, script-free,
|
|
80
|
+
for a screenshot.
|
|
75
81
|
|
|
76
82
|
```
|
|
77
|
-
npx mcp-context-card card
|
|
83
|
+
npx mcp-context-card card # at a terminal: writes context-card.html and opens it
|
|
84
|
+
npx mcp-context-card card --expanded # every section open
|
|
78
85
|
npx mcp-context-card card > x.html # piped/redirected: raw HTML to stdout
|
|
79
|
-
GET /card
|
|
80
|
-
GET /card?theme=light&accent=%230066cc
|
|
86
|
+
GET /card # live, on the HTTP transport
|
|
87
|
+
GET /card?expand=all&theme=light&accent=%230066cc
|
|
81
88
|
```
|
|
82
89
|
|
|
83
90
|
Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
|
|
@@ -115,7 +122,7 @@ npx mcp-context-card card
|
|
|
115
122
|
|
|
116
123
|
At a terminal it writes `context-card.html` and opens it in your browser. Piped
|
|
117
124
|
or redirected (`> card.html`, a script, CI) it writes raw HTML to stdout instead;
|
|
118
|
-
`--stdout` forces that from a terminal too.
|
|
125
|
+
`--stdout` forces that from a terminal too. `--expanded` opens every section.
|
|
119
126
|
|
|
120
127
|
### Wire it into a host
|
|
121
128
|
|
|
@@ -186,6 +193,10 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
|
|
|
186
193
|
| `list_context_sources` | what this project publishes, in what media types, via which surface |
|
|
187
194
|
| `render_context_card` | the whole card as one self‑contained HTML page (also `GET /card`) |
|
|
188
195
|
|
|
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
|
|
198
|
+
title and MCP tool annotations.
|
|
199
|
+
|
|
189
200
|
## The demo
|
|
190
201
|
|
|
191
202
|
`npm run demo` runs every tool over both transports:
|
|
@@ -198,10 +209,11 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
|
|
|
198
209
|
4. **Discovery** — `list_context_sources()`, then the same server over stateless
|
|
199
210
|
HTTP with its `.well-known` routes and `GET /card`.
|
|
200
211
|
|
|
201
|
-
|
|
212
|
+
106 tests on Linux, macOS, and Windows, coverage‑gated in CI. Two spawn a real
|
|
202
213
|
child process and check a remembered fact survives the restart — one against
|
|
203
214
|
an existing `project.fafm`, one starting from a project that has never had
|
|
204
|
-
one; another checks the stdio and HTTP tool surfaces match
|
|
215
|
+
one; another checks the stdio and HTTP tool surfaces match, and another checks
|
|
216
|
+
every tool's title and behaviour hints against what it actually does.
|
|
205
217
|
|
|
206
218
|
## Layout
|
|
207
219
|
|
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.
|
|
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";
|
|
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
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* mcp-context-card card → this directory's context card. At a terminal:
|
|
10
10
|
* writes context-card.html and opens it. Piped
|
|
11
11
|
* or redirected: HTML to stdout ( > card.html ).
|
|
12
|
-
* --theme light|dark · --accent #hex
|
|
12
|
+
* --theme light|dark · --accent #hex
|
|
13
|
+
* --expanded (all sections open) · --stdout
|
|
13
14
|
* mcp-context-card --help → usage
|
|
14
15
|
* mcp-context-card --version → version
|
|
15
16
|
*
|
|
@@ -32,7 +33,8 @@ USAGE
|
|
|
32
33
|
mcp-context-card --stdio force stdio even when PORT is set
|
|
33
34
|
mcp-context-card card this dir's context card — opens it in your browser
|
|
34
35
|
at a terminal; HTML to stdout when piped ( > f.html )
|
|
35
|
-
--theme light|dark --accent #hex
|
|
36
|
+
--theme light|dark --accent #hex
|
|
37
|
+
--expanded (all sections open) --stdout
|
|
36
38
|
mcp-context-card --help this text
|
|
37
39
|
mcp-context-card --version print version
|
|
38
40
|
|
|
@@ -109,6 +111,7 @@ if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
|
|
|
109
111
|
const html = renderCard(root, {
|
|
110
112
|
theme: theme === "light" || theme === "dark" ? theme : "auto",
|
|
111
113
|
accent: safeAccent(flagValue(argv, "--accent")),
|
|
114
|
+
expanded: argv.includes("--expanded"),
|
|
112
115
|
});
|
|
113
116
|
// Piped / redirected (or --stdout) → raw HTML on stdout, unchanged.
|
|
114
117
|
// A bare run at a terminal → the HTML is noise; write a file and open it.
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Server identity constants, in their own module so any file can import
|
|
2
2
|
* them without pulling in the whole server. */
|
|
3
3
|
export declare const NAME = "mcp-context-card";
|
|
4
|
-
export declare const VERSION = "1.
|
|
4
|
+
export declare const VERSION = "1.1.1";
|
|
5
5
|
export declare const SERVER_CARD_URI = "mcp-context-card://server-card";
|
package/dist/constants.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Server identity constants, in their own module so any file can import
|
|
2
2
|
* them without pulling in the whole server. */
|
|
3
3
|
export const NAME = "mcp-context-card";
|
|
4
|
-
export const VERSION = "1.
|
|
4
|
+
export const VERSION = "1.1.1";
|
|
5
5
|
export const SERVER_CARD_URI = "mcp-context-card://server-card";
|
package/dist/render-card.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ export interface CardOptions {
|
|
|
3
3
|
theme?: Theme;
|
|
4
4
|
/** CSS hex colour for the accent. Validated; invalid falls back to AAIF. */
|
|
5
5
|
accent?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Render every AGENTS.md section open. Default: sections collapse to their
|
|
8
|
+
* headings (`<details>`), click one to read it — the card scans in one screen.
|
|
9
|
+
* `expanded` is the whole-page render, for a screenshot or a PR.
|
|
10
|
+
*/
|
|
11
|
+
expanded?: boolean;
|
|
6
12
|
}
|
|
7
13
|
/** AAIF brand orange (aaif.io). The default accent. */
|
|
8
14
|
export declare const AAIF_ACCENT = "#FF702D";
|
package/dist/render-card.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* or drop into a PR. Same three sources as the Server Card _meta block and
|
|
7
7
|
* ai-catalog; this is the view for people.
|
|
8
8
|
*
|
|
9
|
-
* Self-contained: inline CSS, no
|
|
10
|
-
*
|
|
9
|
+
* Self-contained: inline CSS, no external fonts or resources. The only script
|
|
10
|
+
* is the expand-all / print helper (TOGGLE_SCRIPT) — a progressive enhancement;
|
|
11
|
+
* every section still opens on its own without it. Renders anywhere.
|
|
11
12
|
*/
|
|
12
13
|
import { join } from "node:path";
|
|
13
14
|
import { parseAgentsMd } from "./agents-md.js";
|
|
@@ -47,7 +48,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
47
48
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
48
49
|
padding:40px 18px}
|
|
49
50
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
50
|
-
border-radius:14px;overflow:
|
|
51
|
+
border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
|
|
51
52
|
.card>*{padding:26px 30px}
|
|
52
53
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
53
54
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -58,9 +59,31 @@ section{border-bottom:1px solid var(--line)}
|
|
|
58
59
|
section:last-child{border-bottom:0}
|
|
59
60
|
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
60
61
|
color:var(--accent);margin:0 0 14px}
|
|
61
|
-
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0
|
|
62
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
|
|
62
63
|
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
63
64
|
.toc a:hover{color:var(--accent)}
|
|
65
|
+
/* ── collapsible context ─────────────────────────────────────────── */
|
|
66
|
+
.ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
|
|
67
|
+
margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
|
|
68
|
+
display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
|
|
69
|
+
.xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
|
|
70
|
+
white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
|
|
71
|
+
background:var(--chip);color:var(--muted);cursor:pointer}
|
|
72
|
+
.xall:hover{color:var(--accent);border-color:var(--accent)}
|
|
73
|
+
.ctx-preamble{padding-bottom:4px}
|
|
74
|
+
details.ctx-section{border-top:1px solid var(--line)}
|
|
75
|
+
details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
|
|
76
|
+
font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
|
|
77
|
+
details.ctx-section>summary::-webkit-details-marker{display:none}
|
|
78
|
+
details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
|
|
79
|
+
transition:transform .15s ease}
|
|
80
|
+
details.ctx-section[open]>summary::before{transform:rotate(90deg)}
|
|
81
|
+
details.ctx-section>.md{padding:0 0 16px}
|
|
82
|
+
@media print{
|
|
83
|
+
.ctx-nav{display:none}
|
|
84
|
+
details.ctx-section:not([open])>.md{display:block!important}
|
|
85
|
+
details.ctx-section>summary::before{content:""}
|
|
86
|
+
}
|
|
64
87
|
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
65
88
|
.md h1{font-size:1.15rem}
|
|
66
89
|
.md p{margin:8px 0}
|
|
@@ -107,21 +130,28 @@ export function renderCard(root, opts = {}) {
|
|
|
107
130
|
]
|
|
108
131
|
.filter(Boolean)
|
|
109
132
|
.join("");
|
|
110
|
-
// CONTEXT —
|
|
133
|
+
// CONTEXT — one <details> per AGENTS.md section, collapsed by default (the card
|
|
134
|
+
// scans in one screen); `expanded` renders them all open. The "# AGENTS.md"
|
|
135
|
+
// top-level heading is dropped; its intro rides above the sections.
|
|
111
136
|
const bodySections = agents?.sections.filter((s) => s.level > 1) ?? [];
|
|
112
137
|
const toc = bodySections.length
|
|
113
138
|
? `<ul class="toc">${bodySections
|
|
114
139
|
.map((s) => `<li><a href="#${slug(s.heading)}">${escapeHtml(s.heading)}</a></li>`)
|
|
115
140
|
.join("")}</ul>`
|
|
116
141
|
: "";
|
|
142
|
+
const preamble = [agents?.preamble, agents?.sections.find((s) => s.level === 1)?.body ?? ""]
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.join("\n\n");
|
|
145
|
+
const openAttr = opts.expanded ? " open" : "";
|
|
146
|
+
const sections = bodySections
|
|
147
|
+
.map((s) => `<details class="ctx-section"${openAttr} id="${slug(s.heading)}"><summary>${escapeHtml(s.heading)}</summary><div class="md">${renderMarkdown(s.body)}</div></details>`)
|
|
148
|
+
.join("");
|
|
117
149
|
const contextBody = agents
|
|
118
|
-
?
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.filter(Boolean)
|
|
124
|
-
.join("\n\n"))}</div>`
|
|
150
|
+
? `<div class="ctx-nav">${toc}${bodySections.length
|
|
151
|
+
? `<button type="button" class="xall" hidden>${opts.expanded ? "Collapse all" : "Expand all"}</button>`
|
|
152
|
+
: ""}</div>
|
|
153
|
+
${preamble ? `<div class="ctx-preamble md">${renderMarkdown(preamble)}</div>` : ""}
|
|
154
|
+
<div class="ctx-body">${sections}</div>`
|
|
125
155
|
: `<p class="none">No AGENTS.md in this project.</p>`;
|
|
126
156
|
// MEMORY
|
|
127
157
|
const memoryBody = mem.facts.length
|
|
@@ -174,7 +204,35 @@ export function renderCard(root, opts = {}) {
|
|
|
174
204
|
</section>
|
|
175
205
|
<div class="foot">${escapeHtml(name)} · context card</div>
|
|
176
206
|
</main>
|
|
207
|
+
${bodySections.length ? TOGGLE_SCRIPT : ""}
|
|
177
208
|
</body>
|
|
178
209
|
</html>
|
|
179
210
|
`;
|
|
180
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Expand-all / Collapse-all. The only script in the card — a progressive
|
|
214
|
+
* enhancement: with it off, every section still opens and closes on its own
|
|
215
|
+
* (native `<details>`), just without the bulk button. It also opens every
|
|
216
|
+
* section for printing, since browsers don't agree on whether a closed
|
|
217
|
+
* `<details>` prints its content.
|
|
218
|
+
*/
|
|
219
|
+
const TOGGLE_SCRIPT = `<script>
|
|
220
|
+
(function(){
|
|
221
|
+
var btn=document.querySelector(".xall");
|
|
222
|
+
var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
|
|
223
|
+
if(!btn||!secs.length)return;
|
|
224
|
+
var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
|
|
225
|
+
btn.hidden=false;
|
|
226
|
+
btn.addEventListener("click",function(){
|
|
227
|
+
var open=!secs.every(function(d){return d.open});
|
|
228
|
+
secs.forEach(function(d){d.open=open});sync();
|
|
229
|
+
});
|
|
230
|
+
secs.forEach(function(d){d.addEventListener("toggle",sync)});
|
|
231
|
+
var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
|
|
232
|
+
addEventListener("hashchange",openHash);openHash();
|
|
233
|
+
var pre=[];
|
|
234
|
+
addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
|
|
235
|
+
addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
|
|
236
|
+
sync();
|
|
237
|
+
})();
|
|
238
|
+
</script>`;
|
package/dist/server.js
CHANGED
|
@@ -82,6 +82,8 @@ export function createServer(root = ROOT) {
|
|
|
82
82
|
tools: [
|
|
83
83
|
{
|
|
84
84
|
name: "read_agents_md",
|
|
85
|
+
title: "Read AGENTS.md",
|
|
86
|
+
annotations: { title: "Read AGENTS.md", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
85
87
|
description: "Return this project's AGENTS.md — the whole file, or one section by heading. The instructions a client would otherwise have to know to look for and read wholesale.",
|
|
86
88
|
inputSchema: {
|
|
87
89
|
type: "object",
|
|
@@ -95,16 +97,22 @@ export function createServer(root = ROOT) {
|
|
|
95
97
|
},
|
|
96
98
|
{
|
|
97
99
|
name: "author_agents_md",
|
|
100
|
+
title: "Draft an AGENTS.md",
|
|
101
|
+
annotations: { title: "Draft an AGENTS.md", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
98
102
|
description: "Author an AGENTS.md for this project and return the draft — BETTER from repo facts alone (via agents-md-facts: real build/test commands, entry points, toolchain conventions, nothing invented), or BEST when a project.faf exists (facts plus its structured goal/who/why as a second managed block ahead of them). Does not write a file.",
|
|
99
103
|
inputSchema: { type: "object", properties: {} },
|
|
100
104
|
},
|
|
101
105
|
{
|
|
102
106
|
name: "list_agents_md_sections",
|
|
107
|
+
title: "List AGENTS.md Sections",
|
|
108
|
+
annotations: { title: "List AGENTS.md Sections", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
103
109
|
description: "List the headings in this project's AGENTS.md, so a client can pull one section instead of spending context on the whole file.",
|
|
104
110
|
inputSchema: { type: "object", properties: {} },
|
|
105
111
|
},
|
|
106
112
|
{
|
|
107
113
|
name: "remember",
|
|
114
|
+
title: "Remember a Fact",
|
|
115
|
+
annotations: { title: "Remember a Fact", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
108
116
|
description: "Persist a fact past the session boundary — written to a .fafm file, not held in memory. Reusing an existing id replaces that fact's text in place (no duplicate); a new id appends. Facts are written verification_status: unverified.",
|
|
109
117
|
inputSchema: {
|
|
110
118
|
type: "object",
|
|
@@ -123,6 +131,8 @@ export function createServer(root = ROOT) {
|
|
|
123
131
|
},
|
|
124
132
|
{
|
|
125
133
|
name: "recall",
|
|
134
|
+
title: "Recall a Fact",
|
|
135
|
+
annotations: { title: "Recall a Fact", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
126
136
|
description: "Retrieve a fact stored in a previous session by id. Exact lookup — not fuzzy or substring.",
|
|
127
137
|
inputSchema: {
|
|
128
138
|
type: "object",
|
|
@@ -137,6 +147,8 @@ export function createServer(root = ROOT) {
|
|
|
137
147
|
},
|
|
138
148
|
{
|
|
139
149
|
name: "forget",
|
|
150
|
+
title: "Forget a Fact",
|
|
151
|
+
annotations: { title: "Forget a Fact", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
140
152
|
description: "Remove a fact by id — to correct or drop something stale. A missing id is reported, not an error.",
|
|
141
153
|
inputSchema: {
|
|
142
154
|
type: "object",
|
|
@@ -151,22 +163,29 @@ export function createServer(root = ROOT) {
|
|
|
151
163
|
},
|
|
152
164
|
{
|
|
153
165
|
name: "whoami",
|
|
166
|
+
title: "Who Am I",
|
|
167
|
+
annotations: { title: "Who Am I", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
154
168
|
description: "This server's own identity — name, vendor, version, status, license — from its .fafa card.",
|
|
155
169
|
inputSchema: { type: "object", properties: {} },
|
|
156
170
|
},
|
|
157
171
|
{
|
|
158
172
|
name: "list_context_sources",
|
|
173
|
+
title: "List Context Sources",
|
|
174
|
+
annotations: { title: "List Context Sources", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
159
175
|
description: "What context does this project publish (AGENTS.md, memory, identity), in what media types, and through which discovery surface. For a client connecting cold.",
|
|
160
176
|
inputSchema: { type: "object", properties: {} },
|
|
161
177
|
},
|
|
162
178
|
{
|
|
163
179
|
name: "render_context_card",
|
|
164
|
-
|
|
180
|
+
title: "Render Context Card",
|
|
181
|
+
annotations: { title: "Render Context Card", readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
182
|
+
description: "Render the whole card — identity, AGENTS.md, memory, discovery — as one self-contained HTML page a person can read or screenshot. AGENTS.md sections collapse by default; pass expanded:true for the full render. Also served at GET /card (?expand=all) over the HTTP transport.",
|
|
165
183
|
inputSchema: {
|
|
166
184
|
type: "object",
|
|
167
185
|
properties: {
|
|
168
186
|
theme: { type: "string", enum: ["light", "dark", "auto"], description: "default: auto" },
|
|
169
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)" },
|
|
170
189
|
},
|
|
171
190
|
},
|
|
172
191
|
},
|
|
@@ -215,7 +234,8 @@ export function createServer(root = ROOT) {
|
|
|
215
234
|
}
|
|
216
235
|
case "whoami":
|
|
217
236
|
return text(whoami(root));
|
|
218
|
-
case "render_context_card":
|
|
237
|
+
case "render_context_card": {
|
|
238
|
+
const rawExpanded = args.expanded;
|
|
219
239
|
return {
|
|
220
240
|
content: [
|
|
221
241
|
{
|
|
@@ -223,10 +243,12 @@ export function createServer(root = ROOT) {
|
|
|
223
243
|
text: renderCard(root, {
|
|
224
244
|
theme: (["light", "dark", "auto"].includes(args.theme) ? args.theme : "auto"),
|
|
225
245
|
accent: safeAccent(args.accent),
|
|
246
|
+
expanded: rawExpanded === true || rawExpanded === "true",
|
|
226
247
|
}),
|
|
227
248
|
},
|
|
228
249
|
],
|
|
229
250
|
};
|
|
251
|
+
}
|
|
230
252
|
case "list_context_sources": {
|
|
231
253
|
const doc = parseAgentsMd(AGENTS);
|
|
232
254
|
const mem = parseFafm(FAFM);
|
package/dist/transport/http.js
CHANGED
|
@@ -56,7 +56,7 @@ export function httpApp(root = ROOT) {
|
|
|
56
56
|
const q = c.req.query();
|
|
57
57
|
const theme = (["light", "dark", "auto"].includes(q.theme ?? "") ? q.theme : "auto");
|
|
58
58
|
c.header("content-type", "text/html; charset=utf-8");
|
|
59
|
-
return c.body(renderCard(root, { theme, accent: safeAccent(q.accent) }));
|
|
59
|
+
return c.body(renderCard(root, { theme, accent: safeAccent(q.accent), expanded: q.expand === "all" }));
|
|
60
60
|
});
|
|
61
61
|
// ── Index ───────────────────────────────────────────────────────────
|
|
62
62
|
app.get("/", (c) => c.json({
|
package/docs/MECHANISMS.md
CHANGED
package/docs/card-dark.html
CHANGED
|
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
30
30
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
31
|
padding:40px 18px}
|
|
32
32
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
-
border-radius:14px;overflow:
|
|
33
|
+
border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
|
|
34
34
|
.card>*{padding:26px 30px}
|
|
35
35
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
36
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
|
|
|
41
41
|
section:last-child{border-bottom:0}
|
|
42
42
|
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
43
|
color:var(--accent);margin:0 0 14px}
|
|
44
|
-
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
|
|
45
45
|
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
46
|
.toc a:hover{color:var(--accent)}
|
|
47
|
+
/* ── collapsible context ─────────────────────────────────────────── */
|
|
48
|
+
.ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
|
|
49
|
+
margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
|
|
50
|
+
display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
|
|
51
|
+
.xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
|
|
52
|
+
white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
|
|
53
|
+
background:var(--chip);color:var(--muted);cursor:pointer}
|
|
54
|
+
.xall:hover{color:var(--accent);border-color:var(--accent)}
|
|
55
|
+
.ctx-preamble{padding-bottom:4px}
|
|
56
|
+
details.ctx-section{border-top:1px solid var(--line)}
|
|
57
|
+
details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
|
|
58
|
+
font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
|
|
59
|
+
details.ctx-section>summary::-webkit-details-marker{display:none}
|
|
60
|
+
details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
|
|
61
|
+
transition:transform .15s ease}
|
|
62
|
+
details.ctx-section[open]>summary::before{transform:rotate(90deg)}
|
|
63
|
+
details.ctx-section>.md{padding:0 0 16px}
|
|
64
|
+
@media print{
|
|
65
|
+
.ctx-nav{display:none}
|
|
66
|
+
details.ctx-section:not([open])>.md{display:block!important}
|
|
67
|
+
details.ctx-section>summary::before{content:""}
|
|
68
|
+
}
|
|
47
69
|
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
70
|
.md h1{font-size:1.15rem}
|
|
49
71
|
.md p{margin:8px 0}
|
|
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
|
|
|
78
100
|
<main class="card">
|
|
79
101
|
<div class="top">
|
|
80
102
|
<h1>mcp-context-card</h1>
|
|
81
|
-
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.
|
|
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>
|
|
82
104
|
</div>
|
|
83
105
|
<section>
|
|
84
106
|
<p class="label">Context — AGENTS.md</p>
|
|
85
|
-
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><
|
|
86
|
-
<p><code>
|
|
87
|
-
<
|
|
88
|
-
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
-
<p>Node
|
|
90
|
-
|
|
91
|
-
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
-
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
-
<h2 id="test">Test</h2>
|
|
94
|
-
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
107
|
+
<div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
|
|
108
|
+
<div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
109
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
|
|
110
|
+
<div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
|
|
111
|
+
<p>Node 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/
|
|
112
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
113
|
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
114
|
npm run demo # end to end: all tools over stdio, then over stateless HTTP
|
|
97
115
|
npm run version:check # every version-bearing spot agrees with package.json
|
|
98
116
|
npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
|
|
99
|
-
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
|
|
100
|
-
<h2 id="layout">Layout</h2>
|
|
101
|
-
<table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
|
|
102
|
-
<h2 id="conventions">Conventions</h2>
|
|
103
|
-
<ul><li>TypeScript strict, ESM only (<code>"type": "module"</code>, <code>.js</code> import specifiers).</li><li>Tests use <code>node:test</code> + <code>node:assert/strict</code> — no test framework.</li><li>Every source file opens with a comment stating what it is and why.</li><li>Conventional Commit messages (<code>feat:</code>, <code>fix:</code>, <code>chore:</code>, <code>test:</code>, <code>docs:</code>).</li></ul>
|
|
104
|
-
<h2 id="the-invariant">The invariant</h2>
|
|
105
|
-
<p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
|
|
106
|
-
<h2 id="safety">Safety</h2>
|
|
107
|
-
<ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
|
|
108
|
-
<h2 id="definition-of-done">Definition of done</h2>
|
|
109
|
-
<p><code>npm run typecheck && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
|
|
110
|
-
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
111
|
-
<p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
|
|
117
|
+
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><ul><li>TypeScript strict, ESM only (<code>"type": "module"</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 && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div></details></div>
|
|
112
118
|
</section>
|
|
113
119
|
<section>
|
|
114
120
|
<p class="label">Memory — 4 facts</p>
|
|
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
|
|
|
124
130
|
</section>
|
|
125
131
|
<div class="foot">mcp-context-card · context card</div>
|
|
126
132
|
</main>
|
|
133
|
+
<script>
|
|
134
|
+
(function(){
|
|
135
|
+
var btn=document.querySelector(".xall");
|
|
136
|
+
var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
|
|
137
|
+
if(!btn||!secs.length)return;
|
|
138
|
+
var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
|
|
139
|
+
btn.hidden=false;
|
|
140
|
+
btn.addEventListener("click",function(){
|
|
141
|
+
var open=!secs.every(function(d){return d.open});
|
|
142
|
+
secs.forEach(function(d){d.open=open});sync();
|
|
143
|
+
});
|
|
144
|
+
secs.forEach(function(d){d.addEventListener("toggle",sync)});
|
|
145
|
+
var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
|
|
146
|
+
addEventListener("hashchange",openHash);openHash();
|
|
147
|
+
var pre=[];
|
|
148
|
+
addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
|
|
149
|
+
addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
|
|
150
|
+
sync();
|
|
151
|
+
})();
|
|
152
|
+
</script>
|
|
127
153
|
</body>
|
|
128
154
|
</html>
|
package/docs/card-light.html
CHANGED
|
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
30
30
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
31
|
padding:40px 18px}
|
|
32
32
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
-
border-radius:14px;overflow:
|
|
33
|
+
border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
|
|
34
34
|
.card>*{padding:26px 30px}
|
|
35
35
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
36
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
|
|
|
41
41
|
section:last-child{border-bottom:0}
|
|
42
42
|
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
43
|
color:var(--accent);margin:0 0 14px}
|
|
44
|
-
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
|
|
45
45
|
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
46
|
.toc a:hover{color:var(--accent)}
|
|
47
|
+
/* ── collapsible context ─────────────────────────────────────────── */
|
|
48
|
+
.ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
|
|
49
|
+
margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
|
|
50
|
+
display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
|
|
51
|
+
.xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
|
|
52
|
+
white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
|
|
53
|
+
background:var(--chip);color:var(--muted);cursor:pointer}
|
|
54
|
+
.xall:hover{color:var(--accent);border-color:var(--accent)}
|
|
55
|
+
.ctx-preamble{padding-bottom:4px}
|
|
56
|
+
details.ctx-section{border-top:1px solid var(--line)}
|
|
57
|
+
details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
|
|
58
|
+
font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
|
|
59
|
+
details.ctx-section>summary::-webkit-details-marker{display:none}
|
|
60
|
+
details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
|
|
61
|
+
transition:transform .15s ease}
|
|
62
|
+
details.ctx-section[open]>summary::before{transform:rotate(90deg)}
|
|
63
|
+
details.ctx-section>.md{padding:0 0 16px}
|
|
64
|
+
@media print{
|
|
65
|
+
.ctx-nav{display:none}
|
|
66
|
+
details.ctx-section:not([open])>.md{display:block!important}
|
|
67
|
+
details.ctx-section>summary::before{content:""}
|
|
68
|
+
}
|
|
47
69
|
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
70
|
.md h1{font-size:1.15rem}
|
|
49
71
|
.md p{margin:8px 0}
|
|
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
|
|
|
78
100
|
<main class="card">
|
|
79
101
|
<div class="top">
|
|
80
102
|
<h1>mcp-context-card</h1>
|
|
81
|
-
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.
|
|
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>
|
|
82
104
|
</div>
|
|
83
105
|
<section>
|
|
84
106
|
<p class="label">Context — AGENTS.md</p>
|
|
85
|
-
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><
|
|
86
|
-
<p><code>
|
|
87
|
-
<
|
|
88
|
-
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
-
<p>Node
|
|
90
|
-
|
|
91
|
-
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
-
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
-
<h2 id="test">Test</h2>
|
|
94
|
-
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
107
|
+
<div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
|
|
108
|
+
<div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
109
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
|
|
110
|
+
<div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
|
|
111
|
+
<p>Node 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/
|
|
112
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
113
|
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
114
|
npm run demo # end to end: all tools over stdio, then over stateless HTTP
|
|
97
115
|
npm run version:check # every version-bearing spot agrees with package.json
|
|
98
116
|
npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
|
|
99
|
-
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
|
|
100
|
-
<h2 id="layout">Layout</h2>
|
|
101
|
-
<table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
|
|
102
|
-
<h2 id="conventions">Conventions</h2>
|
|
103
|
-
<ul><li>TypeScript strict, ESM only (<code>"type": "module"</code>, <code>.js</code> import specifiers).</li><li>Tests use <code>node:test</code> + <code>node:assert/strict</code> — no test framework.</li><li>Every source file opens with a comment stating what it is and why.</li><li>Conventional Commit messages (<code>feat:</code>, <code>fix:</code>, <code>chore:</code>, <code>test:</code>, <code>docs:</code>).</li></ul>
|
|
104
|
-
<h2 id="the-invariant">The invariant</h2>
|
|
105
|
-
<p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
|
|
106
|
-
<h2 id="safety">Safety</h2>
|
|
107
|
-
<ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
|
|
108
|
-
<h2 id="definition-of-done">Definition of done</h2>
|
|
109
|
-
<p><code>npm run typecheck && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
|
|
110
|
-
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
111
|
-
<p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
|
|
117
|
+
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><ul><li>TypeScript strict, ESM only (<code>"type": "module"</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 && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div></details></div>
|
|
112
118
|
</section>
|
|
113
119
|
<section>
|
|
114
120
|
<p class="label">Memory — 4 facts</p>
|
|
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
|
|
|
124
130
|
</section>
|
|
125
131
|
<div class="foot">mcp-context-card · context card</div>
|
|
126
132
|
</main>
|
|
133
|
+
<script>
|
|
134
|
+
(function(){
|
|
135
|
+
var btn=document.querySelector(".xall");
|
|
136
|
+
var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
|
|
137
|
+
if(!btn||!secs.length)return;
|
|
138
|
+
var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
|
|
139
|
+
btn.hidden=false;
|
|
140
|
+
btn.addEventListener("click",function(){
|
|
141
|
+
var open=!secs.every(function(d){return d.open});
|
|
142
|
+
secs.forEach(function(d){d.open=open});sync();
|
|
143
|
+
});
|
|
144
|
+
secs.forEach(function(d){d.addEventListener("toggle",sync)});
|
|
145
|
+
var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
|
|
146
|
+
addEventListener("hashchange",openHash);openHash();
|
|
147
|
+
var pre=[];
|
|
148
|
+
addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
|
|
149
|
+
addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
|
|
150
|
+
sync();
|
|
151
|
+
})();
|
|
152
|
+
</script>
|
|
127
153
|
</body>
|
|
128
154
|
</html>
|
package/docs/card.html
CHANGED
|
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
30
30
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
31
|
padding:40px 18px}
|
|
32
32
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
-
border-radius:14px;overflow:
|
|
33
|
+
border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
|
|
34
34
|
.card>*{padding:26px 30px}
|
|
35
35
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
36
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
|
|
|
41
41
|
section:last-child{border-bottom:0}
|
|
42
42
|
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
43
|
color:var(--accent);margin:0 0 14px}
|
|
44
|
-
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
|
|
45
45
|
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
46
|
.toc a:hover{color:var(--accent)}
|
|
47
|
+
/* ── collapsible context ─────────────────────────────────────────── */
|
|
48
|
+
.ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
|
|
49
|
+
margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
|
|
50
|
+
display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
|
|
51
|
+
.xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
|
|
52
|
+
white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
|
|
53
|
+
background:var(--chip);color:var(--muted);cursor:pointer}
|
|
54
|
+
.xall:hover{color:var(--accent);border-color:var(--accent)}
|
|
55
|
+
.ctx-preamble{padding-bottom:4px}
|
|
56
|
+
details.ctx-section{border-top:1px solid var(--line)}
|
|
57
|
+
details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
|
|
58
|
+
font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
|
|
59
|
+
details.ctx-section>summary::-webkit-details-marker{display:none}
|
|
60
|
+
details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
|
|
61
|
+
transition:transform .15s ease}
|
|
62
|
+
details.ctx-section[open]>summary::before{transform:rotate(90deg)}
|
|
63
|
+
details.ctx-section>.md{padding:0 0 16px}
|
|
64
|
+
@media print{
|
|
65
|
+
.ctx-nav{display:none}
|
|
66
|
+
details.ctx-section:not([open])>.md{display:block!important}
|
|
67
|
+
details.ctx-section>summary::before{content:""}
|
|
68
|
+
}
|
|
47
69
|
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
70
|
.md h1{font-size:1.15rem}
|
|
49
71
|
.md p{margin:8px 0}
|
|
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
|
|
|
78
100
|
<main class="card">
|
|
79
101
|
<div class="top">
|
|
80
102
|
<h1>mcp-context-card</h1>
|
|
81
|
-
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.
|
|
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>
|
|
82
104
|
</div>
|
|
83
105
|
<section>
|
|
84
106
|
<p class="label">Context — AGENTS.md</p>
|
|
85
|
-
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><
|
|
86
|
-
<p><code>
|
|
87
|
-
<
|
|
88
|
-
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
-
<p>Node
|
|
90
|
-
|
|
91
|
-
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
-
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
-
<h2 id="test">Test</h2>
|
|
94
|
-
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
107
|
+
<div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
|
|
108
|
+
<div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
109
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
|
|
110
|
+
<div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
|
|
111
|
+
<p>Node 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/
|
|
112
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
113
|
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
114
|
npm run demo # end to end: all tools over stdio, then over stateless HTTP
|
|
97
115
|
npm run version:check # every version-bearing spot agrees with package.json
|
|
98
116
|
npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
|
|
99
|
-
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
|
|
100
|
-
<h2 id="layout">Layout</h2>
|
|
101
|
-
<table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
|
|
102
|
-
<h2 id="conventions">Conventions</h2>
|
|
103
|
-
<ul><li>TypeScript strict, ESM only (<code>"type": "module"</code>, <code>.js</code> import specifiers).</li><li>Tests use <code>node:test</code> + <code>node:assert/strict</code> — no test framework.</li><li>Every source file opens with a comment stating what it is and why.</li><li>Conventional Commit messages (<code>feat:</code>, <code>fix:</code>, <code>chore:</code>, <code>test:</code>, <code>docs:</code>).</li></ul>
|
|
104
|
-
<h2 id="the-invariant">The invariant</h2>
|
|
105
|
-
<p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
|
|
106
|
-
<h2 id="safety">Safety</h2>
|
|
107
|
-
<ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
|
|
108
|
-
<h2 id="definition-of-done">Definition of done</h2>
|
|
109
|
-
<p><code>npm run typecheck && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
|
|
110
|
-
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
111
|
-
<p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
|
|
117
|
+
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><ul><li>TypeScript strict, ESM only (<code>"type": "module"</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 && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div></details></div>
|
|
112
118
|
</section>
|
|
113
119
|
<section>
|
|
114
120
|
<p class="label">Memory — 4 facts</p>
|
|
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
|
|
|
124
130
|
</section>
|
|
125
131
|
<div class="foot">mcp-context-card · context card</div>
|
|
126
132
|
</main>
|
|
133
|
+
<script>
|
|
134
|
+
(function(){
|
|
135
|
+
var btn=document.querySelector(".xall");
|
|
136
|
+
var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
|
|
137
|
+
if(!btn||!secs.length)return;
|
|
138
|
+
var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
|
|
139
|
+
btn.hidden=false;
|
|
140
|
+
btn.addEventListener("click",function(){
|
|
141
|
+
var open=!secs.every(function(d){return d.open});
|
|
142
|
+
secs.forEach(function(d){d.open=open});sync();
|
|
143
|
+
});
|
|
144
|
+
secs.forEach(function(d){d.addEventListener("toggle",sync)});
|
|
145
|
+
var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
|
|
146
|
+
addEventListener("hashchange",openHash);openHash();
|
|
147
|
+
var pre=[];
|
|
148
|
+
addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
|
|
149
|
+
addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
|
|
150
|
+
sync();
|
|
151
|
+
})();
|
|
152
|
+
</script>
|
|
127
153
|
</body>
|
|
128
154
|
</html>
|
package/docs/img/card-dark.png
CHANGED
|
Binary file
|
|
Binary file
|
package/docs/img/card-light.png
CHANGED
|
Binary file
|
package/docs/index.html
CHANGED
|
@@ -30,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
30
30
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
31
|
padding:40px 18px}
|
|
32
32
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
-
border-radius:14px;overflow:
|
|
33
|
+
border-radius:14px;overflow:clip;box-shadow:var(--card-shadow)}
|
|
34
34
|
.card>*{padding:26px 30px}
|
|
35
35
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
36
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -41,9 +41,31 @@ section{border-bottom:1px solid var(--line)}
|
|
|
41
41
|
section:last-child{border-bottom:0}
|
|
42
42
|
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
43
|
color:var(--accent);margin:0 0 14px}
|
|
44
|
-
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0;padding:0;list-style:none}
|
|
45
45
|
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
46
|
.toc a:hover{color:var(--accent)}
|
|
47
|
+
/* ── collapsible context ─────────────────────────────────────────── */
|
|
48
|
+
.ctx-nav{position:sticky;top:0;z-index:3;background:var(--card);
|
|
49
|
+
margin:0 -30px 16px;padding:11px 30px;border-bottom:1px solid var(--line);
|
|
50
|
+
display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 16px}
|
|
51
|
+
.xall{margin-left:auto;flex:none;font:inherit;font-size:.76rem;font-weight:600;
|
|
52
|
+
white-space:nowrap;padding:3px 11px;border-radius:20px;border:1px solid var(--line);
|
|
53
|
+
background:var(--chip);color:var(--muted);cursor:pointer}
|
|
54
|
+
.xall:hover{color:var(--accent);border-color:var(--accent)}
|
|
55
|
+
.ctx-preamble{padding-bottom:4px}
|
|
56
|
+
details.ctx-section{border-top:1px solid var(--line)}
|
|
57
|
+
details.ctx-section>summary{cursor:pointer;list-style:none;padding:11px 0;
|
|
58
|
+
font-weight:600;font-size:1rem;letter-spacing:-.01em;display:flex;gap:9px}
|
|
59
|
+
details.ctx-section>summary::-webkit-details-marker{display:none}
|
|
60
|
+
details.ctx-section>summary::before{content:"›";color:var(--accent);font-weight:700;
|
|
61
|
+
transition:transform .15s ease}
|
|
62
|
+
details.ctx-section[open]>summary::before{transform:rotate(90deg)}
|
|
63
|
+
details.ctx-section>.md{padding:0 0 16px}
|
|
64
|
+
@media print{
|
|
65
|
+
.ctx-nav{display:none}
|
|
66
|
+
details.ctx-section:not([open])>.md{display:block!important}
|
|
67
|
+
details.ctx-section>summary::before{content:""}
|
|
68
|
+
}
|
|
47
69
|
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
70
|
.md h1{font-size:1.15rem}
|
|
49
71
|
.md p{margin:8px 0}
|
|
@@ -78,37 +100,21 @@ section:last-child{border-bottom:0}
|
|
|
78
100
|
<main class="card">
|
|
79
101
|
<div class="top">
|
|
80
102
|
<h1>mcp-context-card</h1>
|
|
81
|
-
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v1.
|
|
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>
|
|
82
104
|
</div>
|
|
83
105
|
<section>
|
|
84
106
|
<p class="label">Context — AGENTS.md</p>
|
|
85
|
-
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><
|
|
86
|
-
<p><code>
|
|
87
|
-
<
|
|
88
|
-
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
-
<p>Node
|
|
90
|
-
|
|
91
|
-
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
-
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
-
<h2 id="test">Test</h2>
|
|
94
|
-
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
107
|
+
<div class="ctx-nav"><ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><button type="button" class="xall" hidden>Expand all</button></div>
|
|
108
|
+
<div class="ctx-preamble md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
109
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p></div>
|
|
110
|
+
<div class="ctx-body"><details class="ctx-section" id="setup"><summary>Setup</summary><div class="md"><pre><code class="language-bash">npm ci</code></pre>
|
|
111
|
+
<p>Node 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/
|
|
112
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre></div></details><details class="ctx-section" id="test"><summary>Test</summary><div class="md"><pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
113
|
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
114
|
npm run demo # end to end: all tools over stdio, then over stateless HTTP
|
|
97
115
|
npm run version:check # every version-bearing spot agrees with package.json
|
|
98
116
|
npm run faf:check # project.faf / project.fafm / .well-known/fafa still describe the project</code></pre>
|
|
99
|
-
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p>
|
|
100
|
-
<h2 id="layout">Layout</h2>
|
|
101
|
-
<table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table>
|
|
102
|
-
<h2 id="conventions">Conventions</h2>
|
|
103
|
-
<ul><li>TypeScript strict, ESM only (<code>"type": "module"</code>, <code>.js</code> import specifiers).</li><li>Tests use <code>node:test</code> + <code>node:assert/strict</code> — no test framework.</li><li>Every source file opens with a comment stating what it is and why.</li><li>Conventional Commit messages (<code>feat:</code>, <code>fix:</code>, <code>chore:</code>, <code>test:</code>, <code>docs:</code>).</li></ul>
|
|
104
|
-
<h2 id="the-invariant">The invariant</h2>
|
|
105
|
-
<p><code>src/identity.ts</code>, <code>src/catalog-gen.ts</code>, and <code>src/render-card.ts</code> all describe the <strong>same three sources</strong>: this file, <code>project.fafm</code>, <code>.well-known/fafa</code>. Change what one exposes and you must change the others. <code>npm run catalog:check</code> and <code>npm run card:check</code> enforce it in CI — each regenerates its surface and fails on any diff.</p>
|
|
106
|
-
<h2 id="safety">Safety</h2>
|
|
107
|
-
<ul><li>Branch off <code>main</code>; CI must be green before merge.</li><li><code>npm run demo</code> writes a fact to <code>project.fafm</code> and restores the file on exit — don't kill it mid-run.</li><li>No secrets live in this repo; never add any.</li></ul>
|
|
108
|
-
<h2 id="definition-of-done">Definition of done</h2>
|
|
109
|
-
<p><code>npm run typecheck && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p>
|
|
110
|
-
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
111
|
-
<p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div>
|
|
117
|
+
<p>CI runs <code>version:check → faf:check → typecheck → build → test:coverage → demo</code> on Linux, macOS, and Windows for every push and PR to <code>main</code> (<code>.github/workflows/ci.yml</code>), plus <code>catalog:check</code> / <code>card:check</code>, <code>faf-cli check project.faf --strict</code> (the repo dogfoods a <code>project.faf</code> — this keeps it Trophy), and <code>faf:nudge</code> (PR-only, non-blocking — warns if the code's shape moved without <code>project.faf</code>) on Linux.</p></div></details><details class="ctx-section" id="layout"><summary>Layout</summary><div class="md"><table><thead><tr><th>Path</th><th>What</th></tr></thead><tbody><tr><td><code>src/server.ts</code></td><td>the MCP server — the nine tools + the Server Card resource</td></tr><tr><td><code>src/agents-md.ts</code></td><td>reads and section-splits this file</td></tr><tr><td><code>src/author.ts</code></td><td><code>author_agents_md</code> — BETTER via <code>agents-md-facts</code>, BEST when <code>project.faf</code> exists</td></tr><tr><td><code>src/md.ts</code></td><td>a minimal dependency-free Markdown → HTML renderer</td></tr><tr><td><code>src/render-card.ts</code></td><td>the card — identity + this file + memory + discovery, as one HTML page</td></tr><tr><td><code>src/memory.ts</code> → <code>src/faf/parse-fafm.ts</code></td><td>file-backed <code>remember</code> / <code>recall</code> / <code>forget</code></td></tr><tr><td><code>src/identity.ts</code></td><td><code>whoami</code> (<code>.fafa</code> → <code>package.json</code> fallback) + the <code>_meta</code> context block</td></tr><tr><td><code>src/catalog-gen.ts</code></td><td>writes <code>.well-known/ai-catalog.json</code> from the same three sources</td></tr><tr><td><code>src/transport/http.ts</code></td><td>the stateless Streamable HTTP app (Hono)</td></tr><tr><td><code>src/bin.ts</code></td><td>the entry point (<code>resolveLaunch</code>) — <code>stdio</code> · <code>--http</code> · <code>card</code> · <code>--help</code> · <code>--version</code></td></tr><tr><td><code>src/faf/parse-fafm.ts</code> · <code>parse-fafa.ts</code></td><td>the <code>.fafm</code> / <code>.fafa</code> parsers</td></tr></tbody></table></div></details><details class="ctx-section" id="conventions"><summary>Conventions</summary><div class="md"><ul><li>TypeScript strict, ESM only (<code>"type": "module"</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 && npm run build && npm test && npm run demo</code> all green, plus <code>npm run catalog:check</code> and <code>npm run card:check</code> clean if you touched <code>AGENTS.md</code>, <code>project.fafm</code>, or <code>.well-known/fafa</code>, and <code>npm run faf:check</code> green if you changed the layout, a dependency, or the identity. On a version bump, <code>npm run version:check</code> green (it lists every spot that must move together) and <code>project.faf</code> still Trophy (<code>faf-cli check project.faf --strict</code>). If CI's <code>faf:nudge</code> warns on your PR, reconcile <code>project.faf</code> (and re-check <code>project.fafm</code> facts if <code>AGENTS.md</code> moved) or say why it's fine.</p></div></details><details class="ctx-section" id="authoring-this-file"><summary>Authoring this file</summary><div class="md"><p><code>AGENTS.md</code> here is maintained by hand. The <code>author_agents_md</code> tool (or <code>faf export --agents</code>) would draft a BEST version straight from this repo's own <code>project.faf</code> plus its detected facts — the server doesn't care how the file was authored, only that it's valid Markdown.</p></div></details></div>
|
|
112
118
|
</section>
|
|
113
119
|
<section>
|
|
114
120
|
<p class="label">Memory — 4 facts</p>
|
|
@@ -124,5 +130,25 @@ npm run faf:check # project.faf / project.fafm / .well-known/fafa still desc
|
|
|
124
130
|
</section>
|
|
125
131
|
<div class="foot">mcp-context-card · context card</div>
|
|
126
132
|
</main>
|
|
133
|
+
<script>
|
|
134
|
+
(function(){
|
|
135
|
+
var btn=document.querySelector(".xall");
|
|
136
|
+
var secs=[].slice.call(document.querySelectorAll("details.ctx-section"));
|
|
137
|
+
if(!btn||!secs.length)return;
|
|
138
|
+
var sync=function(){btn.textContent=secs.every(function(d){return d.open})?"Collapse all":"Expand all"};
|
|
139
|
+
btn.hidden=false;
|
|
140
|
+
btn.addEventListener("click",function(){
|
|
141
|
+
var open=!secs.every(function(d){return d.open});
|
|
142
|
+
secs.forEach(function(d){d.open=open});sync();
|
|
143
|
+
});
|
|
144
|
+
secs.forEach(function(d){d.addEventListener("toggle",sync)});
|
|
145
|
+
var openHash=function(){var d=document.getElementById(location.hash.slice(1));if(d&&d.tagName==="DETAILS")d.open=true};
|
|
146
|
+
addEventListener("hashchange",openHash);openHash();
|
|
147
|
+
var pre=[];
|
|
148
|
+
addEventListener("beforeprint",function(){pre=secs.map(function(d){return d.open});secs.forEach(function(d){d.open=true})});
|
|
149
|
+
addEventListener("afterprint",function(){secs.forEach(function(d,i){d.open=pre[i]});sync()});
|
|
150
|
+
sync();
|
|
151
|
+
})();
|
|
152
|
+
</script>
|
|
127
153
|
</body>
|
|
128
154
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-context-card",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.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": [
|
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
|
+
"version": "1.1.1",
|
|
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.
|
|
16
|
+
"version": "1.1.1",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|