@matrajs/mcp 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nahim Hossain Shohan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @matrajs/mcp
2
+
3
+ The Matra documentation as a [Model Context Protocol](https://modelcontextprotocol.io)
4
+ server, so any AI tool can read it. Zero dependencies, like every other
5
+ Matra package.
6
+
7
+ ```sh
8
+ npx -y @matrajs/mcp # stdio · what a desktop client spawns
9
+ npx -y @matrajs/mcp --http # http://localhost:3333/mcp
10
+ ```
11
+
12
+ ## Connect it, step by step
13
+
14
+ **Claude Code**
15
+
16
+ ```sh
17
+ claude mcp add matra -- npx -y @matrajs/mcp
18
+ ```
19
+
20
+ **Claude Desktop** — in `claude_desktop_config.json`:
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "matra": { "command": "npx", "args": ["-y", "@matrajs/mcp"] }
26
+ }
27
+ }
28
+ ```
29
+
30
+ **Cursor** — in `.cursor/mcp.json`, the same object under `"mcpServers"`.
31
+
32
+ **Codex** — in `~/.codex/config.toml`:
33
+
34
+ ```toml
35
+ [mcp_servers.matra]
36
+ command = "npx"
37
+ args = ["-y", "@matrajs/mcp"]
38
+ ```
39
+
40
+ **Anything that speaks HTTP** — run `npx -y @matrajs/mcp --http 3333` and
41
+ point the client at `http://localhost:3333/mcp`.
42
+
43
+ Then ask the tool something about Matra. It will call `search_docs`, read
44
+ the page it needs, and answer from the documentation rather than from
45
+ memory.
46
+
47
+ ## What it serves
48
+
49
+ | Tool | Does |
50
+ |---|---|
51
+ | `list_docs` | Every page, with its slug and a one-line description. |
52
+ | `read_doc { slug }` | One page, as Markdown. |
53
+ | `search_docs { query, limit? }` | Ranked pages with a snippet each. |
54
+
55
+ Every page is also a resource at `matra://docs/<slug>`.
56
+
57
+ The pages are the repository's Markdown — README, the engine notes,
58
+ benchmarks, security, the changelog — and every page of
59
+ [matrajs.com/docs](https://matrajs.com/docs), converted to Markdown at build
60
+ time and shipped inside the package. Nothing is fetched at runtime.
61
+
62
+ ## Use it from code
63
+
64
+ ```ts
65
+ import { createServer } from '@matrajs/mcp'
66
+
67
+ const server = createServer(docs)
68
+ server.handle({ jsonrpc: '2.0', id: 1, method: 'tools/list' })
69
+ ```
70
+
71
+ `createServer` is the protocol without a transport: one message in, one
72
+ reply out. Put it behind whatever transport you already have.
package/dist/cli.js ADDED
@@ -0,0 +1,362 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, readdirSync } from 'fs';
3
+ import { createServer as createServer$1 } from 'http';
4
+ import { createInterface } from 'readline';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ // src/index.ts
8
+ var PARSE_ERROR = -32700;
9
+ var INVALID_REQUEST = -32600;
10
+ var METHOD_NOT_FOUND = -32601;
11
+ var INVALID_PARAMS = -32602;
12
+ var RpcError = class extends Error {
13
+ constructor(code, message) {
14
+ super(message);
15
+ this.code = code;
16
+ }
17
+ code;
18
+ };
19
+ var PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
20
+ var LATEST = PROTOCOL_VERSIONS[0];
21
+ var tokens = (text) => text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 1);
22
+ function searchDocs(docs, query, limit = 5) {
23
+ const terms = tokens(query);
24
+ if (!terms.length) return [];
25
+ const hits = [];
26
+ for (const doc of docs) {
27
+ const title = doc.title.toLowerCase();
28
+ const body = doc.text.toLowerCase();
29
+ let score = 0;
30
+ let missing = false;
31
+ for (const term of terms) {
32
+ const inTitle = title.includes(term) ? 3 : 0;
33
+ let inBody = 0;
34
+ let at = body.indexOf(term);
35
+ while (at !== -1 && inBody < 20) {
36
+ inBody++;
37
+ at = body.indexOf(term, at + term.length);
38
+ }
39
+ if (!inTitle && !inBody) {
40
+ missing = true;
41
+ break;
42
+ }
43
+ score += inTitle + inBody;
44
+ }
45
+ if (missing) continue;
46
+ hits.push({ doc, score, snippet: snippetFor(doc.text, terms[0]) });
47
+ }
48
+ hits.sort((a, b) => b.score - a.score || a.doc.title.localeCompare(b.doc.title));
49
+ return hits.slice(0, Math.max(1, Math.min(limit, 20)));
50
+ }
51
+ function snippetFor(text, term) {
52
+ const lower = text.toLowerCase();
53
+ const at = lower.indexOf(term);
54
+ if (at === -1) return text.slice(0, 200).replace(/\s+/g, " ").trim();
55
+ const start = Math.max(0, at - 120);
56
+ const end = Math.min(text.length, at + 200);
57
+ return `${start > 0 ? "\u2026" : ""}${text.slice(start, end).replace(/\s+/g, " ").trim()}${end < text.length ? "\u2026" : ""}`;
58
+ }
59
+ var URI_PREFIX = "matra://docs/";
60
+ var TOOLS = [
61
+ {
62
+ name: "list_docs",
63
+ title: "List the documentation",
64
+ description: "Every page of the Matra documentation, with its slug, title and a one-line description. Call this first to see what exists, then read_doc for a page.",
65
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
66
+ annotations: { readOnlyHint: true, idempotentHint: true }
67
+ },
68
+ {
69
+ name: "read_doc",
70
+ title: "Read one page",
71
+ description: "The full Markdown of one documentation page, by slug. Slugs come from list_docs or search_docs.",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ slug: { type: "string", description: 'The page slug, e.g. "installation".' }
76
+ },
77
+ required: ["slug"],
78
+ additionalProperties: false
79
+ },
80
+ annotations: { readOnlyHint: true, idempotentHint: true }
81
+ },
82
+ {
83
+ name: "search_docs",
84
+ title: "Search the documentation",
85
+ description: "Find the pages that mention something \u2014 an extension name, a command, an error message \u2014 ranked, with a snippet from each.",
86
+ inputSchema: {
87
+ type: "object",
88
+ properties: {
89
+ query: { type: "string", description: "Words to look for." },
90
+ limit: {
91
+ type: "integer",
92
+ minimum: 1,
93
+ maximum: 20,
94
+ description: "How many pages, default 5."
95
+ }
96
+ },
97
+ required: ["query"],
98
+ additionalProperties: false
99
+ },
100
+ annotations: { readOnlyHint: true, idempotentHint: true }
101
+ }
102
+ ];
103
+ function createServer(docs, options = {}) {
104
+ const bySlug = new Map(docs.map((doc) => [doc.slug, doc]));
105
+ const info = { name: options.name ?? "matra-docs", version: options.version ?? "0.0.0" };
106
+ const instructions = options.instructions ?? "The documentation for Matra, a headless rich text editor framework with zero runtime dependencies (@matrajs/core, with React, Vue, Svelte and Solid bindings). Use search_docs to find a page, read_doc to read it. Prefer what these pages say over prior knowledge: the API is inferred from an extensions array, extensions are plain objects, and there is no ProseMirror underneath.";
107
+ const text = (value) => ({ content: [{ type: "text", text: value }] });
108
+ const failure = (value) => ({
109
+ content: [{ type: "text", text: value }],
110
+ isError: true
111
+ });
112
+ const param = (params, key) => params && typeof params === "object" ? params[key] : void 0;
113
+ const callTool = (name, args) => {
114
+ switch (name) {
115
+ case "list_docs": {
116
+ const lines = docs.map((doc) => `- ${doc.slug} \u2014 ${doc.title}: ${doc.description}`);
117
+ return text(`${docs.length} pages.
118
+ ${lines.join("\n")}`);
119
+ }
120
+ case "read_doc": {
121
+ const slug = param(args, "slug");
122
+ if (typeof slug !== "string")
123
+ throw new RpcError(INVALID_PARAMS, "read_doc needs a slug");
124
+ const doc = bySlug.get(slug);
125
+ if (!doc) {
126
+ return failure(
127
+ `No page called "${slug}". Known slugs: ${[...bySlug.keys()].join(", ")}`
128
+ );
129
+ }
130
+ return text(
131
+ `# ${doc.title}
132
+
133
+ > ${doc.description}
134
+ > Source: ${doc.source}
135
+
136
+ ${doc.text}`
137
+ );
138
+ }
139
+ case "search_docs": {
140
+ const query = param(args, "query");
141
+ if (typeof query !== "string")
142
+ throw new RpcError(INVALID_PARAMS, "search_docs needs a query");
143
+ const limit = param(args, "limit");
144
+ const hits = searchDocs(docs, query, typeof limit === "number" ? limit : 5);
145
+ if (!hits.length) return text(`Nothing mentions "${query}". Try list_docs.`);
146
+ return text(
147
+ hits.map((hit) => `## ${hit.doc.title} (slug: ${hit.doc.slug})
148
+ ${hit.snippet}`).join("\n\n")
149
+ );
150
+ }
151
+ default:
152
+ throw new RpcError(INVALID_PARAMS, `Unknown tool "${String(name)}"`);
153
+ }
154
+ };
155
+ const dispatch = (method, params) => {
156
+ switch (method) {
157
+ case "initialize": {
158
+ const asked = param(params, "protocolVersion");
159
+ const protocolVersion = typeof asked === "string" && PROTOCOL_VERSIONS.includes(asked) ? asked : LATEST;
160
+ return {
161
+ protocolVersion,
162
+ capabilities: { tools: { listChanged: false }, resources: { listChanged: false } },
163
+ serverInfo: { ...info, title: "Matra docs" },
164
+ instructions
165
+ };
166
+ }
167
+ case "ping":
168
+ return {};
169
+ case "tools/list":
170
+ return { tools: TOOLS };
171
+ case "tools/call":
172
+ return callTool(param(params, "name"), param(params, "arguments"));
173
+ case "resources/list":
174
+ return {
175
+ resources: docs.map((doc) => ({
176
+ uri: `${URI_PREFIX}${doc.slug}`,
177
+ name: doc.slug,
178
+ title: doc.title,
179
+ description: doc.description,
180
+ mimeType: "text/markdown"
181
+ }))
182
+ };
183
+ case "resources/templates/list":
184
+ return { resourceTemplates: [] };
185
+ case "resources/read": {
186
+ const uri = param(params, "uri");
187
+ if (typeof uri !== "string" || !uri.startsWith(URI_PREFIX)) {
188
+ throw new RpcError(INVALID_PARAMS, `Not a matra:// documentation URI: ${String(uri)}`);
189
+ }
190
+ const doc = bySlug.get(uri.slice(URI_PREFIX.length));
191
+ if (!doc) throw new RpcError(INVALID_PARAMS, `No page at ${uri}`);
192
+ return { contents: [{ uri, mimeType: "text/markdown", text: doc.text }] };
193
+ }
194
+ case "prompts/list":
195
+ return { prompts: [] };
196
+ case "logging/setLevel":
197
+ return {};
198
+ default:
199
+ throw new RpcError(METHOD_NOT_FOUND, `Method not found: ${method}`);
200
+ }
201
+ };
202
+ const handle = (message) => {
203
+ const request = message;
204
+ const id = request && typeof request === "object" && "id" in request ? request.id ?? null : null;
205
+ if (!request || typeof request !== "object" || request.jsonrpc !== "2.0" || typeof request.method !== "string") {
206
+ return {
207
+ jsonrpc: "2.0",
208
+ id,
209
+ error: { code: INVALID_REQUEST, message: "Not a JSON-RPC 2.0 request" }
210
+ };
211
+ }
212
+ const isNotification = !("id" in request) || request.id === void 0;
213
+ if (request.method.startsWith("notifications/")) return null;
214
+ try {
215
+ const result = dispatch(request.method, request.params);
216
+ return isNotification ? null : { jsonrpc: "2.0", id, result };
217
+ } catch (error) {
218
+ if (isNotification) return null;
219
+ const code = error instanceof RpcError ? error.code : -32603;
220
+ const message2 = error instanceof Error ? error.message : String(error);
221
+ return { jsonrpc: "2.0", id, error: { code, message: message2 } };
222
+ }
223
+ };
224
+ const handleRaw = (json) => {
225
+ let parsed;
226
+ try {
227
+ parsed = JSON.parse(json);
228
+ } catch {
229
+ return { jsonrpc: "2.0", id: null, error: { code: PARSE_ERROR, message: "Parse error" } };
230
+ }
231
+ if (Array.isArray(parsed)) {
232
+ const replies = parsed.map(handle).filter((reply) => reply !== null);
233
+ return replies.length ? replies : null;
234
+ }
235
+ return handle(parsed);
236
+ };
237
+ return { handle, handleRaw, docs };
238
+ }
239
+
240
+ // src/cli.ts
241
+ var here = fileURLToPath(new URL(".", import.meta.url));
242
+ var packageJson = JSON.parse(
243
+ readFileSync(new URL("../package.json", import.meta.url), "utf8")
244
+ );
245
+ function loadDocs(dir) {
246
+ const manifest = JSON.parse(readFileSync(`${dir}/index.json`, "utf8"));
247
+ const files = new Set(readdirSync(dir));
248
+ return manifest.filter((entry) => files.has(entry.file)).map(({ file, ...entry }) => ({ ...entry, text: readFileSync(`${dir}/${file}`, "utf8") }));
249
+ }
250
+ function parseArgs(argv) {
251
+ let http = null;
252
+ let docs = `${here}../docs`;
253
+ for (let i = 0; i < argv.length; i++) {
254
+ const arg = argv[i];
255
+ if (arg === "--http") {
256
+ const port = Number(argv[i + 1]);
257
+ http = Number.isInteger(port) && port > 0 ? port : 3333;
258
+ if (Number.isInteger(port)) i++;
259
+ } else if (arg === "--docs") {
260
+ docs = argv[++i] ?? docs;
261
+ } else if (arg === "--help" || arg === "-h") {
262
+ process.stderr.write(
263
+ "matra-mcp [--http [port]] [--docs <dir>]\n\nThe Matra documentation as an MCP server. Stdio by default.\n"
264
+ );
265
+ process.exit(0);
266
+ } else if (arg === "--version" || arg === "-v") {
267
+ process.stdout.write(`${packageJson.version}
268
+ `);
269
+ process.exit(0);
270
+ }
271
+ }
272
+ return { http, docs };
273
+ }
274
+ function main() {
275
+ const { http, docs: dir } = parseArgs(process.argv.slice(2));
276
+ let docs;
277
+ try {
278
+ docs = loadDocs(dir);
279
+ } catch (error) {
280
+ process.stderr.write(
281
+ `matra-mcp: cannot read the documentation in ${dir}: ${String(error)}
282
+ `
283
+ );
284
+ process.exit(1);
285
+ }
286
+ const server = createServer(docs, { version: packageJson.version });
287
+ if (http !== null) {
288
+ serveHttp(server, http);
289
+ return;
290
+ }
291
+ serveStdio(server);
292
+ }
293
+ function serveStdio(server) {
294
+ const lines = createInterface({ input: process.stdin, crlfDelay: Number.POSITIVE_INFINITY });
295
+ lines.on("line", (line) => {
296
+ if (!line.trim()) return;
297
+ const reply = server.handleRaw(line);
298
+ if (reply) process.stdout.write(`${JSON.stringify(reply)}
299
+ `);
300
+ });
301
+ lines.on("close", () => process.exit(0));
302
+ process.stderr.write(`matra-mcp: ${server.docs.length} pages, stdio
303
+ `);
304
+ }
305
+ function serveHttp(server, port) {
306
+ const http = createServer$1((request, response) => {
307
+ const url = new URL(request.url ?? "/", "http://localhost");
308
+ const headers = {
309
+ "Content-Type": "application/json",
310
+ "Access-Control-Allow-Origin": "*",
311
+ "Access-Control-Allow-Headers": "Content-Type, Accept, Mcp-Session-Id, MCP-Protocol-Version",
312
+ "Access-Control-Allow-Methods": "POST, GET, DELETE, OPTIONS"
313
+ };
314
+ if (request.method === "OPTIONS") {
315
+ response.writeHead(204, headers);
316
+ response.end();
317
+ return;
318
+ }
319
+ if (url.pathname !== "/mcp") {
320
+ response.writeHead(404, headers);
321
+ response.end(JSON.stringify({ error: "POST JSON-RPC to /mcp" }));
322
+ return;
323
+ }
324
+ if (request.method === "DELETE") {
325
+ response.writeHead(200, headers);
326
+ response.end();
327
+ return;
328
+ }
329
+ if (request.method !== "POST") {
330
+ response.writeHead(405, { ...headers, Allow: "POST" });
331
+ response.end();
332
+ return;
333
+ }
334
+ let body = "";
335
+ request.setEncoding("utf8");
336
+ request.on("data", (chunk) => {
337
+ body += chunk;
338
+ if (body.length > 1e6) request.destroy();
339
+ });
340
+ request.on("end", () => {
341
+ const reply = server.handleRaw(body);
342
+ if (!reply) {
343
+ response.writeHead(202, headers);
344
+ response.end();
345
+ return;
346
+ }
347
+ response.writeHead(200, headers);
348
+ response.end(JSON.stringify(reply));
349
+ });
350
+ });
351
+ http.listen(port, () => {
352
+ process.stderr.write(
353
+ `matra-mcp: ${server.docs.length} pages at http://localhost:${port}/mcp
354
+ `
355
+ );
356
+ });
357
+ }
358
+ main();
359
+
360
+ export { loadDocs };
361
+ //# sourceMappingURL=cli.js.map
362
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/cli.ts"],"names":["message","createHttpServer"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * The Matra documentation, served over the Model Context Protocol.\n *\n * MCP is JSON-RPC 2.0 with a handshake and a small vocabulary — tools,\n * resources, prompts — that Claude, Cursor, Codex and the rest all speak. This\n * module is the protocol half: it takes one message and returns one reply,\n * and knows nothing about where either came from. The transports — stdio and\n * HTTP — are in `cli.ts`, and a test drives this without either.\n *\n * Written against the spec directly, with no SDK, because every other package\n * here has zero runtime dependencies and the one that exists to be installed\n * with `npx` should not be the exception.\n */\n\n/** One page of documentation. */\nexport interface Doc {\n /** URL-safe, unique: `installation`, `engine`, `changelog`. */\n slug: string\n title: string\n description: string\n /** Where it came from — a path in the repository, or a page on the site. */\n source: string\n /** Markdown. */\n text: string\n}\n\nexport interface ServerOptions {\n name?: string\n version?: string\n /** What a client is told about this server when it connects. */\n instructions?: string\n}\n\n// --- JSON-RPC ---------------------------------------------------------------\n\nexport type JsonRpcId = string | number | null\n\nexport interface JsonRpcRequest {\n jsonrpc: '2.0'\n id?: JsonRpcId\n method: string\n params?: Record<string, unknown>\n}\n\nexport interface JsonRpcResponse {\n jsonrpc: '2.0'\n id: JsonRpcId\n result?: unknown\n error?: { code: number; message: string; data?: unknown }\n}\n\nconst PARSE_ERROR = -32700\nconst INVALID_REQUEST = -32600\nconst METHOD_NOT_FOUND = -32601\nconst INVALID_PARAMS = -32602\n\nclass RpcError extends Error {\n constructor(\n readonly code: number,\n message: string,\n ) {\n super(message)\n }\n}\n\n/** Protocol revisions this server can speak, newest first. */\nexport const PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'] as const\n\nconst LATEST = PROTOCOL_VERSIONS[0]\n\n// --- searching ----------------------------------------------------------------\n\nconst tokens = (text: string): string[] =>\n text\n .toLowerCase()\n .split(/[^\\p{L}\\p{N}]+/u)\n .filter((word) => word.length > 1)\n\ninterface Hit {\n doc: Doc\n score: number\n snippet: string\n}\n\n/**\n * Rank pages for a query.\n *\n * Term frequency, with the title worth more than the body and every term\n * required to appear somewhere. Small enough to read, good enough for twenty\n * pages of documentation, and it needs no index built in advance.\n */\nexport function searchDocs(docs: readonly Doc[], query: string, limit = 5): Hit[] {\n const terms = tokens(query)\n if (!terms.length) return []\n const hits: Hit[] = []\n for (const doc of docs) {\n const title = doc.title.toLowerCase()\n const body = doc.text.toLowerCase()\n let score = 0\n let missing = false\n for (const term of terms) {\n const inTitle = title.includes(term) ? 3 : 0\n let inBody = 0\n let at = body.indexOf(term)\n while (at !== -1 && inBody < 20) {\n inBody++\n at = body.indexOf(term, at + term.length)\n }\n if (!inTitle && !inBody) {\n missing = true\n break\n }\n score += inTitle + inBody\n }\n if (missing) continue\n hits.push({ doc, score, snippet: snippetFor(doc.text, terms[0] as string) })\n }\n hits.sort((a, b) => b.score - a.score || a.doc.title.localeCompare(b.doc.title))\n return hits.slice(0, Math.max(1, Math.min(limit, 20)))\n}\n\n/** A line or two around the first place a term appears. */\nfunction snippetFor(text: string, term: string): string {\n const lower = text.toLowerCase()\n const at = lower.indexOf(term)\n if (at === -1) return text.slice(0, 200).replace(/\\s+/g, ' ').trim()\n const start = Math.max(0, at - 120)\n const end = Math.min(text.length, at + 200)\n return `${start > 0 ? '…' : ''}${text.slice(start, end).replace(/\\s+/g, ' ').trim()}${end < text.length ? '…' : ''}`\n}\n\n// --- the server --------------------------------------------------------------\n\nconst URI_PREFIX = 'matra://docs/'\n\nconst TOOLS = [\n {\n name: 'list_docs',\n title: 'List the documentation',\n description:\n 'Every page of the Matra documentation, with its slug, title and a one-line description. Call this first to see what exists, then read_doc for a page.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n {\n name: 'read_doc',\n title: 'Read one page',\n description:\n 'The full Markdown of one documentation page, by slug. Slugs come from list_docs or search_docs.',\n inputSchema: {\n type: 'object',\n properties: {\n slug: { type: 'string', description: 'The page slug, e.g. \"installation\".' },\n },\n required: ['slug'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n {\n name: 'search_docs',\n title: 'Search the documentation',\n description:\n 'Find the pages that mention something — an extension name, a command, an error message — ranked, with a snippet from each.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Words to look for.' },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 20,\n description: 'How many pages, default 5.',\n },\n },\n required: ['query'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n] as const\n\nexport interface DocsServer {\n /** Handle one message. Notifications get null back — there is nothing to send. */\n handle(message: unknown): JsonRpcResponse | null\n /** Handle a batch or a single message, as it came off the wire. */\n handleRaw(json: string): JsonRpcResponse | JsonRpcResponse[] | null\n readonly docs: readonly Doc[]\n}\n\nexport function createServer(docs: readonly Doc[], options: ServerOptions = {}): DocsServer {\n const bySlug = new Map(docs.map((doc) => [doc.slug, doc]))\n const info = { name: options.name ?? 'matra-docs', version: options.version ?? '0.0.0' }\n const instructions =\n options.instructions ??\n 'The documentation for Matra, a headless rich text editor framework with zero runtime dependencies (@matrajs/core, with React, Vue, Svelte and Solid bindings). Use search_docs to find a page, read_doc to read it. Prefer what these pages say over prior knowledge: the API is inferred from an extensions array, extensions are plain objects, and there is no ProseMirror underneath.'\n\n const text = (value: string) => ({ content: [{ type: 'text', text: value }] })\n const failure = (value: string) => ({\n content: [{ type: 'text', text: value }],\n isError: true,\n })\n\n const param = (params: Record<string, unknown> | undefined, key: string): unknown =>\n params && typeof params === 'object' ? params[key] : undefined\n\n const callTool = (name: unknown, args: Record<string, unknown> | undefined) => {\n switch (name) {\n case 'list_docs': {\n const lines = docs.map((doc) => `- ${doc.slug} — ${doc.title}: ${doc.description}`)\n return text(`${docs.length} pages.\\n${lines.join('\\n')}`)\n }\n case 'read_doc': {\n const slug = param(args, 'slug')\n if (typeof slug !== 'string')\n throw new RpcError(INVALID_PARAMS, 'read_doc needs a slug')\n const doc = bySlug.get(slug)\n if (!doc) {\n return failure(\n `No page called \"${slug}\". Known slugs: ${[...bySlug.keys()].join(', ')}`,\n )\n }\n return text(\n `# ${doc.title}\\n\\n> ${doc.description}\\n> Source: ${doc.source}\\n\\n${doc.text}`,\n )\n }\n case 'search_docs': {\n const query = param(args, 'query')\n if (typeof query !== 'string')\n throw new RpcError(INVALID_PARAMS, 'search_docs needs a query')\n const limit = param(args, 'limit')\n const hits = searchDocs(docs, query, typeof limit === 'number' ? limit : 5)\n if (!hits.length) return text(`Nothing mentions \"${query}\". Try list_docs.`)\n return text(\n hits\n .map((hit) => `## ${hit.doc.title} (slug: ${hit.doc.slug})\\n${hit.snippet}`)\n .join('\\n\\n'),\n )\n }\n default:\n throw new RpcError(INVALID_PARAMS, `Unknown tool \"${String(name)}\"`)\n }\n }\n\n const dispatch = (method: string, params: Record<string, unknown> | undefined): unknown => {\n switch (method) {\n case 'initialize': {\n const asked = param(params, 'protocolVersion')\n const protocolVersion =\n typeof asked === 'string' && (PROTOCOL_VERSIONS as readonly string[]).includes(asked)\n ? asked\n : LATEST\n return {\n protocolVersion,\n capabilities: { tools: { listChanged: false }, resources: { listChanged: false } },\n serverInfo: { ...info, title: 'Matra docs' },\n instructions,\n }\n }\n case 'ping':\n return {}\n case 'tools/list':\n return { tools: TOOLS }\n case 'tools/call':\n return callTool(param(params, 'name'), param(params, 'arguments') as never)\n case 'resources/list':\n return {\n resources: docs.map((doc) => ({\n uri: `${URI_PREFIX}${doc.slug}`,\n name: doc.slug,\n title: doc.title,\n description: doc.description,\n mimeType: 'text/markdown',\n })),\n }\n case 'resources/templates/list':\n return { resourceTemplates: [] }\n case 'resources/read': {\n const uri = param(params, 'uri')\n if (typeof uri !== 'string' || !uri.startsWith(URI_PREFIX)) {\n throw new RpcError(INVALID_PARAMS, `Not a matra:// documentation URI: ${String(uri)}`)\n }\n const doc = bySlug.get(uri.slice(URI_PREFIX.length))\n if (!doc) throw new RpcError(INVALID_PARAMS, `No page at ${uri}`)\n return { contents: [{ uri, mimeType: 'text/markdown', text: doc.text }] }\n }\n case 'prompts/list':\n return { prompts: [] }\n case 'logging/setLevel':\n return {}\n default:\n throw new RpcError(METHOD_NOT_FOUND, `Method not found: ${method}`)\n }\n }\n\n const handle = (message: unknown): JsonRpcResponse | null => {\n const request = message as Partial<JsonRpcRequest> | null\n const id: JsonRpcId =\n request && typeof request === 'object' && 'id' in request ? (request.id ?? null) : null\n if (\n !request ||\n typeof request !== 'object' ||\n request.jsonrpc !== '2.0' ||\n typeof request.method !== 'string'\n ) {\n return {\n jsonrpc: '2.0',\n id,\n error: { code: INVALID_REQUEST, message: 'Not a JSON-RPC 2.0 request' },\n }\n }\n // A notification carries no id and gets no reply.\n const isNotification = !('id' in request) || request.id === undefined\n if (request.method.startsWith('notifications/')) return null\n try {\n const result = dispatch(request.method, request.params)\n return isNotification ? null : { jsonrpc: '2.0', id, result }\n } catch (error) {\n if (isNotification) return null\n const code = error instanceof RpcError ? error.code : -32603\n const message = error instanceof Error ? error.message : String(error)\n return { jsonrpc: '2.0', id, error: { code, message } }\n }\n }\n\n const handleRaw = (json: string): JsonRpcResponse | JsonRpcResponse[] | null => {\n let parsed: unknown\n try {\n parsed = JSON.parse(json)\n } catch {\n return { jsonrpc: '2.0', id: null, error: { code: PARSE_ERROR, message: 'Parse error' } }\n }\n if (Array.isArray(parsed)) {\n const replies = parsed\n .map(handle)\n .filter((reply): reply is JsonRpcResponse => reply !== null)\n return replies.length ? replies : null\n }\n return handle(parsed)\n }\n\n return { handle, handleRaw, docs }\n}\n","#!/usr/bin/env node\n/// <reference types=\"node\" />\n/**\n * `matra-mcp` — the Matra documentation as an MCP server.\n *\n * matra-mcp stdio, which is what a desktop client spawns\n * matra-mcp --http 3333 Streamable HTTP on http://localhost:3333/mcp\n * matra-mcp --docs ./dir serve another directory of pages\n *\n * Both transports feed the same `createServer`. Stdio is newline-delimited\n * JSON on stdin and stdout, with everything human going to stderr so it never\n * lands in the protocol stream. HTTP is one POST per message, answered with\n * JSON — the simplest legal shape of the streamable transport, and enough for\n * a documentation server with nothing to push.\n */\nimport { readFileSync, readdirSync } from 'node:fs'\nimport { createServer as createHttpServer } from 'node:http'\nimport { createInterface } from 'node:readline'\nimport { fileURLToPath } from 'node:url'\nimport { type Doc, createServer } from './index'\n\nconst here = fileURLToPath(new URL('.', import.meta.url))\nconst packageJson = JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf8'),\n) as {\n version: string\n}\n\n/** Read the pages the build wrote. */\nexport function loadDocs(dir: string): Doc[] {\n const manifest = JSON.parse(readFileSync(`${dir}/index.json`, 'utf8')) as Array<\n Omit<Doc, 'text'> & { file: string }\n >\n const files = new Set(readdirSync(dir))\n return manifest\n .filter((entry) => files.has(entry.file))\n .map(({ file, ...entry }) => ({ ...entry, text: readFileSync(`${dir}/${file}`, 'utf8') }))\n}\n\nfunction parseArgs(argv: string[]): { http: number | null; docs: string } {\n let http: number | null = null\n let docs = `${here}../docs`\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]\n if (arg === '--http') {\n const port = Number(argv[i + 1])\n http = Number.isInteger(port) && port > 0 ? port : 3333\n if (Number.isInteger(port)) i++\n } else if (arg === '--docs') {\n docs = argv[++i] ?? docs\n } else if (arg === '--help' || arg === '-h') {\n process.stderr.write(\n 'matra-mcp [--http [port]] [--docs <dir>]\\n\\nThe Matra documentation as an MCP server. Stdio by default.\\n',\n )\n process.exit(0)\n } else if (arg === '--version' || arg === '-v') {\n process.stdout.write(`${packageJson.version}\\n`)\n process.exit(0)\n }\n }\n return { http, docs }\n}\n\nfunction main(): void {\n const { http, docs: dir } = parseArgs(process.argv.slice(2))\n let docs: Doc[]\n try {\n docs = loadDocs(dir)\n } catch (error) {\n process.stderr.write(\n `matra-mcp: cannot read the documentation in ${dir}: ${String(error)}\\n`,\n )\n process.exit(1)\n }\n const server = createServer(docs, { version: packageJson.version })\n\n if (http !== null) {\n serveHttp(server, http)\n return\n }\n serveStdio(server)\n}\n\nfunction serveStdio(server: ReturnType<typeof createServer>): void {\n const lines = createInterface({ input: process.stdin, crlfDelay: Number.POSITIVE_INFINITY })\n lines.on('line', (line) => {\n if (!line.trim()) return\n const reply = server.handleRaw(line)\n if (reply) process.stdout.write(`${JSON.stringify(reply)}\\n`)\n })\n lines.on('close', () => process.exit(0))\n process.stderr.write(`matra-mcp: ${server.docs.length} pages, stdio\\n`)\n}\n\nfunction serveHttp(server: ReturnType<typeof createServer>, port: number): void {\n const http = createHttpServer((request, response) => {\n const url = new URL(request.url ?? '/', 'http://localhost')\n const headers = {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Headers':\n 'Content-Type, Accept, Mcp-Session-Id, MCP-Protocol-Version',\n 'Access-Control-Allow-Methods': 'POST, GET, DELETE, OPTIONS',\n }\n if (request.method === 'OPTIONS') {\n response.writeHead(204, headers)\n response.end()\n return\n }\n if (url.pathname !== '/mcp') {\n response.writeHead(404, headers)\n response.end(JSON.stringify({ error: 'POST JSON-RPC to /mcp' }))\n return\n }\n if (request.method === 'DELETE') {\n response.writeHead(200, headers)\n response.end()\n return\n }\n if (request.method !== 'POST') {\n // No server-initiated messages, so there is no stream to open.\n response.writeHead(405, { ...headers, Allow: 'POST' })\n response.end()\n return\n }\n let body = ''\n request.setEncoding('utf8')\n request.on('data', (chunk: string) => {\n body += chunk\n if (body.length > 1_000_000) request.destroy()\n })\n request.on('end', () => {\n const reply = server.handleRaw(body)\n if (!reply) {\n response.writeHead(202, headers)\n response.end()\n return\n }\n response.writeHead(200, headers)\n response.end(JSON.stringify(reply))\n })\n })\n http.listen(port, () => {\n process.stderr.write(\n `matra-mcp: ${server.docs.length} pages at http://localhost:${port}/mcp\\n`,\n )\n })\n}\n\nmain()\n"]}