mcp-context-card 0.5.2 → 0.6.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/ai-catalog.json +2 -2
- package/.well-known/fafa +2 -2
- package/CHANGELOG.md +81 -2
- package/README.md +47 -29
- package/dist/bin.d.ts +1 -1
- package/dist/card-gen.js +15 -2
- package/dist/catalog-gen.d.ts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/identity.d.ts +4 -4
- package/dist/identity.js +1 -1
- package/dist/render-card.js +6 -1
- package/dist/server.d.ts +3 -3
- package/docs/MECHANISMS.md +22 -5
- package/docs/WIRING.md +2 -2
- package/docs/card-dark.html +126 -0
- package/docs/card-light.html +126 -0
- package/docs/card.html +7 -2
- package/docs/img/card-context.png +0 -0
- 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/img/card-memory.png +0 -0
- package/docs/index.html +126 -0
- package/package.json +3 -3
- package/server.json +7 -7
- package/docs/img/card.png +0 -0
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"description": "Cross-session memory — 4 fact(s), profile \"knowledge\". Recall survives a process restart. No de-facto standard for this concern yet.",
|
|
22
22
|
"url": "./project.fafm",
|
|
23
23
|
"_meta": {
|
|
24
|
-
"io.github.
|
|
24
|
+
"io.github.Wolfe-Jam.mcp-context-card/iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
{
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"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 a self-published ai-catalog.json.",
|
|
33
33
|
"url": "./.well-known/fafa",
|
|
34
34
|
"_meta": {
|
|
35
|
-
"io.github.
|
|
35
|
+
"io.github.Wolfe-Jam.mcp-context-card/iana": "https://www.iana.org/assignments/media-types/application/vnd.fafa+yaml"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
]
|
package/.well-known/fafa
CHANGED
|
@@ -8,8 +8,8 @@ version: "1.0"
|
|
|
8
8
|
agent:
|
|
9
9
|
name: "mcp-context-card"
|
|
10
10
|
displayName: "mcp-context-card"
|
|
11
|
-
vendor: "io.github.
|
|
12
|
-
version: "0.
|
|
11
|
+
vendor: "io.github.Wolfe-Jam"
|
|
12
|
+
version: "0.6.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,85 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project. Adheres to [Semantic Versioning](https://semver.org).
|
|
4
4
|
|
|
5
|
+
## 0.6.1
|
|
6
|
+
|
|
7
|
+
Two real bugs, both caught by the actual `/pubaaif` publish run against
|
|
8
|
+
0.6.0 — not a dry-run this time, the live registry rejected the first
|
|
9
|
+
attempt and the live npm publish shipped the second one wrong.
|
|
10
|
+
|
|
11
|
+
- **Fix: the publisher namespace was wrong-cased everywhere.** Every
|
|
12
|
+
`_meta` key, `server.json.name`, `package.json.mcpName`, and
|
|
13
|
+
`.well-known/fafa`'s `vendor` field used `io.github.wolfe-jam` —
|
|
14
|
+
lowercase. The MCP Registry checks this against the authenticated
|
|
15
|
+
GitHub identity byte-for-byte and rejected the publish: `403`, *"You
|
|
16
|
+
have permission to publish: `io.github.Wolfe-Jam/*`. Attempting to
|
|
17
|
+
publish: `io.github.wolfe-jam/mcp-context-card`."* The real GitHub
|
|
18
|
+
login is `Wolfe-Jam` (capital W, capital J) — an assumption baked in
|
|
19
|
+
since the original `mcp-trinity` rename that the registry lowercases
|
|
20
|
+
GitHub logins for namespace purposes was simply wrong. Fixed at the
|
|
21
|
+
source (`src/identity.ts`'s `META_NS` constant) and everywhere it was
|
|
22
|
+
hand-duplicated (`server.json`, `package.json`, `.well-known/fafa`,
|
|
23
|
+
tests, docs) — the 0.6.0 tarball actually shipped this wrong; anyone
|
|
24
|
+
who installed it got the incorrect namespace in the live `_meta` block.
|
|
25
|
+
- **Fix: `server.json`'s description exceeded the MCP Registry's
|
|
26
|
+
100-character cap.** `mcp-publisher publish` rejected it: `422`,
|
|
27
|
+
`"expected length <= 100"` — ours was 263 characters. Trimmed to 97,
|
|
28
|
+
same claim. `package.json`'s longer description is unaffected — the
|
|
29
|
+
two are allowed to differ.
|
|
30
|
+
- The 3 version-pill card images (`card-dark.png`, `card-light.png`,
|
|
31
|
+
`card-identity.png`) re-shot again — they render the vendor pill text,
|
|
32
|
+
which changed with the casing fix.
|
|
33
|
+
|
|
34
|
+
No functional/behavioral change beyond the corrected namespace. 102/102
|
|
35
|
+
tests, `card:check` + `catalog:check` green.
|
|
36
|
+
|
|
37
|
+
## 0.6.0
|
|
38
|
+
|
|
39
|
+
The README as a hero, not just a description. Everything visual this repo
|
|
40
|
+
claims is now backed by a real screenshot from the actual rendered card —
|
|
41
|
+
nothing hand-drawn, nothing mocked up.
|
|
42
|
+
|
|
43
|
+
- **The card leads the README** — a side-by-side "Light | Dark" table right
|
|
44
|
+
at the top, instead of one fixed screenshot. Shows the real range to
|
|
45
|
+
every viewer regardless of their own GitHub theme.
|
|
46
|
+
- **Each of the three concerns gets its own proof** — context, memory, and
|
|
47
|
+
identity are each followed by a real crop from the card: the `AGENTS.md`
|
|
48
|
+
section + the `read_agents_md` line, an actual tagged and verified
|
|
49
|
+
memory fact, and the title + pills.
|
|
50
|
+
- **"Pick one"** — a table right after the hero: add an `AGENTS.md`,
|
|
51
|
+
improve one to BEST, get a new MCP server base, or extend an MCP you
|
|
52
|
+
already run. Replaces the old "Who it's for" table.
|
|
53
|
+
- The dark card no longer blends into GitHub's own dark mode — added a
|
|
54
|
+
visible ring plus a soft accent-tinted glow so it reads as a distinct
|
|
55
|
+
card regardless of backdrop.
|
|
56
|
+
- **GitHub Pages, live** — `wolfe-jam.github.io/mcp-context-card/` serves
|
|
57
|
+
the card in auto/light/dark. The GitHub repo's own "Website" field links
|
|
58
|
+
there. `package.json`'s `homepage` is a different field and stays on the
|
|
59
|
+
repo itself — that's where install steps and the tools table live, not a
|
|
60
|
+
bare rendered card.
|
|
61
|
+
- "Vendor-free," not "Not tied to FAF" — dropped a defensive clause nobody
|
|
62
|
+
needed, and reworded the vendor-boundary line to state the property
|
|
63
|
+
without naming a vendor to disclaim against.
|
|
64
|
+
- An external README review caught four real gaps, fixed before publish:
|
|
65
|
+
the identity line said "agent card" — reworded to **Server Card**, the
|
|
66
|
+
term this repo already documents and owns (SEP‑2127), so it can't be read
|
|
67
|
+
as A2A's own, distinctly-specified AgentCard; the "Wire it into a host"
|
|
68
|
+
example now states the Node ≥22 requirement and cross-references the
|
|
69
|
+
documented `npx` `ENOENT` fix (Cursor) instead of leaving it undiscoverable
|
|
70
|
+
until WIRING; `docs/WIRING.md`'s `list_agents_md_sections` example showed
|
|
71
|
+
`sections: 9` — the real, parser-verified count is 10 (it includes the
|
|
72
|
+
`AGENTS.md` H1, not just its nine `##` headings).
|
|
73
|
+
- `docs/MECHANISMS.md` states the A2A position: Server Card is what this
|
|
74
|
+
server has. A2A's AgentCard is a different thing — a live agent, an
|
|
75
|
+
endpoint, skills, auth. We're ready for A2A: the same `.fafa` source
|
|
76
|
+
publishes a real AgentCard alongside it the day a project here is
|
|
77
|
+
reachable over one, not a reshape of `.fafa` itself.
|
|
78
|
+
- Bumped straight to 0.6.0 — 0.5.3 was committed but never published;
|
|
79
|
+
no reason to leave a changelog entry for a version nobody received.
|
|
80
|
+
|
|
81
|
+
No functional change — README, docs, and card assets only. 102 tests,
|
|
82
|
+
typecheck/build/demo clean, `card:check` + `catalog:check` green.
|
|
83
|
+
|
|
5
84
|
## 0.5.2
|
|
6
85
|
|
|
7
86
|
The soak, closed out. Two Cursor host checks — a real bug found and fixed, a
|
|
@@ -56,7 +135,7 @@ First-hour ergonomics and wording, from the 0.5.0 soak.
|
|
|
56
135
|
context, memory, and identity discoverable…"). Same in `.well-known/fafa`;
|
|
57
136
|
the three `project.fafm` facts are `type: fact`. `package.json` `author` set
|
|
58
137
|
to the LICENSE holder.
|
|
59
|
-
- `.well-known/fafa` — `vendor: io.github.
|
|
138
|
+
- `.well-known/fafa` — `vendor: io.github.Wolfe-Jam`, `status: published`
|
|
60
139
|
(were both `reference`). Shows in `whoami` and as the card's pills.
|
|
61
140
|
|
|
62
141
|
## 0.5.0
|
|
@@ -88,7 +167,7 @@ tested server.
|
|
|
88
167
|
### Exposure
|
|
89
168
|
|
|
90
169
|
- Server Card `_meta` block — publisher-namespaced keys
|
|
91
|
-
(`io.github.
|
|
170
|
+
(`io.github.Wolfe-Jam.mcp-context-card/{context,memory,identity}`), one per
|
|
92
171
|
concern. `context` points at `AGENTS.md` / `text/markdown`.
|
|
93
172
|
- `mcp-context-card://server-card` MCP resource (in-band) +
|
|
94
173
|
`GET /.well-known/mcp/server-card` (out-of-band, HTTP transport).
|
package/README.md
CHANGED
|
@@ -3,16 +3,38 @@
|
|
|
3
3
|
[](https://github.com/Wolfe-Jam/mcp-context-card/actions/workflows/ci.yml)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
The essential MCP server for a project's
|
|
7
|
-
discoverable to any MCP client, and
|
|
6
|
+
**Get one. Or add it to yours.** The essential MCP server for a project's
|
|
7
|
+
context, memory, and identity — discoverable to any MCP client, and
|
|
8
|
+
rendered as one card you can read.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
| Light | Dark |
|
|
11
|
+
|---|---|
|
|
12
|
+
|  |  |
|
|
13
|
+
|
|
14
|
+
**context** — the project's `AGENTS.md`, served whole or one section at a time.
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
**memory** — facts that persist across sessions, in a file.
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
**identity** — what this server is, from its own Server Card.
|
|
23
|
+
|
|
24
|
+

|
|
12
25
|
|
|
13
26
|
Discovery goes through two surfaces already in the ecosystem: the Server Card
|
|
14
27
|
`_meta` block and `ai-catalog.json` sibling entries.
|
|
15
28
|
|
|
29
|
+
## Pick one
|
|
30
|
+
|
|
31
|
+
| You want to… | |
|
|
32
|
+
|---|---|
|
|
33
|
+
| **Add an `AGENTS.md`** — you don't have one | `author_agents_md` drafts one from your repo's real facts |
|
|
34
|
+
| **Improve an `AGENTS.md`** — you have one, make it the best it can be | the same tool, automatically — drop in a `project.faf` and it upgrades to BEST: goal, who it's for, why |
|
|
35
|
+
| **Get a new MCP server base** — context, memory, identity, wired | stand this up as-is; a host has all three before you write a tool of your own |
|
|
36
|
+
| **Improve your MCP with context, memory, ID** — you already run one | run it alongside your existing server; nothing to migrate, it composes |
|
|
37
|
+
|
|
16
38
|
## A base MCP — or an extension for any other
|
|
17
39
|
|
|
18
40
|
Context, memory, and identity are essential — every MCP host needs an agent
|
|
@@ -37,18 +59,17 @@ It composes:
|
|
|
37
59
|
- **author BETTER, keep true** — [`agents-md-facts`](https://github.com/Wolfe-Jam/agents-md-facts) (`author_agents_md` wraps it for the facts layer; adds a BEST layer of its own from `project.faf` when one exists)
|
|
38
60
|
- **files · shell · git** — [`server-filesystem`](https://github.com/modelcontextprotocol/servers), [`server-git`](https://github.com/modelcontextprotocol/servers) / github‑mcp‑server, your test runner's MCP
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
Vendor-free — context is plain Markdown (`AGENTS.md`); the memory and
|
|
63
|
+
identity formats are swappable examples. It reads and writes only its own
|
|
64
|
+
three files (`AGENTS.md`, `project.fafm`, `.well-known/fafa`) — no general
|
|
65
|
+
file access, no shell, no search.
|
|
44
66
|
|
|
45
67
|
## The card
|
|
46
68
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
screenshot it, drop it in a PR, put it on a status page.
|
|
69
|
+
The screenshot at the top of this page is exactly this — the same three
|
|
70
|
+
sources rendered as one self‑contained HTML page: identity, `AGENTS.md`,
|
|
71
|
+
memory, and how a machine fetches it. The view for people: screenshot it,
|
|
72
|
+
drop it in a PR, put it on a status page.
|
|
52
73
|
|
|
53
74
|
```
|
|
54
75
|
GET /card # live, on the HTTP transport
|
|
@@ -57,17 +78,10 @@ npx mcp-context-card card # or: npm run card → docs/card.html
|
|
|
57
78
|
```
|
|
58
79
|
|
|
59
80
|
Light, dark, or auto; the accent defaults to the AAIF palette and takes any hex.
|
|
60
|
-
[
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
| You want… | Reach for |
|
|
65
|
-
|---|---|
|
|
66
|
-
| an `AGENTS.md` and you don't have one | `author_agents_md` — BEST with a `project.faf`, BETTER without |
|
|
67
|
-
| your agent to pull *one* `AGENTS.md` section on demand, not the whole file | `read_agents_md` · `list_agents_md_sections` |
|
|
68
|
-
| a persistent notepad for your agent — survives restarts, no setup | `remember` · `recall` · `forget` |
|
|
69
|
-
| a shareable view of what your MCP server exposes to agents | `GET /card` · `npx mcp-context-card card` |
|
|
70
|
-
| the two‑surface discovery pattern to copy into your own server | read `src/` |
|
|
81
|
+
This repo's own card, live: [auto](https://wolfe-jam.github.io/mcp-context-card/) ·
|
|
82
|
+
[light](https://wolfe-jam.github.io/mcp-context-card/card-light.html) ·
|
|
83
|
+
[dark](https://wolfe-jam.github.io/mcp-context-card/card-dark.html)
|
|
84
|
+
(all in the AAIF accent shown here — pass any hex to change it).
|
|
71
85
|
|
|
72
86
|
## Add it to your setup
|
|
73
87
|
|
|
@@ -114,9 +128,13 @@ Claude Desktop, Cursor, or any stdio host:
|
|
|
114
128
|
|
|
115
129
|
`MCP_CONTEXT_CARD_ROOT` points at the directory with your `AGENTS.md`. The
|
|
116
130
|
memory tools work with or without it; identity is optional. Over HTTP instead:
|
|
117
|
-
`PORT=8080 npx mcp-context-card`.
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
`PORT=8080 npx mcp-context-card`. Requires Node ≥22.
|
|
132
|
+
|
|
133
|
+
If `command: "npx"` fails to spawn (`spawn npx ENOENT` — seen on Cursor, whose
|
|
134
|
+
host process doesn't inherit a shell `PATH`), point `command` at `node` and
|
|
135
|
+
the installed `dist/bin.js` instead — see
|
|
136
|
+
[docs/WIRING.md](./docs/WIRING.md#1-running-it-in-a-host). Transport choice is
|
|
137
|
+
in [docs/TRANSPORT.md](./docs/TRANSPORT.md).
|
|
120
138
|
|
|
121
139
|
Extending an MCP you already run: most hosts accept more than one
|
|
122
140
|
`mcpServers` entry — add `context-card` alongside `server-filesystem`,
|
|
@@ -173,7 +191,7 @@ The wire‑level detail is in [docs/MECHANISMS.md](./docs/MECHANISMS.md).
|
|
|
173
191
|
4. **Discovery** — `list_context_sources()`, then the same server over stateless
|
|
174
192
|
HTTP with its `.well-known` routes and `GET /card`.
|
|
175
193
|
|
|
176
|
-
|
|
194
|
+
102 tests on Linux, macOS, and Windows, coverage‑gated in CI. Two spawn a real
|
|
177
195
|
child process and check a remembered fact survives the restart — one against
|
|
178
196
|
an existing `project.fafm`, one starting from a project that has never had
|
|
179
197
|
one; another checks the stdio and HTTP tool surfaces match.
|
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 0.
|
|
11
|
+
export declare const HELP = "mcp-context-card 0.6.1\nServe a project's context (AGENTS.md), memory, and identity over MCP.\n\nUSAGE\n mcp-context-card stdio MCP server \u2014 what an MCP host spawns (default)\n mcp-context-card --http stateless Streamable HTTP on PORT (default 3000)\n mcp-context-card --stdio force stdio even when PORT is set\n mcp-context-card card [> f.html] render this directory's context card to stdout\n --theme light|dark --accent #hex\n mcp-context-card --help this text\n mcp-context-card --version print version\n\nENV\n MCP_CONTEXT_CARD_ROOT read AGENTS.md / project.fafm / .well-known/ from here\n PORT if set, run HTTP instead of stdio\n\nA bare run is an stdio server: it waits for a host to speak JSON-RPC on stdin,\nso it looks idle at a terminal. Try `card` or `--http` to see output directly.\nhttps://github.com/Wolfe-Jam/mcp-context-card\n";
|
|
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/card-gen.js
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
* card-gen - write docs/card.html from the three sources, so the card is
|
|
3
3
|
* browsable on GitHub and screenshot-able for the README. Same renderer as
|
|
4
4
|
* GET /card and the render_context_card tool.
|
|
5
|
+
*
|
|
6
|
+
* Also writes two theme-pinned siblings (docs/card-light.html,
|
|
7
|
+
* docs/card-dark.html) — docs/card.html stays "auto" (follows the viewer's
|
|
8
|
+
* OS preference); the two siblings are for linking a forced theme from the
|
|
9
|
+
* README, since a static host can't answer a `?theme=` query param.
|
|
10
|
+
*
|
|
11
|
+
* GitHub Pages serves this repo from main /docs (wolfe-jam.github.io/
|
|
12
|
+
* mcp-context-card/) — docs/index.html (a copy of the auto card) is what
|
|
13
|
+
* answers the bare root, so it isn't a 404.
|
|
5
14
|
*/
|
|
6
15
|
import { writeFileSync } from "node:fs";
|
|
7
16
|
import { dirname, join } from "node:path";
|
|
@@ -9,6 +18,10 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
9
18
|
import { renderCard } from "./render-card.js";
|
|
10
19
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
11
20
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
const auto = renderCard(root);
|
|
22
|
+
writeFileSync(join(root, "docs/card.html"), auto);
|
|
23
|
+
writeFileSync(join(root, "docs/index.html"), auto);
|
|
24
|
+
writeFileSync(join(root, "docs/card-light.html"), renderCard(root, { theme: "light" }));
|
|
25
|
+
writeFileSync(join(root, "docs/card-dark.html"), renderCard(root, { theme: "dark" }));
|
|
26
|
+
console.log("wrote docs/card.html + docs/index.html (auto) + card-light.html + card-dark.html — the context card, rendered from AGENTS.md / project.fafm / .well-known/fafa");
|
|
14
27
|
}
|
package/dist/catalog-gen.d.ts
CHANGED
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 = "0.
|
|
4
|
+
export declare const VERSION = "0.6.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 = "0.
|
|
4
|
+
export const VERSION = "0.6.1";
|
|
5
5
|
export const SERVER_CARD_URI = "mcp-context-card://server-card";
|
package/dist/identity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentIdentity } from "./faf/types.js";
|
|
2
2
|
/** The `_meta` key namespace — the publisher's, reverse-DNS. */
|
|
3
|
-
export declare const META_NS = "io.github.
|
|
3
|
+
export declare const META_NS = "io.github.Wolfe-Jam.mcp-context-card";
|
|
4
4
|
export declare function identity(root: string): AgentIdentity | null;
|
|
5
5
|
/**
|
|
6
6
|
* The identity to show: the `.well-known/fafa` card if present — richer and
|
|
@@ -17,17 +17,17 @@ export declare function whoami(root: string): string;
|
|
|
17
17
|
* because there is no de-facto standard for it yet.
|
|
18
18
|
*/
|
|
19
19
|
export declare function serverCardMeta(): {
|
|
20
|
-
readonly "io.github.
|
|
20
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/context": {
|
|
21
21
|
readonly source: "AGENTS.md";
|
|
22
22
|
readonly mediaType: "text/markdown";
|
|
23
23
|
};
|
|
24
|
-
readonly "io.github.
|
|
24
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/memory": {
|
|
25
25
|
readonly source: "project.fafm";
|
|
26
26
|
readonly mediaType: "application/vnd.fafm+yaml";
|
|
27
27
|
readonly iana: string;
|
|
28
28
|
readonly note: "no de-facto standard for agent memory yet — this is one instantiation";
|
|
29
29
|
};
|
|
30
|
-
readonly "io.github.
|
|
30
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/identity": {
|
|
31
31
|
readonly source: ".well-known/fafa";
|
|
32
32
|
readonly mediaType: "application/vnd.fafa+yaml";
|
|
33
33
|
readonly iana: string;
|
package/dist/identity.js
CHANGED
|
@@ -11,7 +11,7 @@ import { readFileSync } from "node:fs";
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { parseFafa } from "./faf/parse-fafa.js";
|
|
13
13
|
/** The `_meta` key namespace — the publisher's, reverse-DNS. */
|
|
14
|
-
export const META_NS = "io.github.
|
|
14
|
+
export const META_NS = "io.github.Wolfe-Jam.mcp-context-card";
|
|
15
15
|
const iana = (t) => `https://www.iana.org/assignments/media-types/${t}`;
|
|
16
16
|
export function identity(root) {
|
|
17
17
|
return parseFafa(join(root, ".well-known/fafa"));
|
package/dist/render-card.js
CHANGED
|
@@ -26,15 +26,20 @@ const CSS = (accent) => `
|
|
|
26
26
|
--accent:${accent};
|
|
27
27
|
--bg:#f4f4f5; --card:#fff; --fg:#0a0a0a; --muted:#6b6b70;
|
|
28
28
|
--line:rgba(0,0,0,.09); --chip:rgba(0,0,0,.05);
|
|
29
|
+
--card-shadow:0 1px 3px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.10);
|
|
29
30
|
}
|
|
30
31
|
:root[data-theme="dark"]{
|
|
31
32
|
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
32
33
|
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
34
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
35
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
33
36
|
}
|
|
34
37
|
@media (prefers-color-scheme:dark){
|
|
35
38
|
:root:not([data-theme="light"]){
|
|
36
39
|
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
37
40
|
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
41
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
42
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
45
|
*{box-sizing:border-box}
|
|
@@ -42,7 +47,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
42
47
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
43
48
|
padding:40px 18px}
|
|
44
49
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
45
|
-
border-radius:14px;overflow:hidden}
|
|
50
|
+
border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
|
|
46
51
|
.card>*{padding:26px 30px}
|
|
47
52
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
48
53
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
package/dist/server.d.ts
CHANGED
|
@@ -29,17 +29,17 @@ export declare function serverCard(): {
|
|
|
29
29
|
name: string;
|
|
30
30
|
version: string;
|
|
31
31
|
_meta: {
|
|
32
|
-
readonly "io.github.
|
|
32
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/context": {
|
|
33
33
|
readonly source: "AGENTS.md";
|
|
34
34
|
readonly mediaType: "text/markdown";
|
|
35
35
|
};
|
|
36
|
-
readonly "io.github.
|
|
36
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/memory": {
|
|
37
37
|
readonly source: "project.fafm";
|
|
38
38
|
readonly mediaType: "application/vnd.fafm+yaml";
|
|
39
39
|
readonly iana: string;
|
|
40
40
|
readonly note: "no de-facto standard for agent memory yet — this is one instantiation";
|
|
41
41
|
};
|
|
42
|
-
readonly "io.github.
|
|
42
|
+
readonly "io.github.Wolfe-Jam.mcp-context-card/identity": {
|
|
43
43
|
readonly source: ".well-known/fafa";
|
|
44
44
|
readonly mediaType: "application/vnd.fafa+yaml";
|
|
45
45
|
readonly iana: string;
|
package/docs/MECHANISMS.md
CHANGED
|
@@ -29,19 +29,19 @@ Both return:
|
|
|
29
29
|
```jsonc
|
|
30
30
|
{
|
|
31
31
|
"name": "mcp-context-card",
|
|
32
|
-
"version": "0.
|
|
32
|
+
"version": "0.6.1",
|
|
33
33
|
"_meta": {
|
|
34
|
-
"io.github.
|
|
34
|
+
"io.github.Wolfe-Jam.mcp-context-card/context": {
|
|
35
35
|
"source": "AGENTS.md",
|
|
36
36
|
"mediaType": "text/markdown"
|
|
37
37
|
},
|
|
38
|
-
"io.github.
|
|
38
|
+
"io.github.Wolfe-Jam.mcp-context-card/memory": {
|
|
39
39
|
"source": "project.fafm",
|
|
40
40
|
"mediaType": "application/vnd.fafm+yaml",
|
|
41
41
|
"iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml",
|
|
42
42
|
"note": "no de-facto standard for agent memory yet — this is one instantiation"
|
|
43
43
|
},
|
|
44
|
-
"io.github.
|
|
44
|
+
"io.github.Wolfe-Jam.mcp-context-card/identity": {
|
|
45
45
|
"source": ".well-known/fafa",
|
|
46
46
|
"mediaType": "application/vnd.fafa+yaml",
|
|
47
47
|
"iana": "https://www.iana.org/assignments/media-types/application/vnd.fafa+yaml"
|
|
@@ -55,7 +55,7 @@ Both return:
|
|
|
55
55
|
- **`_meta` is the extension point.** SEP‑2127 defines it as
|
|
56
56
|
`additionalProperties: {}`. A consumer that doesn't know a key ignores it.
|
|
57
57
|
- **Keys are reverse‑DNS‑namespaced to the publisher**
|
|
58
|
-
(`io.github.
|
|
58
|
+
(`io.github.Wolfe-Jam.mcp-context-card/context`, not `context`). No collisions, and
|
|
59
59
|
the key's owner is unambiguous. Use a domain or GitHub identity you control.
|
|
60
60
|
- **One key per concern**, each self‑describing: the source file, its media
|
|
61
61
|
type, and — where the media type is IANA‑registered — the anchor. `context`
|
|
@@ -135,3 +135,20 @@ change a source, both surfaces move together.
|
|
|
135
135
|
|
|
136
136
|
**Describe the artifacts once; expose them through whatever mechanism the
|
|
137
137
|
consumer speaks.**
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Server Card, and A2A
|
|
142
|
+
|
|
143
|
+
**Server Card** is what this server has: `AGENTS.md`, a memory file, an
|
|
144
|
+
identity block — read in-band as an MCP resource, or out-of-band at
|
|
145
|
+
`GET /.well-known/mcp/server-card`.
|
|
146
|
+
|
|
147
|
+
**A2A's [AgentCard](https://a2a-protocol.org/latest/specification/)** is
|
|
148
|
+
different: a live agent you can hand a task to — an endpoint, `capabilities`,
|
|
149
|
+
`skills`, authentication.
|
|
150
|
+
|
|
151
|
+
`.fafa` is the identity source behind the Server Card. We're ready for A2A:
|
|
152
|
+
the day a project here is reachable over A2A, the same source publishes a
|
|
153
|
+
real AgentCard alongside it — one more mechanism, same invariant, a real
|
|
154
|
+
endpoint and real skills, not a reshape of `.fafa`.
|
package/docs/WIRING.md
CHANGED
|
@@ -77,7 +77,7 @@ And to discover what a server offers before committing to it:
|
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
79
|
await client.callTool({ name: "list_context_sources", arguments: {} });
|
|
80
|
-
// → { context: { source: "AGENTS.md", mediaType: "text/markdown", present: true, sections:
|
|
80
|
+
// → { context: { source: "AGENTS.md", mediaType: "text/markdown", present: true, sections: 10 },
|
|
81
81
|
// memory: { … }, identity: { … },
|
|
82
82
|
// surfaces: { mcp: { serverCard: "resource mcp-context-card://server-card" },
|
|
83
83
|
// http: { serverCard: "GET /.well-known/mcp/server-card",
|
|
@@ -95,7 +95,7 @@ To serve *your* artifacts:
|
|
|
95
95
|
— with your own, or point `MCP_CONTEXT_CARD_ROOT` at a directory that has them.
|
|
96
96
|
`AGENTS.md` is the one with a real standard; the other two are swappable.
|
|
97
97
|
2. **Rename the namespace.** `serverCardMeta()` in `src/identity.ts` uses
|
|
98
|
-
`io.github.
|
|
98
|
+
`io.github.Wolfe-Jam.mcp-context-card/*` keys, and `buildCatalog()` in
|
|
99
99
|
`src/catalog-gen.ts` uses `urn:air:mcp-context-card:*` identifiers. Change both to
|
|
100
100
|
a domain or GitHub identity you control ([MECHANISMS.md](./MECHANISMS.md)).
|
|
101
101
|
3. **Swap the media types** in `serverCardMeta()` if your memory / identity
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>mcp-context-card — context card</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{
|
|
9
|
+
--accent:#FF702D;
|
|
10
|
+
--bg:#f4f4f5; --card:#fff; --fg:#0a0a0a; --muted:#6b6b70;
|
|
11
|
+
--line:rgba(0,0,0,.09); --chip:rgba(0,0,0,.05);
|
|
12
|
+
--card-shadow:0 1px 3px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.10);
|
|
13
|
+
}
|
|
14
|
+
:root[data-theme="dark"]{
|
|
15
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
16
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
17
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
18
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
19
|
+
}
|
|
20
|
+
@media (prefers-color-scheme:dark){
|
|
21
|
+
:root:not([data-theme="light"]){
|
|
22
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
23
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
24
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
25
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
*{box-sizing:border-box}
|
|
29
|
+
body{margin:0;background:var(--bg);color:var(--fg);
|
|
30
|
+
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
|
+
padding:40px 18px}
|
|
32
|
+
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
+
border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
|
|
34
|
+
.card>*{padding:26px 30px}
|
|
35
|
+
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
|
+
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
37
|
+
.pills{display:flex;flex-wrap:wrap;gap:6px}
|
|
38
|
+
.pill{font-size:.74rem;font-weight:600;padding:3px 9px;border-radius:20px;background:var(--chip);color:var(--muted)}
|
|
39
|
+
.pill.accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent)}
|
|
40
|
+
section{border-bottom:1px solid var(--line)}
|
|
41
|
+
section:last-child{border-bottom:0}
|
|
42
|
+
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
|
+
color:var(--accent);margin:0 0 14px}
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
|
|
45
|
+
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
|
+
.toc a:hover{color:var(--accent)}
|
|
47
|
+
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
|
+
.md h1{font-size:1.15rem}
|
|
49
|
+
.md p{margin:8px 0}
|
|
50
|
+
.md ul,.md ol{margin:8px 0;padding-left:22px}
|
|
51
|
+
.md li{margin:3px 0}
|
|
52
|
+
.md code{background:var(--chip);padding:1px 5px;border-radius:5px;
|
|
53
|
+
font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
54
|
+
.md pre{background:var(--chip);padding:14px 16px;border-radius:9px;overflow:auto}
|
|
55
|
+
.md pre code{background:none;padding:0}
|
|
56
|
+
.md table{border-collapse:collapse;width:100%;margin:12px 0;font-size:.88rem;display:block;overflow:auto}
|
|
57
|
+
.md th,.md td{border:1px solid var(--line);padding:6px 10px;text-align:left}
|
|
58
|
+
.md blockquote{margin:10px 0;padding-left:14px;border-left:3px solid var(--line);color:var(--muted)}
|
|
59
|
+
.md a{color:var(--accent)}
|
|
60
|
+
.fact{padding:12px 0;border-bottom:1px solid var(--line)}
|
|
61
|
+
.fact:last-child{border-bottom:0}
|
|
62
|
+
.fact p{margin:0 0 7px}
|
|
63
|
+
.meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
|
|
64
|
+
.tag{font-size:.72rem;padding:2px 8px;border-radius:5px;background:var(--chip);color:var(--muted)}
|
|
65
|
+
.dot{width:7px;height:7px;border-radius:50%;background:var(--accent);display:inline-block}
|
|
66
|
+
.dot.pending{background:var(--muted)}
|
|
67
|
+
.disc{width:100%;border-collapse:collapse;font-size:.84rem}
|
|
68
|
+
.disc th,.disc td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--line)}
|
|
69
|
+
.disc th{color:var(--muted);font-weight:600}
|
|
70
|
+
.disc code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}
|
|
71
|
+
.fetch{margin:14px 0 0;font-size:.82rem;color:var(--muted)}
|
|
72
|
+
.fetch code{background:var(--chip);padding:1px 5px;border-radius:5px}
|
|
73
|
+
.foot{color:var(--muted);font-size:.78rem;text-align:center;border-top:1px solid var(--line)}
|
|
74
|
+
.none{color:var(--muted);font-style:italic}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<main class="card">
|
|
79
|
+
<div class="top">
|
|
80
|
+
<h1>mcp-context-card</h1>
|
|
81
|
+
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v0.6.1</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
|
|
82
|
+
</div>
|
|
83
|
+
<section>
|
|
84
|
+
<p class="label">Context — AGENTS.md</p>
|
|
85
|
+
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><div class="md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
86
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
|
|
87
|
+
<h2 id="setup">Setup</h2>
|
|
88
|
+
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
+
<p>Node 22 or newer. No other system dependencies.</p>
|
|
90
|
+
<h2 id="build">Build</h2>
|
|
91
|
+
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
+
<h2 id="test">Test</h2>
|
|
94
|
+
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
|
+
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
|
+
npm run demo # end to end: all tools over stdio, then over stateless HTTP</code></pre>
|
|
97
|
+
<p>CI runs <code>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>).</p>
|
|
98
|
+
<h2 id="layout">Layout</h2>
|
|
99
|
+
<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>
|
|
100
|
+
<h2 id="conventions">Conventions</h2>
|
|
101
|
+
<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>
|
|
102
|
+
<h2 id="the-invariant">The invariant</h2>
|
|
103
|
+
<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>
|
|
104
|
+
<h2 id="safety">Safety</h2>
|
|
105
|
+
<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>
|
|
106
|
+
<h2 id="definition-of-done">Definition of done</h2>
|
|
107
|
+
<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>.</p>
|
|
108
|
+
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
109
|
+
<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>
|
|
110
|
+
</section>
|
|
111
|
+
<section>
|
|
112
|
+
<p class="label">Memory — 4 facts</p>
|
|
113
|
+
<div class="fact"><p>The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so this server uses .fafm and .fafa as one instantiation each.</p><div class="meta"><span class="tag">scope</span><span class="tag">agents-md</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart.</p><div class="meta"><span class="tag">mcp</span><span class="tag">server-card</span><span class="tag">ai-catalog</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Distribution: a published npm package (bin <code>mcp-context-card</code>, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project.</p><div class="meta"><span class="tag">distribution</span><span class="tag">mit</span><span class="tag">npm</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>author_agents_md authors the best AGENTS.md the project has the material for, not a fixed floor. BETTER is the facts-only draft (via agents-md-facts: build/test commands, entry points, conventions — nothing invented). BEST is that plus a '## Project' section ahead of it, read straight from project.faf when one exists — goal, who it's for, why, and a start-here file list. The rule is concrete: project.faf present means BEST, absent means BETTER.</p><div class="meta"><span class="tag">agents-md</span><span class="tag">author_agents_md</span><span class="tag">faf</span><span class="dot" title="verified"></span></div></div>
|
|
114
|
+
</section>
|
|
115
|
+
<section>
|
|
116
|
+
<p class="label">Discovery</p>
|
|
117
|
+
<table class="disc"><thead><tr><th>concern</th><th>source</th><th>media type</th></tr></thead><tbody><tr><td>context</td><td><code>AGENTS.md</code></td><td><code>text/markdown</code></td></tr><tr><td>memory</td><td><code>project.fafm</code></td><td><code>application/vnd.fafm+yaml</code></td></tr><tr><td>identity</td><td><code>.well-known/fafa</code></td><td><code>application/vnd.fafa+yaml</code></td></tr></tbody></table>
|
|
118
|
+
<p class="fetch">A machine reads this over <b>MCP</b> from the
|
|
119
|
+
<code>mcp-context-card://server-card</code> resource; over <b>HTTP</b> also
|
|
120
|
+
from <code>GET /.well-known/mcp/server-card</code> and
|
|
121
|
+
<code>GET /.well-known/ai-catalog.json</code>.</p>
|
|
122
|
+
</section>
|
|
123
|
+
<div class="foot">mcp-context-card · context card</div>
|
|
124
|
+
</main>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="light">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>mcp-context-card — context card</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{
|
|
9
|
+
--accent:#FF702D;
|
|
10
|
+
--bg:#f4f4f5; --card:#fff; --fg:#0a0a0a; --muted:#6b6b70;
|
|
11
|
+
--line:rgba(0,0,0,.09); --chip:rgba(0,0,0,.05);
|
|
12
|
+
--card-shadow:0 1px 3px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.10);
|
|
13
|
+
}
|
|
14
|
+
:root[data-theme="dark"]{
|
|
15
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
16
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
17
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
18
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
19
|
+
}
|
|
20
|
+
@media (prefers-color-scheme:dark){
|
|
21
|
+
:root:not([data-theme="light"]){
|
|
22
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
23
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
24
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
25
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
*{box-sizing:border-box}
|
|
29
|
+
body{margin:0;background:var(--bg);color:var(--fg);
|
|
30
|
+
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
|
+
padding:40px 18px}
|
|
32
|
+
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
+
border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
|
|
34
|
+
.card>*{padding:26px 30px}
|
|
35
|
+
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
|
+
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
37
|
+
.pills{display:flex;flex-wrap:wrap;gap:6px}
|
|
38
|
+
.pill{font-size:.74rem;font-weight:600;padding:3px 9px;border-radius:20px;background:var(--chip);color:var(--muted)}
|
|
39
|
+
.pill.accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent)}
|
|
40
|
+
section{border-bottom:1px solid var(--line)}
|
|
41
|
+
section:last-child{border-bottom:0}
|
|
42
|
+
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
|
+
color:var(--accent);margin:0 0 14px}
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
|
|
45
|
+
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
|
+
.toc a:hover{color:var(--accent)}
|
|
47
|
+
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
|
+
.md h1{font-size:1.15rem}
|
|
49
|
+
.md p{margin:8px 0}
|
|
50
|
+
.md ul,.md ol{margin:8px 0;padding-left:22px}
|
|
51
|
+
.md li{margin:3px 0}
|
|
52
|
+
.md code{background:var(--chip);padding:1px 5px;border-radius:5px;
|
|
53
|
+
font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
54
|
+
.md pre{background:var(--chip);padding:14px 16px;border-radius:9px;overflow:auto}
|
|
55
|
+
.md pre code{background:none;padding:0}
|
|
56
|
+
.md table{border-collapse:collapse;width:100%;margin:12px 0;font-size:.88rem;display:block;overflow:auto}
|
|
57
|
+
.md th,.md td{border:1px solid var(--line);padding:6px 10px;text-align:left}
|
|
58
|
+
.md blockquote{margin:10px 0;padding-left:14px;border-left:3px solid var(--line);color:var(--muted)}
|
|
59
|
+
.md a{color:var(--accent)}
|
|
60
|
+
.fact{padding:12px 0;border-bottom:1px solid var(--line)}
|
|
61
|
+
.fact:last-child{border-bottom:0}
|
|
62
|
+
.fact p{margin:0 0 7px}
|
|
63
|
+
.meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
|
|
64
|
+
.tag{font-size:.72rem;padding:2px 8px;border-radius:5px;background:var(--chip);color:var(--muted)}
|
|
65
|
+
.dot{width:7px;height:7px;border-radius:50%;background:var(--accent);display:inline-block}
|
|
66
|
+
.dot.pending{background:var(--muted)}
|
|
67
|
+
.disc{width:100%;border-collapse:collapse;font-size:.84rem}
|
|
68
|
+
.disc th,.disc td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--line)}
|
|
69
|
+
.disc th{color:var(--muted);font-weight:600}
|
|
70
|
+
.disc code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}
|
|
71
|
+
.fetch{margin:14px 0 0;font-size:.82rem;color:var(--muted)}
|
|
72
|
+
.fetch code{background:var(--chip);padding:1px 5px;border-radius:5px}
|
|
73
|
+
.foot{color:var(--muted);font-size:.78rem;text-align:center;border-top:1px solid var(--line)}
|
|
74
|
+
.none{color:var(--muted);font-style:italic}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<main class="card">
|
|
79
|
+
<div class="top">
|
|
80
|
+
<h1>mcp-context-card</h1>
|
|
81
|
+
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v0.6.1</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
|
|
82
|
+
</div>
|
|
83
|
+
<section>
|
|
84
|
+
<p class="label">Context — AGENTS.md</p>
|
|
85
|
+
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><div class="md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
86
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
|
|
87
|
+
<h2 id="setup">Setup</h2>
|
|
88
|
+
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
+
<p>Node 22 or newer. No other system dependencies.</p>
|
|
90
|
+
<h2 id="build">Build</h2>
|
|
91
|
+
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
+
<h2 id="test">Test</h2>
|
|
94
|
+
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
|
+
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
|
+
npm run demo # end to end: all tools over stdio, then over stateless HTTP</code></pre>
|
|
97
|
+
<p>CI runs <code>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>).</p>
|
|
98
|
+
<h2 id="layout">Layout</h2>
|
|
99
|
+
<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>
|
|
100
|
+
<h2 id="conventions">Conventions</h2>
|
|
101
|
+
<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>
|
|
102
|
+
<h2 id="the-invariant">The invariant</h2>
|
|
103
|
+
<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>
|
|
104
|
+
<h2 id="safety">Safety</h2>
|
|
105
|
+
<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>
|
|
106
|
+
<h2 id="definition-of-done">Definition of done</h2>
|
|
107
|
+
<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>.</p>
|
|
108
|
+
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
109
|
+
<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>
|
|
110
|
+
</section>
|
|
111
|
+
<section>
|
|
112
|
+
<p class="label">Memory — 4 facts</p>
|
|
113
|
+
<div class="fact"><p>The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so this server uses .fafm and .fafa as one instantiation each.</p><div class="meta"><span class="tag">scope</span><span class="tag">agents-md</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart.</p><div class="meta"><span class="tag">mcp</span><span class="tag">server-card</span><span class="tag">ai-catalog</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Distribution: a published npm package (bin <code>mcp-context-card</code>, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project.</p><div class="meta"><span class="tag">distribution</span><span class="tag">mit</span><span class="tag">npm</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>author_agents_md authors the best AGENTS.md the project has the material for, not a fixed floor. BETTER is the facts-only draft (via agents-md-facts: build/test commands, entry points, conventions — nothing invented). BEST is that plus a '## Project' section ahead of it, read straight from project.faf when one exists — goal, who it's for, why, and a start-here file list. The rule is concrete: project.faf present means BEST, absent means BETTER.</p><div class="meta"><span class="tag">agents-md</span><span class="tag">author_agents_md</span><span class="tag">faf</span><span class="dot" title="verified"></span></div></div>
|
|
114
|
+
</section>
|
|
115
|
+
<section>
|
|
116
|
+
<p class="label">Discovery</p>
|
|
117
|
+
<table class="disc"><thead><tr><th>concern</th><th>source</th><th>media type</th></tr></thead><tbody><tr><td>context</td><td><code>AGENTS.md</code></td><td><code>text/markdown</code></td></tr><tr><td>memory</td><td><code>project.fafm</code></td><td><code>application/vnd.fafm+yaml</code></td></tr><tr><td>identity</td><td><code>.well-known/fafa</code></td><td><code>application/vnd.fafa+yaml</code></td></tr></tbody></table>
|
|
118
|
+
<p class="fetch">A machine reads this over <b>MCP</b> from the
|
|
119
|
+
<code>mcp-context-card://server-card</code> resource; over <b>HTTP</b> also
|
|
120
|
+
from <code>GET /.well-known/mcp/server-card</code> and
|
|
121
|
+
<code>GET /.well-known/ai-catalog.json</code>.</p>
|
|
122
|
+
</section>
|
|
123
|
+
<div class="foot">mcp-context-card · context card</div>
|
|
124
|
+
</main>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
package/docs/card.html
CHANGED
|
@@ -9,15 +9,20 @@
|
|
|
9
9
|
--accent:#FF702D;
|
|
10
10
|
--bg:#f4f4f5; --card:#fff; --fg:#0a0a0a; --muted:#6b6b70;
|
|
11
11
|
--line:rgba(0,0,0,.09); --chip:rgba(0,0,0,.05);
|
|
12
|
+
--card-shadow:0 1px 3px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.10);
|
|
12
13
|
}
|
|
13
14
|
:root[data-theme="dark"]{
|
|
14
15
|
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
15
16
|
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
17
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
18
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
16
19
|
}
|
|
17
20
|
@media (prefers-color-scheme:dark){
|
|
18
21
|
:root:not([data-theme="light"]){
|
|
19
22
|
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
20
23
|
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
24
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
25
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
*{box-sizing:border-box}
|
|
@@ -25,7 +30,7 @@ body{margin:0;background:var(--bg);color:var(--fg);
|
|
|
25
30
|
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
26
31
|
padding:40px 18px}
|
|
27
32
|
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
28
|
-
border-radius:14px;overflow:hidden}
|
|
33
|
+
border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
|
|
29
34
|
.card>*{padding:26px 30px}
|
|
30
35
|
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
31
36
|
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
@@ -73,7 +78,7 @@ section:last-child{border-bottom:0}
|
|
|
73
78
|
<main class="card">
|
|
74
79
|
<div class="top">
|
|
75
80
|
<h1>mcp-context-card</h1>
|
|
76
|
-
<div class="pills"><span class="pill">io.github.
|
|
81
|
+
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v0.6.1</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
|
|
77
82
|
</div>
|
|
78
83
|
<section>
|
|
79
84
|
<p class="label">Context — AGENTS.md</p>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>mcp-context-card — context card</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{
|
|
9
|
+
--accent:#FF702D;
|
|
10
|
+
--bg:#f4f4f5; --card:#fff; --fg:#0a0a0a; --muted:#6b6b70;
|
|
11
|
+
--line:rgba(0,0,0,.09); --chip:rgba(0,0,0,.05);
|
|
12
|
+
--card-shadow:0 1px 3px rgba(0,0,0,.06), 0 12px 32px rgba(0,0,0,.10);
|
|
13
|
+
}
|
|
14
|
+
:root[data-theme="dark"]{
|
|
15
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
16
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
17
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
18
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
19
|
+
}
|
|
20
|
+
@media (prefers-color-scheme:dark){
|
|
21
|
+
:root:not([data-theme="light"]){
|
|
22
|
+
--bg:#000; --card:#0d0d0d; --fg:#fafafa; --muted:#9a9aa0;
|
|
23
|
+
--line:rgba(255,255,255,.13); --chip:rgba(255,255,255,.07);
|
|
24
|
+
--card-shadow:0 0 0 1px rgba(255,255,255,.16),
|
|
25
|
+
0 8px 40px color-mix(in srgb, var(--accent) 20%, transparent);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
*{box-sizing:border-box}
|
|
29
|
+
body{margin:0;background:var(--bg);color:var(--fg);
|
|
30
|
+
font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
31
|
+
padding:40px 18px}
|
|
32
|
+
.card{max-width:760px;margin:0 auto;background:var(--card);border:1px solid var(--line);
|
|
33
|
+
border-radius:14px;overflow:hidden;box-shadow:var(--card-shadow)}
|
|
34
|
+
.card>*{padding:26px 30px}
|
|
35
|
+
.top{border-top:4px solid var(--accent);border-bottom:1px solid var(--line)}
|
|
36
|
+
h1{margin:0 0 10px;font-size:1.7rem;letter-spacing:-.02em}
|
|
37
|
+
.pills{display:flex;flex-wrap:wrap;gap:6px}
|
|
38
|
+
.pill{font-size:.74rem;font-weight:600;padding:3px 9px;border-radius:20px;background:var(--chip);color:var(--muted)}
|
|
39
|
+
.pill.accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent)}
|
|
40
|
+
section{border-bottom:1px solid var(--line)}
|
|
41
|
+
section:last-child{border-bottom:0}
|
|
42
|
+
.label{font-size:.7rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
|
|
43
|
+
color:var(--accent);margin:0 0 14px}
|
|
44
|
+
.toc{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 20px;padding:0;list-style:none}
|
|
45
|
+
.toc a{font-size:.82rem;color:var(--muted);text-decoration:none}
|
|
46
|
+
.toc a:hover{color:var(--accent)}
|
|
47
|
+
.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;font-size:1rem;letter-spacing:-.01em}
|
|
48
|
+
.md h1{font-size:1.15rem}
|
|
49
|
+
.md p{margin:8px 0}
|
|
50
|
+
.md ul,.md ol{margin:8px 0;padding-left:22px}
|
|
51
|
+
.md li{margin:3px 0}
|
|
52
|
+
.md code{background:var(--chip);padding:1px 5px;border-radius:5px;
|
|
53
|
+
font:.86em ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
54
|
+
.md pre{background:var(--chip);padding:14px 16px;border-radius:9px;overflow:auto}
|
|
55
|
+
.md pre code{background:none;padding:0}
|
|
56
|
+
.md table{border-collapse:collapse;width:100%;margin:12px 0;font-size:.88rem;display:block;overflow:auto}
|
|
57
|
+
.md th,.md td{border:1px solid var(--line);padding:6px 10px;text-align:left}
|
|
58
|
+
.md blockquote{margin:10px 0;padding-left:14px;border-left:3px solid var(--line);color:var(--muted)}
|
|
59
|
+
.md a{color:var(--accent)}
|
|
60
|
+
.fact{padding:12px 0;border-bottom:1px solid var(--line)}
|
|
61
|
+
.fact:last-child{border-bottom:0}
|
|
62
|
+
.fact p{margin:0 0 7px}
|
|
63
|
+
.meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
|
|
64
|
+
.tag{font-size:.72rem;padding:2px 8px;border-radius:5px;background:var(--chip);color:var(--muted)}
|
|
65
|
+
.dot{width:7px;height:7px;border-radius:50%;background:var(--accent);display:inline-block}
|
|
66
|
+
.dot.pending{background:var(--muted)}
|
|
67
|
+
.disc{width:100%;border-collapse:collapse;font-size:.84rem}
|
|
68
|
+
.disc th,.disc td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--line)}
|
|
69
|
+
.disc th{color:var(--muted);font-weight:600}
|
|
70
|
+
.disc code{font:.86em ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}
|
|
71
|
+
.fetch{margin:14px 0 0;font-size:.82rem;color:var(--muted)}
|
|
72
|
+
.fetch code{background:var(--chip);padding:1px 5px;border-radius:5px}
|
|
73
|
+
.foot{color:var(--muted);font-size:.78rem;text-align:center;border-top:1px solid var(--line)}
|
|
74
|
+
.none{color:var(--muted);font-style:italic}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<main class="card">
|
|
79
|
+
<div class="top">
|
|
80
|
+
<h1>mcp-context-card</h1>
|
|
81
|
+
<div class="pills"><span class="pill">io.github.Wolfe-Jam</span><span class="pill">v0.6.1</span><span class="pill accent">published</span><span class="pill">MIT</span></div>
|
|
82
|
+
</div>
|
|
83
|
+
<section>
|
|
84
|
+
<p class="label">Context — AGENTS.md</p>
|
|
85
|
+
<ul class="toc"><li><a href="#setup">Setup</a></li><li><a href="#build">Build</a></li><li><a href="#test">Test</a></li><li><a href="#layout">Layout</a></li><li><a href="#conventions">Conventions</a></li><li><a href="#the-invariant">The invariant</a></li><li><a href="#safety">Safety</a></li><li><a href="#definition-of-done">Definition of done</a></li><li><a href="#authoring-this-file">Authoring this file</a></li></ul><div class="md"><p><code>mcp-context-card</code> is the essential MCP server for a project's <strong>context</strong> (this file), <strong>memory</strong>, and <strong>identity</strong> — usable as your base MCP, or dropped into any existing MCP server as an extension. Discoverable to any MCP client through the two surfaces already in the ecosystem: the Server Card <code>_meta</code> block and <code>ai-catalog.json</code> sibling entries.</p>
|
|
86
|
+
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
|
|
87
|
+
<h2 id="setup">Setup</h2>
|
|
88
|
+
<pre><code class="language-bash">npm ci</code></pre>
|
|
89
|
+
<p>Node 22 or newer. No other system dependencies.</p>
|
|
90
|
+
<h2 id="build">Build</h2>
|
|
91
|
+
<pre><code class="language-bash">npm run build # tsc -p tsconfig.build.json → dist/
|
|
92
|
+
npm run typecheck # tsc --noEmit over src/ + test/</code></pre>
|
|
93
|
+
<h2 id="test">Test</h2>
|
|
94
|
+
<pre><code class="language-bash">npm test # node:test — every test/*.test.ts
|
|
95
|
+
npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80, src/ only)
|
|
96
|
+
npm run demo # end to end: all tools over stdio, then over stateless HTTP</code></pre>
|
|
97
|
+
<p>CI runs <code>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>).</p>
|
|
98
|
+
<h2 id="layout">Layout</h2>
|
|
99
|
+
<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>
|
|
100
|
+
<h2 id="conventions">Conventions</h2>
|
|
101
|
+
<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>
|
|
102
|
+
<h2 id="the-invariant">The invariant</h2>
|
|
103
|
+
<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>
|
|
104
|
+
<h2 id="safety">Safety</h2>
|
|
105
|
+
<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>
|
|
106
|
+
<h2 id="definition-of-done">Definition of done</h2>
|
|
107
|
+
<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>.</p>
|
|
108
|
+
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
109
|
+
<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>
|
|
110
|
+
</section>
|
|
111
|
+
<section>
|
|
112
|
+
<p class="label">Memory — 4 facts</p>
|
|
113
|
+
<div class="fact"><p>The context concern points at AGENTS.md — the de-facto standard for agent instructions. read_agents_md serves it whole or one section at a time, so a client pulls '## Test' without spending its context window on the whole file. Memory and identity have no de-facto standard, so this server uses .fafm and .fafa as one instantiation each.</p><div class="meta"><span class="tag">scope</span><span class="tag">agents-md</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Both exposure mechanisms — the Server Card _meta block and a self-published ai-catalog.json — already exist in the MCP ecosystem. This server wires all three concerns through them, from one set of source files, with a CI check (catalog:check) that fails if the two surfaces drift apart.</p><div class="meta"><span class="tag">mcp</span><span class="tag">server-card</span><span class="tag">ai-catalog</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>Distribution: a published npm package (bin <code>mcp-context-card</code>, dual transport). The three source files (AGENTS.md, project.fafm, .well-known/fafa) ship with the package so it is a working discovery target on install. MCP_CONTEXT_CARD_ROOT points it at a real project.</p><div class="meta"><span class="tag">distribution</span><span class="tag">mit</span><span class="tag">npm</span><span class="dot" title="verified"></span></div></div><div class="fact"><p>author_agents_md authors the best AGENTS.md the project has the material for, not a fixed floor. BETTER is the facts-only draft (via agents-md-facts: build/test commands, entry points, conventions — nothing invented). BEST is that plus a '## Project' section ahead of it, read straight from project.faf when one exists — goal, who it's for, why, and a start-here file list. The rule is concrete: project.faf present means BEST, absent means BETTER.</p><div class="meta"><span class="tag">agents-md</span><span class="tag">author_agents_md</span><span class="tag">faf</span><span class="dot" title="verified"></span></div></div>
|
|
114
|
+
</section>
|
|
115
|
+
<section>
|
|
116
|
+
<p class="label">Discovery</p>
|
|
117
|
+
<table class="disc"><thead><tr><th>concern</th><th>source</th><th>media type</th></tr></thead><tbody><tr><td>context</td><td><code>AGENTS.md</code></td><td><code>text/markdown</code></td></tr><tr><td>memory</td><td><code>project.fafm</code></td><td><code>application/vnd.fafm+yaml</code></td></tr><tr><td>identity</td><td><code>.well-known/fafa</code></td><td><code>application/vnd.fafa+yaml</code></td></tr></tbody></table>
|
|
118
|
+
<p class="fetch">A machine reads this over <b>MCP</b> from the
|
|
119
|
+
<code>mcp-context-card://server-card</code> resource; over <b>HTTP</b> also
|
|
120
|
+
from <code>GET /.well-known/mcp/server-card</code> and
|
|
121
|
+
<code>GET /.well-known/ai-catalog.json</code>.</p>
|
|
122
|
+
</section>
|
|
123
|
+
<div class="foot">mcp-context-card · context card</div>
|
|
124
|
+
</main>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-context-card",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"mcpName": "io.github.
|
|
3
|
+
"version": "0.6.1",
|
|
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": [
|
|
7
7
|
"mcp",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"catalog": "tsx src/catalog-gen.ts",
|
|
54
54
|
"catalog:check": "tsx src/catalog-gen.ts && git diff --exit-code -- .well-known/ai-catalog.json",
|
|
55
55
|
"card": "tsx src/card-gen.ts",
|
|
56
|
-
"card:check": "tsx src/card-gen.ts && git diff --exit-code -- docs/card.html",
|
|
56
|
+
"card:check": "tsx src/card-gen.ts && git diff --exit-code -- docs/card.html docs/index.html docs/card-light.html docs/card-dark.html",
|
|
57
57
|
"test": "node --import tsx --test \"test/*.test.ts\"",
|
|
58
58
|
"test:coverage": "node --import tsx --test --experimental-test-coverage --test-coverage-exclude=\"test/**\" --test-coverage-exclude=\"demo.ts\" --test-coverage-lines=90 --test-coverage-functions=85 --test-coverage-branches=80 \"test/*.test.ts\"",
|
|
59
59
|
"typecheck": "tsc --noEmit"
|
package/server.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
-
"name": "io.github.
|
|
3
|
+
"name": "io.github.Wolfe-Jam/mcp-context-card",
|
|
4
4
|
"title": "mcp-context-card",
|
|
5
|
-
"description": "
|
|
6
|
-
"version": "0.
|
|
5
|
+
"description": "MCP server for a project's context (AGENTS.md), memory, and identity — base or drop-in extension.",
|
|
6
|
+
"version": "0.6.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": "0.
|
|
16
|
+
"version": "0.6.1",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
@@ -29,17 +29,17 @@
|
|
|
29
29
|
],
|
|
30
30
|
"_meta": {
|
|
31
31
|
"io.modelcontextprotocol.registry/publisher-provided": {
|
|
32
|
-
"io.github.
|
|
32
|
+
"io.github.Wolfe-Jam.mcp-context-card/context": {
|
|
33
33
|
"source": "./AGENTS.md",
|
|
34
34
|
"mediaType": "text/markdown"
|
|
35
35
|
},
|
|
36
|
-
"io.github.
|
|
36
|
+
"io.github.Wolfe-Jam.mcp-context-card/memory": {
|
|
37
37
|
"source": "./project.fafm",
|
|
38
38
|
"mediaType": "application/vnd.fafm+yaml",
|
|
39
39
|
"iana": "https://www.iana.org/assignments/media-types/application/vnd.fafm+yaml",
|
|
40
40
|
"note": "no de-facto standard for agent memory yet — this is one instantiation"
|
|
41
41
|
},
|
|
42
|
-
"io.github.
|
|
42
|
+
"io.github.Wolfe-Jam.mcp-context-card/identity": {
|
|
43
43
|
"source": "./.well-known/fafa",
|
|
44
44
|
"mediaType": "application/vnd.fafa+yaml",
|
|
45
45
|
"iana": "https://www.iana.org/assignments/media-types/application/vnd.fafa+yaml"
|
package/docs/img/card.png
DELETED
|
Binary file
|