@nifrajs/cli 0.1.0-alpha.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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/check.d.ts +100 -0
  4. package/dist/check.d.ts.map +1 -0
  5. package/dist/check.js +690 -0
  6. package/dist/check.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +208 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/docs-search.d.ts +30 -0
  12. package/dist/docs-search.d.ts.map +1 -0
  13. package/dist/docs-search.js +94 -0
  14. package/dist/docs-search.js.map +1 -0
  15. package/dist/doctor.d.ts +52 -0
  16. package/dist/doctor.d.ts.map +1 -0
  17. package/dist/doctor.js +291 -0
  18. package/dist/doctor.js.map +1 -0
  19. package/dist/examples.d.ts +30 -0
  20. package/dist/examples.d.ts.map +1 -0
  21. package/dist/examples.js +70 -0
  22. package/dist/examples.js.map +1 -0
  23. package/dist/introspect.d.ts +64 -0
  24. package/dist/introspect.d.ts.map +1 -0
  25. package/dist/introspect.js +243 -0
  26. package/dist/introspect.js.map +1 -0
  27. package/dist/load.d.ts +51 -0
  28. package/dist/load.d.ts.map +1 -0
  29. package/dist/load.js +70 -0
  30. package/dist/load.js.map +1 -0
  31. package/dist/mcp-docs-tools.d.ts +13 -0
  32. package/dist/mcp-docs-tools.d.ts.map +1 -0
  33. package/dist/mcp-docs-tools.js +63 -0
  34. package/dist/mcp-docs-tools.js.map +1 -0
  35. package/dist/mcp-http.d.ts +43 -0
  36. package/dist/mcp-http.d.ts.map +1 -0
  37. package/dist/mcp-http.js +136 -0
  38. package/dist/mcp-http.js.map +1 -0
  39. package/dist/mcp-protocol.d.ts +97 -0
  40. package/dist/mcp-protocol.d.ts.map +1 -0
  41. package/dist/mcp-protocol.js +248 -0
  42. package/dist/mcp-protocol.js.map +1 -0
  43. package/dist/mcp-render.d.ts +17 -0
  44. package/dist/mcp-render.d.ts.map +1 -0
  45. package/dist/mcp-render.js +73 -0
  46. package/dist/mcp-render.js.map +1 -0
  47. package/dist/mcp-run.d.ts +24 -0
  48. package/dist/mcp-run.d.ts.map +1 -0
  49. package/dist/mcp-run.js +142 -0
  50. package/dist/mcp-run.js.map +1 -0
  51. package/dist/mcp-ws.d.ts +26 -0
  52. package/dist/mcp-ws.d.ts.map +1 -0
  53. package/dist/mcp-ws.js +258 -0
  54. package/dist/mcp-ws.js.map +1 -0
  55. package/dist/mcp.d.ts +42 -0
  56. package/dist/mcp.d.ts.map +1 -0
  57. package/dist/mcp.js +712 -0
  58. package/dist/mcp.js.map +1 -0
  59. package/dist/openapi-tool.d.ts +6 -0
  60. package/dist/openapi-tool.d.ts.map +1 -0
  61. package/dist/openapi-tool.js +48 -0
  62. package/dist/openapi-tool.js.map +1 -0
  63. package/dist/scaffold.d.ts +35 -0
  64. package/dist/scaffold.d.ts.map +1 -0
  65. package/dist/scaffold.js +140 -0
  66. package/dist/scaffold.js.map +1 -0
  67. package/dist/search-terms.d.ts +17 -0
  68. package/dist/search-terms.d.ts.map +1 -0
  69. package/dist/search-terms.js +82 -0
  70. package/dist/search-terms.js.map +1 -0
  71. package/dist/test-tool.d.ts +29 -0
  72. package/dist/test-tool.d.ts.map +1 -0
  73. package/dist/test-tool.js +150 -0
  74. package/dist/test-tool.js.map +1 -0
  75. package/docs/examples.json +314 -0
  76. package/docs/llms-full.txt +4325 -0
  77. package/package.json +58 -0
  78. package/src/check.ts +790 -0
  79. package/src/cli.ts +237 -0
  80. package/src/docs-search.ts +111 -0
  81. package/src/doctor.ts +349 -0
  82. package/src/examples.ts +89 -0
  83. package/src/introspect.ts +284 -0
  84. package/src/load.ts +129 -0
  85. package/src/mcp-docs-tools.ts +72 -0
  86. package/src/mcp-http.ts +155 -0
  87. package/src/mcp-protocol.ts +326 -0
  88. package/src/mcp-render.ts +78 -0
  89. package/src/mcp-run.ts +153 -0
  90. package/src/mcp-ws.ts +328 -0
  91. package/src/mcp.ts +863 -0
  92. package/src/openapi-tool.ts +51 -0
  93. package/src/scaffold.ts +164 -0
  94. package/src/search-terms.ts +89 -0
  95. package/src/test-tool.ts +181 -0
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The PUBLIC nifra docs MCP — Streamable-HTTP transport exposing the project-INDEPENDENT tools
3
+ * (`nifra_docs` + `nifra_example`) so any remote AI agent can learn nifra without a local checkout.
4
+ * Both tools read the bundled corpus (llms-full.txt / examples.json shipped in this package) and ignore
5
+ * `cwd`, so they reuse the exact definitions from {@link projectTools} — one source, no drift.
6
+ *
7
+ * {@link handleMcpHttp} is a plain Web `fetch` handler, so it self-hosts ANYWHERE Bun runs — the
8
+ * simplest path is `nifra docs-mcp` on a VPS behind a reverse proxy (Caddy/nginx + TLS), where the
9
+ * bundled corpus reads straight from disk (`Bun.file`). `export default { port, fetch }` also lets
10
+ * `bun run mcp-http.ts` serve it directly, and the same handler runs on Cloudflare/Vercel edge — only
11
+ * there must you inline the two corpus files as string imports (a Worker has no filesystem). The
12
+ * dispatch is the shared, transport-agnostic {@link handleRpc}.
13
+ */
14
+ import { loadDocsCorpus } from "./docs-search.js";
15
+ import { loadExamplesCorpus } from "./examples.js";
16
+ import { docsTools } from "./mcp-docs-tools.js";
17
+ import { handleRpc, rpcError } from "./mcp-protocol.js";
18
+ // Re-exported so a self-host (e.g. a Cloudflare-Pages `/mcp` worker route) gets the corpus-injectable
19
+ // tool factory + the transport core from one entry: `import { respondMcpHttp, docsTools } from "@nifrajs/cli/mcp"`.
20
+ export { docsTools } from "./mcp-docs-tools.js";
21
+ const VERSION = "0.1.0-alpha.1";
22
+ const SERVER_INFO = { name: "nifra-docs", version: VERSION };
23
+ const CORS = {
24
+ "access-control-allow-origin": "*",
25
+ "access-control-allow-methods": "POST, GET, OPTIONS",
26
+ "access-control-allow-headers": "content-type",
27
+ };
28
+ const DEFAULT_MAX_BODY_BYTES = 1_000_000;
29
+ const TEXT_DECODER = new TextDecoder();
30
+ function parseContentLength(value) {
31
+ if (value.length === 0)
32
+ return undefined;
33
+ let length = 0;
34
+ for (let i = 0; i < value.length; i++) {
35
+ const digit = value.charCodeAt(i) - 48;
36
+ if (digit < 0 || digit > 9)
37
+ return undefined;
38
+ length = length * 10 + digit;
39
+ if (length > Number.MAX_SAFE_INTEGER)
40
+ return Number.POSITIVE_INFINITY;
41
+ }
42
+ return length;
43
+ }
44
+ async function readJsonBounded(request, maxBytes) {
45
+ const declared = request.headers.get("content-length");
46
+ if (declared !== null) {
47
+ const length = parseContentLength(declared);
48
+ if (length === undefined)
49
+ return { ok: false, status: 400 };
50
+ if (length > maxBytes)
51
+ return { ok: false, status: 413 };
52
+ }
53
+ const body = request.body;
54
+ if (body === null)
55
+ return { ok: false, status: 400 };
56
+ const reader = body.getReader();
57
+ const chunks = [];
58
+ let total = 0;
59
+ for (;;) {
60
+ const { done, value } = await reader.read();
61
+ if (done)
62
+ break;
63
+ total += value.byteLength;
64
+ if (total > maxBytes) {
65
+ await reader.cancel();
66
+ return { ok: false, status: 413 };
67
+ }
68
+ chunks.push(value);
69
+ }
70
+ const bytes = new Uint8Array(total);
71
+ let offset = 0;
72
+ for (const chunk of chunks) {
73
+ bytes.set(chunk, offset);
74
+ offset += chunk.byteLength;
75
+ }
76
+ try {
77
+ return { ok: true, value: JSON.parse(TEXT_DECODER.decode(bytes)) };
78
+ }
79
+ catch {
80
+ return { ok: false, status: 400 };
81
+ }
82
+ }
83
+ /** The two project-independent tools, reading the package's bundled corpus from disk (CLI use). */
84
+ export function publicDocsTools() {
85
+ return docsTools(loadDocsCorpus, loadExamplesCorpus);
86
+ }
87
+ /**
88
+ * The transport core, shared by every HTTP host (CLI `docs-mcp`, the site's edge worker): handle one
89
+ * MCP request against the given `tools`. POST a JSON-RPC body → JSON-RPC response; GET is a health page;
90
+ * OPTIONS is the CORS preflight. Never throws — a bad body becomes a JSON-RPC parse error. Pass the
91
+ * tools so each host supplies its own corpus source (disk vs cached fetch) behind identical defs.
92
+ */
93
+ export async function respondMcpHttp(request, tools, options = {}) {
94
+ if (request.method === "OPTIONS")
95
+ return new Response(null, { status: 204, headers: CORS });
96
+ if (request.method === "GET") {
97
+ return new Response("nifra docs MCP — POST JSON-RPC 2.0 here (methods: initialize, tools/list, tools/call). Tools: nifra_docs, nifra_example.", { headers: { "content-type": "text/plain; charset=utf-8", ...CORS } });
98
+ }
99
+ if (request.method !== "POST") {
100
+ return new Response("method not allowed", {
101
+ status: 405,
102
+ headers: { allow: "POST, GET", ...CORS },
103
+ });
104
+ }
105
+ const parsed = await readJsonBounded(request, options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES);
106
+ if (!parsed.ok) {
107
+ if (parsed.status === 413) {
108
+ return Response.json(rpcError(null, -32000, "payload too large"), {
109
+ status: 413,
110
+ headers: CORS,
111
+ });
112
+ }
113
+ return Response.json(rpcError(null, -32700, "parse error"), { status: 400, headers: CORS });
114
+ }
115
+ const message = parsed.value;
116
+ const response = await handleRpc(message, tools, SERVER_INFO, {}, { signal: request.signal });
117
+ // A notification (no id) yields null — acknowledge with 204, no body.
118
+ if (response === null)
119
+ return new Response(null, { status: 204, headers: CORS });
120
+ return Response.json(response, { headers: CORS });
121
+ }
122
+ /** The CLI HTTP handler: serves the disk-backed corpus tools. (`nifra docs-mcp` / `bun run` this file.) */
123
+ export function handleMcpHttp(request) {
124
+ return respondMcpHttp(request, publicDocsTools());
125
+ }
126
+ /**
127
+ * Worker/edge + local entry. `export default { fetch }` is the universal server shape: Cloudflare /
128
+ * Vercel edge / Deno deploy use `fetch` (and ignore `port`); `bun run mcp-http.ts` auto-serves it on
129
+ * `port` (PORT env, default 8787) — Bun serves a module's default-exported server, so NO manual
130
+ * `Bun.serve` here (that would double-bind the port).
131
+ */
132
+ export default {
133
+ port: typeof Bun !== "undefined" ? Number(Bun.env.PORT ?? 8787) : 8787,
134
+ fetch: handleMcpHttp,
135
+ };
136
+ //# sourceMappingURL=mcp-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-http.js","sourceRoot":"","sources":["../src/mcp-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAqC,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG1F,sGAAsG;AACtG,oHAAoH;AACpH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,MAAM,OAAO,GAAG,eAAe,CAAA;AAC/B,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;AAE5D,MAAM,IAAI,GAA2B;IACnC,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,oBAAoB;IACpD,8BAA8B,EAAE,cAAc;CAC/C,CAAA;AAED,MAAM,sBAAsB,GAAG,SAAS,CAAA;AACxC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAA;AAOtC,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IACxC,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;QACtC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QAC5C,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,KAAK,CAAA;QAC5B,IAAI,MAAM,GAAG,MAAM,CAAC,gBAAgB;YAAE,OAAO,MAAM,CAAC,iBAAiB,CAAA;IACvE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,OAAgB,EAChB,QAAgB;IAEhB,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IACtD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAA;QAC3C,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;QAC3D,IAAI,MAAM,GAAG,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAC1D,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IACzB,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IAEpD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAA;IAC/B,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,SAAS,CAAC;QACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3C,IAAI,IAAI;YAAE,MAAK;QACf,KAAK,IAAI,KAAK,CAAC,UAAU,CAAA;QACzB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACrB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAA;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;QACnC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IACnC,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACxB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAA;IAC5B,CAAC;IACD,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAY,EAAE,CAAA;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;IACnC,CAAC;AACH,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,eAAe;IAC7B,OAAO,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgB,EAChB,KAAgB,EAChB,UAA0B,EAAE;IAE5B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3F,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,OAAO,IAAI,QAAQ,CACjB,0HAA0H,EAC1H,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,GAAG,IAAI,EAAE,EAAE,CACtE,CAAA;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,IAAI,QAAQ,CAAC,oBAAoB,EAAE;YACxC,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE;SACzC,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,sBAAsB,CAAC,CAAA;IAC7F,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE;gBAChE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,IAAI;aACd,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7F,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAuB,CAAA;IAC9C,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7F,sEAAsE;IACtE,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAChF,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;AACnD,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAA;AACnD,CAAC;AAED;;;;;GAKG;AACH,eAAe;IACb,IAAI,EAAE,OAAO,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;IACtE,KAAK,EAAE,aAAa;CACrB,CAAA"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The pure MCP (Model Context Protocol) JSON-RPC dispatch — no I/O, no `Bun.*`, no side effects, so it
3
+ * unit-tests cleanly. {@link runMcpServer} in `./mcp.ts` wires this to stdin/stdout; the tools are
4
+ * injected, so the protocol logic is exercised without spawning or reading streams.
5
+ */
6
+ export declare const PROTOCOL_VERSION = "2024-11-05";
7
+ type RequestId = string | number;
8
+ type JsonRpcId = RequestId | null;
9
+ type ProgressToken = string | number;
10
+ export interface McpToolContext {
11
+ readonly signal: AbortSignal;
12
+ readonly requestId: JsonRpcId;
13
+ readonly progressToken?: ProgressToken;
14
+ readonly reportProgress: (progress: number, total?: number) => void;
15
+ }
16
+ /** A tool the agent can call. `handler` returns the text shown to the agent. */
17
+ export interface McpTool {
18
+ readonly name: string;
19
+ readonly description: string;
20
+ readonly inputSchema: Record<string, unknown>;
21
+ readonly handler: (args: Record<string, unknown>, context: McpToolContext) => Promise<string>;
22
+ }
23
+ export interface McpResource {
24
+ readonly uri: string;
25
+ readonly name: string;
26
+ readonly description?: string;
27
+ readonly mimeType?: string;
28
+ readonly read: () => Promise<{
29
+ readonly text: string;
30
+ readonly mimeType?: string;
31
+ }>;
32
+ }
33
+ export interface McpPromptMessage {
34
+ readonly role: "user" | "assistant";
35
+ readonly content: {
36
+ readonly type: "text";
37
+ readonly text: string;
38
+ };
39
+ }
40
+ export interface McpPrompt {
41
+ readonly name: string;
42
+ readonly description: string;
43
+ readonly arguments?: readonly {
44
+ readonly name: string;
45
+ readonly description?: string;
46
+ readonly required?: boolean;
47
+ }[];
48
+ readonly handler: (args: Record<string, unknown>) => Promise<readonly McpPromptMessage[]>;
49
+ }
50
+ export interface McpServerFeatures {
51
+ readonly resources?: readonly McpResource[];
52
+ readonly prompts?: readonly McpPrompt[];
53
+ }
54
+ export interface JsonRpcRequest {
55
+ readonly jsonrpc?: string;
56
+ readonly id?: JsonRpcId;
57
+ readonly method?: string;
58
+ readonly params?: Record<string, unknown>;
59
+ }
60
+ export interface JsonRpcNotification {
61
+ readonly jsonrpc: "2.0";
62
+ readonly method: string;
63
+ readonly params?: Record<string, unknown>;
64
+ }
65
+ export type JsonRpcResponse = {
66
+ jsonrpc: "2.0";
67
+ id: JsonRpcId;
68
+ result: unknown;
69
+ } | {
70
+ jsonrpc: "2.0";
71
+ id: JsonRpcId;
72
+ error: {
73
+ code: number;
74
+ message: string;
75
+ };
76
+ };
77
+ export declare const rpcResult: (id: JsonRpcId, value: unknown) => JsonRpcResponse;
78
+ export declare const rpcError: (id: JsonRpcId, code: number, message: string) => JsonRpcResponse;
79
+ export interface McpProtocolState {
80
+ readonly activeRequests: Map<string, AbortController>;
81
+ }
82
+ export interface McpProtocolOptions {
83
+ readonly state?: McpProtocolState;
84
+ readonly signal?: AbortSignal;
85
+ readonly sendNotification?: (notification: JsonRpcNotification) => void;
86
+ }
87
+ export declare function createMcpProtocolState(): McpProtocolState;
88
+ /**
89
+ * Dispatch one JSON-RPC message against the given tools. Returns the response, or `null` for a
90
+ * notification (no reply). Tool errors are reported in-band (`isError`) so the agent can react to them.
91
+ */
92
+ export declare function handleRpc(message: JsonRpcRequest, tools: readonly McpTool[], serverInfo: {
93
+ name: string;
94
+ version: string;
95
+ }, features?: McpServerFeatures, options?: McpProtocolOptions): Promise<JsonRpcResponse | null>;
96
+ export {};
97
+ //# sourceMappingURL=mcp-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protocol.d.ts","sourceRoot":"","sources":["../src/mcp-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * The pure MCP (Model Context Protocol) JSON-RPC dispatch — no I/O, no `Bun.*`, no side effects, so it
3
+ * unit-tests cleanly. {@link runMcpServer} in `./mcp.ts` wires this to stdin/stdout; the tools are
4
+ * injected, so the protocol logic is exercised without spawning or reading streams.
5
+ */
6
+ export const PROTOCOL_VERSION = "2024-11-05";
7
+ export const rpcResult = (id, value) => ({
8
+ jsonrpc: "2.0",
9
+ id,
10
+ result: value,
11
+ });
12
+ export const rpcError = (id, code, message) => ({
13
+ jsonrpc: "2.0",
14
+ id,
15
+ error: { code, message },
16
+ });
17
+ export function createMcpProtocolState() {
18
+ return { activeRequests: new Map() };
19
+ }
20
+ function requestKey(id) {
21
+ if (typeof id === "string")
22
+ return `s:${id}`;
23
+ return typeof id === "number" && Number.isFinite(id) ? `n:${id}` : undefined;
24
+ }
25
+ function progressTokenOf(params) {
26
+ const meta = params?._meta;
27
+ if (typeof meta !== "object" || meta === null || Array.isArray(meta))
28
+ return undefined;
29
+ const token = meta.progressToken;
30
+ return typeof token === "string" || (typeof token === "number" && Number.isFinite(token))
31
+ ? token
32
+ : undefined;
33
+ }
34
+ function cancellationReason(params) {
35
+ const reason = params?.reason;
36
+ return typeof reason === "string" && reason.length > 0 ? reason : undefined;
37
+ }
38
+ function linkAbortSignal(parent, child) {
39
+ if (parent === undefined)
40
+ return () => { };
41
+ if (parent.aborted) {
42
+ child.abort(parent.reason);
43
+ return () => { };
44
+ }
45
+ const abort = () => child.abort(parent.reason);
46
+ parent.addEventListener("abort", abort, { once: true });
47
+ return () => parent.removeEventListener("abort", abort);
48
+ }
49
+ function abortMessage(signal) {
50
+ const reason = signal.reason;
51
+ if (typeof reason === "string" && reason.length > 0)
52
+ return `Cancelled: ${reason}`;
53
+ return "Cancelled";
54
+ }
55
+ function compactDescription(description) {
56
+ const text = description.replace(/\s+/g, " ").trim();
57
+ const sentenceEnd = text.search(/[.!?](?:\s|$)/);
58
+ const sentence = sentenceEnd === -1 ? text : text.slice(0, sentenceEnd + 1);
59
+ if (sentence.length <= 120)
60
+ return sentence;
61
+ return `${sentence.slice(0, 117).trimEnd()}...`;
62
+ }
63
+ /**
64
+ * Dispatch one JSON-RPC message against the given tools. Returns the response, or `null` for a
65
+ * notification (no reply). Tool errors are reported in-band (`isError`) so the agent can react to them.
66
+ */
67
+ export async function handleRpc(message, tools, serverInfo, features = {}, options = {}) {
68
+ const { id, method, params } = message;
69
+ const isNotification = id === undefined;
70
+ const rid = id ?? null;
71
+ const resources = features.resources ?? [];
72
+ const prompts = features.prompts ?? [];
73
+ const state = options.state ?? createMcpProtocolState();
74
+ switch (method) {
75
+ case "initialize":
76
+ return rpcResult(rid, {
77
+ protocolVersion: PROTOCOL_VERSION,
78
+ capabilities: {
79
+ tools: {},
80
+ ...(resources.length > 0 ? { resources: {} } : {}),
81
+ ...(prompts.length > 0 ? { prompts: {} } : {}),
82
+ },
83
+ serverInfo,
84
+ });
85
+ case "notifications/initialized":
86
+ return null;
87
+ case "notifications/cancelled": {
88
+ const key = requestKey(params?.requestId);
89
+ if (key !== undefined)
90
+ state.activeRequests.get(key)?.abort(cancellationReason(params));
91
+ return null;
92
+ }
93
+ case "ping":
94
+ return rpcResult(rid, {});
95
+ case "tools/list":
96
+ return rpcResult(rid, params?.compact === true
97
+ ? {
98
+ tools: tools.map((t) => ({
99
+ name: t.name,
100
+ description: compactDescription(t.description),
101
+ })),
102
+ }
103
+ : {
104
+ tools: tools.map((t) => ({
105
+ name: t.name,
106
+ description: t.description,
107
+ inputSchema: t.inputSchema,
108
+ })),
109
+ });
110
+ case "tools/describe": {
111
+ const name = params?.name;
112
+ const tool = tools.find((t) => t.name === name);
113
+ if (!tool)
114
+ return rpcError(rid, -32602, `unknown tool: ${String(name)}`);
115
+ return rpcResult(rid, {
116
+ tool: {
117
+ name: tool.name,
118
+ description: tool.description,
119
+ inputSchema: tool.inputSchema,
120
+ },
121
+ });
122
+ }
123
+ case "tools/call": {
124
+ const name = params?.name;
125
+ const tool = tools.find((t) => t.name === name);
126
+ if (!tool)
127
+ return rpcError(rid, -32602, `unknown tool: ${String(name)}`);
128
+ const args = params?.arguments ?? {};
129
+ const controller = new AbortController();
130
+ const key = requestKey(id);
131
+ const cleanupAbort = linkAbortSignal(options.signal, controller);
132
+ if (key !== undefined)
133
+ state.activeRequests.set(key, controller);
134
+ const progressToken = progressTokenOf(params);
135
+ let lastProgress = Number.NEGATIVE_INFINITY;
136
+ const reportProgress = (progress, total) => {
137
+ if (progressToken === undefined ||
138
+ !Number.isFinite(progress) ||
139
+ progress <= lastProgress ||
140
+ (total !== undefined && !Number.isFinite(total))) {
141
+ return;
142
+ }
143
+ lastProgress = progress;
144
+ options.sendNotification?.({
145
+ jsonrpc: "2.0",
146
+ method: "notifications/progress",
147
+ params: {
148
+ progressToken,
149
+ progress,
150
+ ...(total !== undefined ? { total } : {}),
151
+ },
152
+ });
153
+ };
154
+ try {
155
+ reportProgress(0, 1);
156
+ if (controller.signal.aborted)
157
+ throw new DOMException("cancelled", "AbortError");
158
+ const text = await tool.handler(args, {
159
+ signal: controller.signal,
160
+ requestId: rid,
161
+ ...(progressToken !== undefined ? { progressToken } : {}),
162
+ reportProgress,
163
+ });
164
+ if (controller.signal.aborted)
165
+ throw new DOMException("cancelled", "AbortError");
166
+ reportProgress(1, 1);
167
+ return rpcResult(rid, { content: [{ type: "text", text }] });
168
+ }
169
+ catch (err) {
170
+ if (controller.signal.aborted) {
171
+ return rpcResult(rid, {
172
+ content: [{ type: "text", text: abortMessage(controller.signal) }],
173
+ isError: true,
174
+ });
175
+ }
176
+ const msg = err instanceof Error ? err.message : String(err);
177
+ return rpcResult(rid, { content: [{ type: "text", text: `Error: ${msg}` }], isError: true });
178
+ }
179
+ finally {
180
+ cleanupAbort();
181
+ if (key !== undefined && state.activeRequests.get(key) === controller) {
182
+ state.activeRequests.delete(key);
183
+ }
184
+ }
185
+ }
186
+ case "resources/list":
187
+ return rpcResult(rid, {
188
+ resources: resources.map((r) => ({
189
+ uri: r.uri,
190
+ name: r.name,
191
+ ...(r.description !== undefined ? { description: r.description } : {}),
192
+ ...(r.mimeType !== undefined ? { mimeType: r.mimeType } : {}),
193
+ })),
194
+ });
195
+ case "resources/read": {
196
+ const uri = params?.uri;
197
+ const resource = resources.find((r) => r.uri === uri);
198
+ if (!resource)
199
+ return rpcError(rid, -32602, `unknown resource: ${String(uri)}`);
200
+ try {
201
+ const content = await resource.read();
202
+ return rpcResult(rid, {
203
+ contents: [
204
+ {
205
+ uri: resource.uri,
206
+ mimeType: content.mimeType ?? resource.mimeType ?? "text/plain",
207
+ text: content.text,
208
+ },
209
+ ],
210
+ });
211
+ }
212
+ catch (err) {
213
+ const msg = err instanceof Error ? err.message : String(err);
214
+ return rpcError(rid, -32000, msg);
215
+ }
216
+ }
217
+ case "prompts/list":
218
+ return rpcResult(rid, {
219
+ prompts: prompts.map((p) => ({
220
+ name: p.name,
221
+ description: p.description,
222
+ ...(p.arguments !== undefined ? { arguments: p.arguments } : {}),
223
+ })),
224
+ });
225
+ case "prompts/get": {
226
+ const name = params?.name;
227
+ const prompt = prompts.find((p) => p.name === name);
228
+ if (!prompt)
229
+ return rpcError(rid, -32602, `unknown prompt: ${String(name)}`);
230
+ const args = params?.arguments ?? {};
231
+ try {
232
+ return rpcResult(rid, {
233
+ description: prompt.description,
234
+ messages: await prompt.handler(args),
235
+ });
236
+ }
237
+ catch (err) {
238
+ const msg = err instanceof Error ? err.message : String(err);
239
+ return rpcError(rid, -32000, msg);
240
+ }
241
+ }
242
+ default:
243
+ if (isNotification)
244
+ return null;
245
+ return rpcError(rid, -32601, `method not found: ${String(method)}`);
246
+ }
247
+ }
248
+ //# sourceMappingURL=mcp-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protocol.js","sourceRoot":"","sources":["../src/mcp-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The `nifra_render` engine + its child-process entry — the page half of `nifra_run`. Where `nifra_run`
3
+ * runs requests through the BACKEND, this SSRs page routes through the WEB app (`createWebApp`), so an
4
+ * agent can verify a page renders and its loader ran after an edit. Spawned fresh per call (`bun
5
+ * mcp-render.ts <cwd>`) so the project's CURRENT route/loader code is loaded.
6
+ *
7
+ * No build required: a placeholder `clientEntry` is injected (the SSR HTML renders regardless — the
8
+ * client bundle only matters for hydration in the browser, not for "did this page render server-side").
9
+ * {@link renderPages} never throws — every failure (no config, a loader error, a render throw) becomes
10
+ * `{ error }` so the agent gets the actionable message.
11
+ */
12
+ export declare function renderPages(cwd: string, requests: unknown): Promise<{
13
+ results: unknown;
14
+ } | {
15
+ error: string;
16
+ }>;
17
+ //# sourceMappingURL=mcp-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-render.d.ts","sourceRoot":"","sources":["../src/mcp-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCnD"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The `nifra_render` engine + its child-process entry — the page half of `nifra_run`. Where `nifra_run`
3
+ * runs requests through the BACKEND, this SSRs page routes through the WEB app (`createWebApp`), so an
4
+ * agent can verify a page renders and its loader ran after an edit. Spawned fresh per call (`bun
5
+ * mcp-render.ts <cwd>`) so the project's CURRENT route/loader code is loaded.
6
+ *
7
+ * No build required: a placeholder `clientEntry` is injected (the SSR HTML renders regardless — the
8
+ * client bundle only matters for hydration in the browser, not for "did this page render server-side").
9
+ * {@link renderPages} never throws — every failure (no config, a loader error, a render throw) becomes
10
+ * `{ error }` so the agent gets the actionable message.
11
+ */
12
+ import { inProcessClient } from "@nifrajs/client";
13
+ import { runApp } from "@nifrajs/runner";
14
+ import { createWebApp } from "@nifrajs/web";
15
+ import { discoverRoutes } from "@nifrajs/web/fs";
16
+ import { loadApp, resolvePlugins } from "./load.js";
17
+ const errString = (err) => err instanceof Error ? `${err.name}: ${err.message}` : String(err);
18
+ export async function renderPages(cwd, requests) {
19
+ if (!Array.isArray(requests))
20
+ return { error: "expected { requests: [...] }" };
21
+ let app;
22
+ try {
23
+ app = await loadApp(cwd, "dist");
24
+ }
25
+ catch (err) {
26
+ return { error: errString(err) };
27
+ }
28
+ // Register the framework's SSR Bun plugins so `.vue`/`.svelte`/Solid route files compile on import
29
+ // (React/Preact JSX is Bun-native → none). Mirrors `nifra start`.
30
+ try {
31
+ const { plugin } = await import("bun");
32
+ for (const p of await resolvePlugins(app.framework.serverPlugins)) {
33
+ plugin(p);
34
+ }
35
+ }
36
+ catch (err) {
37
+ return { error: errString(err) };
38
+ }
39
+ let webApp;
40
+ try {
41
+ webApp = createWebApp({
42
+ // The adapter is validated by loadApp; cast at the seam (same as the CLI's `asAdapter`).
43
+ adapter: app.framework.adapter,
44
+ manifest: discoverRoutes(app.routesDir),
45
+ clientEntry: "/_nifra-render-only.js", // placeholder; SSR HTML does not need the built client
46
+ ...(app.backend !== undefined ? { api: inProcessClient(app.backend) } : {}),
47
+ });
48
+ }
49
+ catch (err) {
50
+ return { error: errString(err) };
51
+ }
52
+ try {
53
+ return { results: await runApp(webApp, requests) };
54
+ }
55
+ catch (err) {
56
+ return { error: errString(err) };
57
+ }
58
+ }
59
+ // Child-process entry: read `{ requests }` from stdin, SSR, print JSON. Guarded so importing this
60
+ // module in a test does not execute it.
61
+ if (import.meta.main) {
62
+ const cwd = process.argv[2] ?? process.cwd();
63
+ let output;
64
+ try {
65
+ const { requests } = JSON.parse(await Bun.stdin.text());
66
+ output = await renderPages(cwd, requests);
67
+ }
68
+ catch {
69
+ output = { error: "invalid input: expected JSON { requests: [...] }" };
70
+ }
71
+ process.stdout.write(JSON.stringify(output, null, 2));
72
+ }
73
+ //# sourceMappingURL=mcp-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-render.js","sourceRoot":"","sources":["../src/mcp-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The `nifra_run` engine + its child-process entry. The MCP server spawns this file fresh on every
3
+ * `nifra_run` call (`bun mcp-run.ts <cwd>`) so the project's CURRENT backend code is loaded — picking
4
+ * up the agent's latest edits. {@link runBackend} is the pure-ish core (resolve entry → import → run),
5
+ * exported so it's unit-testable in-process; the entry below wires it to stdin/stdout.
6
+ */
7
+ import { type AppLike } from "@nifrajs/runner";
8
+ export declare function loadBackend(cwd: string, entry?: string): Promise<{
9
+ app: AppLike;
10
+ } | {
11
+ error: string;
12
+ }>;
13
+ /**
14
+ * Resolve the backend entry under `cwd`, import it, and run `requests` through its exported app. Never
15
+ * throws — every failure (missing/invalid entry, import/compile/runtime error) becomes `{ error }`, so
16
+ * the caller (and the agent) always gets actionable output. An import error here IS the failure the
17
+ * agent needs to see and fix.
18
+ */
19
+ export declare function runBackend(cwd: string, requests: unknown, entry?: string): Promise<{
20
+ results: unknown;
21
+ } | {
22
+ error: string;
23
+ }>;
24
+ //# sourceMappingURL=mcp-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-run.d.ts","sourceRoot":"","sources":["../src/mcp-run.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,iBAAiB,CAAA;AAOtD,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB/C;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,OAAO,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAWnD"}