mcp-context-card 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.well-known/ai-catalog.json +2 -2
- package/.well-known/fafa +5 -4
- package/AGENTS.md +11 -9
- package/CHANGELOG.md +87 -9
- package/README.md +82 -49
- package/dist/author.d.ts +11 -2
- package/dist/author.js +73 -14
- package/dist/bin.d.ts +1 -1
- package/dist/card-gen.js +15 -2
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/identity.d.ts +1 -1
- package/dist/identity.js +1 -1
- package/dist/render-card.js +8 -3
- package/dist/server.d.ts +4 -4
- package/dist/server.js +10 -9
- package/dist/transport/http.js +1 -1
- package/docs/MECHANISMS.md +21 -4
- package/docs/TRANSPORT.md +1 -1
- package/docs/WIRING.md +3 -3
- package/docs/card-dark.html +126 -0
- package/docs/card-light.html +126 -0
- package/docs/card.html +12 -7
- 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 +4 -3
- package/project.faf +6 -6
- package/project.fafm +9 -0
- package/server.json +4 -4
- package/docs/img/card.png +0 -0
package/dist/render-card.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { parseAgentsMd } from "./agents-md.js";
|
|
14
14
|
import { parseFafm } from "./memory.js";
|
|
15
|
-
import { resolveIdentity,
|
|
15
|
+
import { resolveIdentity, serverCardMeta, META_NS } from "./identity.js";
|
|
16
16
|
import { NAME, SERVER_CARD_URI } from "./constants.js";
|
|
17
17
|
import { escapeHtml, renderInline, renderMarkdown, slug } from "./md.js";
|
|
18
18
|
/** AAIF brand orange (aaif.io). The default accent. */
|
|
@@ -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}
|
|
@@ -92,7 +97,7 @@ export function renderCard(root, opts = {}) {
|
|
|
92
97
|
const agents = parseAgentsMd(join(root, "AGENTS.md"));
|
|
93
98
|
const mem = parseFafm(join(root, "project.fafm"));
|
|
94
99
|
const id = resolveIdentity(root);
|
|
95
|
-
const meta =
|
|
100
|
+
const meta = serverCardMeta();
|
|
96
101
|
const name = id?.displayName ?? id?.name ?? NAME;
|
|
97
102
|
const pills = [
|
|
98
103
|
id?.vendor && id.vendor !== id.status && `<span class="pill">${escapeHtml(id.vendor)}</span>`,
|
package/dist/server.d.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* mcp-context-card server — makes a project's context, memory, and identity
|
|
3
3
|
* discoverable to any MCP client.
|
|
4
4
|
*
|
|
5
|
-
* context — read_agents_md · list_agents_md_sections (this project's AGENTS.md)
|
|
6
|
-
* memory — remember · recall · forget
|
|
7
|
-
* identity — whoami
|
|
8
|
-
* discovery — list_context_sources
|
|
5
|
+
* context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
|
|
6
|
+
* memory — remember · recall · forget (a .fafm file)
|
|
7
|
+
* identity — whoami (this server's .fafa)
|
|
8
|
+
* discovery — list_context_sources · render_context_card (what's published, and how)
|
|
9
9
|
*
|
|
10
10
|
* ...exposed through the two mechanisms already in the ecosystem:
|
|
11
11
|
*
|
package/dist/server.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* mcp-context-card server — makes a project's context, memory, and identity
|
|
3
3
|
* discoverable to any MCP client.
|
|
4
4
|
*
|
|
5
|
-
* context — read_agents_md · list_agents_md_sections (this project's AGENTS.md)
|
|
6
|
-
* memory — remember · recall · forget
|
|
7
|
-
* identity — whoami
|
|
8
|
-
* discovery — list_context_sources
|
|
5
|
+
* context — read_agents_md · list_agents_md_sections · author_agents_md (this project's AGENTS.md)
|
|
6
|
+
* memory — remember · recall · forget (a .fafm file)
|
|
7
|
+
* identity — whoami (this server's .fafa)
|
|
8
|
+
* discovery — list_context_sources · render_context_card (what's published, and how)
|
|
9
9
|
*
|
|
10
10
|
* ...exposed through the two mechanisms already in the ecosystem:
|
|
11
11
|
*
|
|
@@ -22,7 +22,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
22
22
|
import { findSection, parseAgentsMd } from "./agents-md.js";
|
|
23
23
|
import { authorAgentsMd } from "./author.js";
|
|
24
24
|
import { forget, parseFafm, recall, remember } from "./memory.js";
|
|
25
|
-
import { identity,
|
|
25
|
+
import { identity, serverCardMeta, whoami } from "./identity.js";
|
|
26
26
|
import { renderCard, safeAccent } from "./render-card.js";
|
|
27
27
|
export { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
|
|
28
28
|
import { NAME, VERSION, SERVER_CARD_URI } from "./constants.js";
|
|
@@ -36,7 +36,7 @@ export const ROOT = join(here, "..");
|
|
|
36
36
|
* `/.well-known/mcp/server-card`.
|
|
37
37
|
*/
|
|
38
38
|
export function serverCard() {
|
|
39
|
-
return { name: NAME, version: VERSION, _meta:
|
|
39
|
+
return { name: NAME, version: VERSION, _meta: serverCardMeta() };
|
|
40
40
|
}
|
|
41
41
|
const text = (s) => ({ content: [{ type: "text", text: s }] });
|
|
42
42
|
/**
|
|
@@ -88,7 +88,7 @@ export function createServer(root = ROOT) {
|
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
name: "author_agents_md",
|
|
91
|
-
description: "Author an AGENTS.md for this project from
|
|
91
|
+
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.",
|
|
92
92
|
inputSchema: { type: "object", properties: {} },
|
|
93
93
|
},
|
|
94
94
|
{
|
|
@@ -170,9 +170,10 @@ export function createServer(root = ROOT) {
|
|
|
170
170
|
}
|
|
171
171
|
case "author_agents_md": {
|
|
172
172
|
const a = authorAgentsMd(root);
|
|
173
|
+
const tier = a.tier === "best" ? "BEST (project.faf + facts)" : "BETTER (facts only)";
|
|
173
174
|
const note = a.exists
|
|
174
|
-
?
|
|
175
|
-
:
|
|
175
|
+
? `${tier} — AGENTS.md already exists, diff this in, don't overwrite`
|
|
176
|
+
: `${tier} — no AGENTS.md yet, write this, then \`npx agents-md-facts --check\` keeps the facts block true`;
|
|
176
177
|
return text(`<!-- ${note} -->\n\n${a.markdown}`);
|
|
177
178
|
}
|
|
178
179
|
case "remember": {
|
package/dist/transport/http.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* transports in a map; this one deliberately does not.
|
|
12
12
|
*
|
|
13
13
|
* Alongside the MCP endpoint it serves the discovery documents:
|
|
14
|
-
* GET /.well-known/mcp/server-card — the Server Card + _meta
|
|
14
|
+
* GET /.well-known/mcp/server-card — the Server Card + _meta block
|
|
15
15
|
* GET /.well-known/ai-catalog.json — the three sibling entries
|
|
16
16
|
* GET /.well-known/fafa — the agent identity card
|
|
17
17
|
*/
|
package/docs/MECHANISMS.md
CHANGED
|
@@ -29,7 +29,7 @@ Both return:
|
|
|
29
29
|
```jsonc
|
|
30
30
|
{
|
|
31
31
|
"name": "mcp-context-card",
|
|
32
|
-
"version": "0.
|
|
32
|
+
"version": "0.6.0",
|
|
33
33
|
"_meta": {
|
|
34
34
|
"io.github.wolfe-jam.mcp-context-card/context": {
|
|
35
35
|
"source": "AGENTS.md",
|
|
@@ -39,7 +39,7 @@ Both return:
|
|
|
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
|
-
"note": "no de-facto standard for agent memory yet — one instantiation"
|
|
42
|
+
"note": "no de-facto standard for agent memory yet — this is one instantiation"
|
|
43
43
|
},
|
|
44
44
|
"io.github.wolfe-jam.mcp-context-card/identity": {
|
|
45
45
|
"source": ".well-known/fafa",
|
|
@@ -64,7 +64,7 @@ Both return:
|
|
|
64
64
|
is for instructions; the block says so rather than implying `.fafm` is a
|
|
65
65
|
standard.
|
|
66
66
|
|
|
67
|
-
Built by `
|
|
67
|
+
Built by `serverCardMeta()` in [`src/identity.ts`](../src/identity.ts).
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
@@ -129,9 +129,26 @@ project.fafm ─┼─→ Server Card _meta (context · memory · identity)
|
|
|
129
129
|
fafa
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
`catalog-gen.ts` reads exactly the files `
|
|
132
|
+
`catalog-gen.ts` reads exactly the files `serverCardMeta()` names. The CI job
|
|
133
133
|
`npm run catalog:check` regenerates `ai-catalog.json` and fails on any drift —
|
|
134
134
|
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/TRANSPORT.md
CHANGED
|
@@ -41,7 +41,7 @@ the wire, so all logging goes to `stderr`.
|
|
|
41
41
|
```
|
|
42
42
|
GET / → index (endpoints)
|
|
43
43
|
POST /mcp → MCP (initialize, tools/list, tools/call, …)
|
|
44
|
-
GET /.well-known/mcp/server-card → the Server Card + _meta
|
|
44
|
+
GET /.well-known/mcp/server-card → the Server Card + _meta block
|
|
45
45
|
GET /.well-known/ai-catalog.json → the three sibling entries
|
|
46
46
|
GET /.well-known/fafa → the agent identity card
|
|
47
47
|
```
|
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",
|
|
@@ -94,11 +94,11 @@ To serve *your* artifacts:
|
|
|
94
94
|
1. **Replace the three files** — `AGENTS.md`, `project.fafm`, `.well-known/fafa`
|
|
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
|
-
2. **Rename the namespace.** `
|
|
97
|
+
2. **Rename the namespace.** `serverCardMeta()` in `src/identity.ts` uses
|
|
98
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
|
-
3. **Swap the media types** in `
|
|
101
|
+
3. **Swap the media types** in `serverCardMeta()` if your memory / identity
|
|
102
102
|
artifacts aren't `.fafm` / `.fafa`. Drop the `iana` field for any that isn't
|
|
103
103
|
a registered type.
|
|
104
104
|
4. `npm run catalog` to regenerate, `npm run demo` to confirm all three still
|
|
@@ -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.0</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.0</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,11 +78,11 @@ 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.wolfe-jam</span><span class="pill">v0.
|
|
81
|
+
<div class="pills"><span class="pill">io.github.wolfe-jam</span><span class="pill">v0.6.0</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>
|
|
80
|
-
<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
|
|
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>
|
|
81
86
|
<p><code>read_agents_md</code> serves this file, section by section, over the same MCP connection.</p>
|
|
82
87
|
<h2 id="setup">Setup</h2>
|
|
83
88
|
<pre><code class="language-bash">npm ci</code></pre>
|
|
@@ -91,7 +96,7 @@ npm run test:coverage # + the coverage gate (lines 90 / funcs 85 / branches 80,
|
|
|
91
96
|
npm run demo # end to end: all tools over stdio, then over stateless HTTP</code></pre>
|
|
92
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>
|
|
93
98
|
<h2 id="layout">Layout</h2>
|
|
94
|
-
<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> —
|
|
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>
|
|
95
100
|
<h2 id="conventions">Conventions</h2>
|
|
96
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>
|
|
97
102
|
<h2 id="the-invariant">The invariant</h2>
|
|
@@ -101,11 +106,11 @@ npm run demo # end to end: all tools over stdio, then over stateless HT
|
|
|
101
106
|
<h2 id="definition-of-done">Definition of done</h2>
|
|
102
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>
|
|
103
108
|
<h2 id="authoring-this-file">Authoring this file</h2>
|
|
104
|
-
<p><code>AGENTS.md</code> here is maintained by hand.
|
|
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>
|
|
105
110
|
</section>
|
|
106
111
|
<section>
|
|
107
|
-
<p class="label">Memory —
|
|
108
|
-
<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>
|
|
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>
|
|
109
114
|
</section>
|
|
110
115
|
<section>
|
|
111
116
|
<p class="label">Discovery</p>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|