@refrakt-md/mcp 0.11.0 → 0.11.2

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/dist/bin.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stdio entry point for the refrakt MCP server.
4
+ *
5
+ * Usage:
6
+ * refrakt-mcp [--cwd <path>]
7
+ *
8
+ * Reads the project root from `--cwd` (or `process.cwd()` by default), then
9
+ * starts the MCP server on stdio.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
package/dist/bin.js ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stdio entry point for the refrakt MCP server.
4
+ *
5
+ * Usage:
6
+ * refrakt-mcp [--cwd <path>]
7
+ *
8
+ * Reads the project root from `--cwd` (or `process.cwd()` by default), then
9
+ * starts the MCP server on stdio.
10
+ */
11
+ import { runStdioServer } from './server.js';
12
+ function parseArgs(argv) {
13
+ let cwd;
14
+ let help = false;
15
+ for (let i = 0; i < argv.length; i++) {
16
+ const a = argv[i];
17
+ if (a === '--cwd') {
18
+ cwd = argv[++i];
19
+ if (!cwd) {
20
+ console.error('Error: --cwd requires a path');
21
+ process.exit(1);
22
+ }
23
+ }
24
+ else if (a === '--help' || a === '-h') {
25
+ help = true;
26
+ }
27
+ else {
28
+ console.error(`Error: Unknown argument "${a}"`);
29
+ process.exit(1);
30
+ }
31
+ }
32
+ return { cwd, help };
33
+ }
34
+ const { cwd, help } = parseArgs(process.argv.slice(2));
35
+ if (help) {
36
+ console.log(`
37
+ Usage: refrakt-mcp [--cwd <path>]
38
+
39
+ A Model Context Protocol server that wraps the refrakt CLI. Speaks JSON-RPC
40
+ over stdio. Register it with your MCP client (Claude Desktop, Claude Code,
41
+ Cursor, etc.) by adding to the client's config:
42
+
43
+ "refrakt": {
44
+ "command": "npx",
45
+ "args": ["-y", "@refrakt-md/mcp"]
46
+ }
47
+
48
+ Options:
49
+ --cwd <path> Project root the server operates against. Defaults to
50
+ process.cwd(). Useful when the MCP client launches the
51
+ server from a different directory.
52
+
53
+ --help, -h Show this help message.
54
+ `);
55
+ process.exit(0);
56
+ }
57
+ runStdioServer({ cwd }).catch((err) => {
58
+ process.stderr.write(`refrakt-mcp failed to start: ${err.message}\n`);
59
+ process.exit(1);
60
+ });
61
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,SAAS,SAAS,CAAC,IAAc;IAChC,IAAI,GAAuB,CAAC;IAC5B,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;YACnB,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAChB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACF,CAAC;aAAM,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,IAAI,GAAG,IAAI,CAAC;QACb,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,GAAG,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACF,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvD,IAAI,IAAI,EAAE,CAAC;IACV,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;CAkBZ,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Resolve the path to the `@refrakt-md/cli` bin entry from the running MCP
3
+ * package. Used by both the CLI-shelling tool handlers and the resource
4
+ * handlers.
5
+ *
6
+ * Resolution order:
7
+ * 1. `@refrakt-md/cli/package.json` (works when the cli package exports it).
8
+ * 2. `@refrakt-md/cli/lib/plugins.js` (always exported); walk up to the
9
+ * package root and append `dist/bin.js`.
10
+ *
11
+ * If both fail, throws a clear error rather than returning a bare `'refrakt'`
12
+ * string — that fallback used to silently produce confusing
13
+ * `Cannot find module '<cwd>/refrakt'` errors when execFileSync resolved the
14
+ * relative path against the user's cwd.
15
+ */
16
+ export declare function resolveCliBin(): string;
17
+ //# sourceMappingURL=cli-bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-bin.d.ts","sourceRoot":"","sources":["../src/cli-bin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,wBAAgB,aAAa,IAAI,MAAM,CA2BtC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Resolve the path to the `@refrakt-md/cli` bin entry from the running MCP
3
+ * package. Used by both the CLI-shelling tool handlers and the resource
4
+ * handlers.
5
+ *
6
+ * Resolution order:
7
+ * 1. `@refrakt-md/cli/package.json` (works when the cli package exports it).
8
+ * 2. `@refrakt-md/cli/lib/plugins.js` (always exported); walk up to the
9
+ * package root and append `dist/bin.js`.
10
+ *
11
+ * If both fail, throws a clear error rather than returning a bare `'refrakt'`
12
+ * string — that fallback used to silently produce confusing
13
+ * `Cannot find module '<cwd>/refrakt'` errors when execFileSync resolved the
14
+ * relative path against the user's cwd.
15
+ */
16
+ import { createRequire } from 'node:module';
17
+ import { resolve, dirname } from 'node:path';
18
+ const require_ = createRequire(import.meta.url);
19
+ let cached;
20
+ export function resolveCliBin() {
21
+ if (cached)
22
+ return cached;
23
+ const errors = [];
24
+ try {
25
+ const pkgJsonPath = require_.resolve('@refrakt-md/cli/package.json');
26
+ cached = resolve(dirname(pkgJsonPath), 'dist', 'bin.js');
27
+ return cached;
28
+ }
29
+ catch (err) {
30
+ errors.push(`package.json: ${err.message}`);
31
+ }
32
+ try {
33
+ // `lib/plugins.js` is always declared in @refrakt-md/cli's exports map.
34
+ // From .../node_modules/@refrakt-md/cli/dist/lib/plugins.js, walk up two
35
+ // directories to reach the package root.
36
+ const pluginsPath = require_.resolve('@refrakt-md/cli/lib/plugins.js');
37
+ const pkgDir = dirname(dirname(dirname(pluginsPath)));
38
+ cached = resolve(pkgDir, 'dist', 'bin.js');
39
+ return cached;
40
+ }
41
+ catch (err) {
42
+ errors.push(`lib/plugins.js: ${err.message}`);
43
+ }
44
+ throw new Error(`Unable to resolve @refrakt-md/cli bin from MCP server. Tried:\n - ${errors.join('\n - ')}`);
45
+ }
46
+ //# sourceMappingURL=cli-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-bin.js","sourceRoot":"","sources":["../src/cli-bin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEhD,IAAI,MAA0B,CAAC;AAE/B,MAAM,UAAU,aAAa;IAC5B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC;QACJ,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC;QACrE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzD,OAAO,MAAM,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,iBAAkB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,CAAC;QACJ,wEAAwE;QACxE,yEAAyE;QACzE,yCAAyC;QACzC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,mBAAoB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,KAAK,CACd,sEAAsE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAC7F,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Auto-detection for the MCP server.
3
+ *
4
+ * Inspects the working directory once at startup to figure out which
5
+ * tool groups should be exposed:
6
+ * - `plan` context: a `plan/` directory exists.
7
+ * - `site` context: `refrakt.config.json` declares one or more sites.
8
+ *
9
+ * Both can be active in the same project. Neither being active leaves the
10
+ * server with diagnostic-only tools.
11
+ */
12
+ import { type DiscoveredPlugin } from '@refrakt-md/cli/lib/plugins.js';
13
+ export interface DetectedPlanContext {
14
+ dir: string;
15
+ fileCount: number;
16
+ }
17
+ export interface DetectedSiteContext {
18
+ configPath: string;
19
+ sites: string[];
20
+ plugins: string[];
21
+ }
22
+ export interface DetectionResult {
23
+ cwd: string;
24
+ plan: DetectedPlanContext | null;
25
+ site: DetectedSiteContext | null;
26
+ plugins: DiscoveredPlugin[];
27
+ configSource: 'config-file' | 'autodetect';
28
+ }
29
+ export declare function detect(cwd?: string): Promise<DetectionResult>;
30
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAExF,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,YAAY,EAAE,aAAa,GAAG,YAAY,CAAC;CAC3C;AAED,wBAAsB,MAAM,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8ClF"}
package/dist/detect.js ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Auto-detection for the MCP server.
3
+ *
4
+ * Inspects the working directory once at startup to figure out which
5
+ * tool groups should be exposed:
6
+ * - `plan` context: a `plan/` directory exists.
7
+ * - `site` context: `refrakt.config.json` declares one or more sites.
8
+ *
9
+ * Both can be active in the same project. Neither being active leaves the
10
+ * server with diagnostic-only tools.
11
+ */
12
+ import { existsSync, readdirSync, statSync } from 'node:fs';
13
+ import { resolve } from 'node:path';
14
+ import { loadRefraktConfigWithRaw } from '@refrakt-md/transform/node';
15
+ import { discoverPlugins } from '@refrakt-md/cli/lib/plugins.js';
16
+ export async function detect(cwd = process.cwd()) {
17
+ const result = {
18
+ cwd,
19
+ plan: null,
20
+ site: null,
21
+ plugins: [],
22
+ configSource: 'autodetect',
23
+ };
24
+ const configPath = resolve(cwd, 'refrakt.config.json');
25
+ if (existsSync(configPath)) {
26
+ try {
27
+ const { normalized } = loadRefraktConfigWithRaw(configPath);
28
+ result.configSource = 'config-file';
29
+ const siteNames = Object.keys(normalized.sites);
30
+ if (siteNames.length > 0) {
31
+ result.site = {
32
+ configPath,
33
+ sites: siteNames,
34
+ plugins: normalized.plugins ?? [],
35
+ };
36
+ }
37
+ if (normalized.plan?.dir) {
38
+ const planDir = resolve(cwd, normalized.plan.dir);
39
+ result.plan = describePlanDir(planDir);
40
+ }
41
+ }
42
+ catch {
43
+ // Malformed config — fall through to autodetect
44
+ }
45
+ }
46
+ // Autodetect plan/ if not declared in config
47
+ if (!result.plan) {
48
+ const planDir = resolve(cwd, 'plan');
49
+ if (existsSync(planDir) && safeIsDirectory(planDir)) {
50
+ result.plan = describePlanDir(planDir);
51
+ }
52
+ }
53
+ try {
54
+ result.plugins = await discoverPlugins({ cwd, warn: false });
55
+ }
56
+ catch {
57
+ // Discovery failures are non-fatal
58
+ }
59
+ return result;
60
+ }
61
+ function describePlanDir(dir) {
62
+ let fileCount = 0;
63
+ const stack = [dir];
64
+ while (stack.length > 0) {
65
+ const current = stack.pop();
66
+ if (!existsSync(current) || !safeIsDirectory(current))
67
+ continue;
68
+ try {
69
+ for (const entry of readdirSync(current)) {
70
+ const full = resolve(current, entry);
71
+ if (safeIsDirectory(full)) {
72
+ stack.push(full);
73
+ }
74
+ else if (entry.endsWith('.md')) {
75
+ fileCount++;
76
+ }
77
+ }
78
+ }
79
+ catch {
80
+ // keep counting what we can
81
+ }
82
+ }
83
+ return { dir, fileCount };
84
+ }
85
+ function safeIsDirectory(path) {
86
+ try {
87
+ return statSync(path).isDirectory();
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @refrakt-md/mcp — Model Context Protocol server wrapping the refrakt CLI.
3
+ *
4
+ * Most users will install this and register `refrakt-mcp` (the bin entry) in
5
+ * their MCP client config. Programmatic consumers can import the server
6
+ * factory directly.
7
+ */
8
+ export { createServer, runStdioServer } from './server.js';
9
+ export type { CreateServerOptions } from './server.js';
10
+ export { detect } from './detect.js';
11
+ export type { DetectionResult, DetectedPlanContext, DetectedSiteContext } from './detect.js';
12
+ export { CORE_TOOLS } from './tools/core.js';
13
+ export type { McpTool } from './tools/core.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @refrakt-md/mcp — Model Context Protocol server wrapping the refrakt CLI.
3
+ *
4
+ * Most users will install this and register `refrakt-mcp` (the bin entry) in
5
+ * their MCP client config. Programmatic consumers can import the server
6
+ * factory directly.
7
+ */
8
+ export { createServer, runStdioServer } from './server.js';
9
+ export { detect } from './detect.js';
10
+ export { CORE_TOOLS } from './tools/core.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * MCP resources — read-only addressable data the server exposes.
3
+ *
4
+ * Resources mirror the read-only subset of the tool surface so MCP clients
5
+ * that prefer pull semantics (ReadResource) get equivalent data without a
6
+ * tool invocation.
7
+ *
8
+ * URI scheme:
9
+ * refrakt://detect — full detection result
10
+ * refrakt://reference — rune syntax reference (JSON)
11
+ * refrakt://contracts — structure contracts (JSON)
12
+ * refrakt://rune/<name> — identity transform output for one rune
13
+ * refrakt://plan/index — list of plan entities
14
+ * refrakt://plan/<type>/<id> — Markdoc source for one plan entity
15
+ * refrakt://plan/status — plan status payload
16
+ */
17
+ export interface McpResource {
18
+ uri: string;
19
+ name: string;
20
+ description: string;
21
+ mimeType: string;
22
+ }
23
+ export interface ResourceContent {
24
+ uri: string;
25
+ mimeType: string;
26
+ text: string;
27
+ }
28
+ /** Static resource list — dynamic ones (e.g. refrakt://rune/<name>) are
29
+ * surfaced via templated entries the client can complete. */
30
+ export declare function listResources(ctx: {
31
+ cwd: string;
32
+ hasPlan: boolean;
33
+ hasSites: boolean;
34
+ }): McpResource[];
35
+ /** Read the contents of a resource by URI. Returns the text payload (always
36
+ * JSON for now — markdown could be added later for plan entity reads). */
37
+ export declare function readResource(uri: string, ctx: {
38
+ cwd: string;
39
+ }): Promise<ResourceContent>;
40
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,WAAW,WAAW;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED;8DAC8D;AAC9D,wBAAgB,aAAa,CAAC,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,WAAW,EAAE,CA0CtG;AAED;2EAC2E;AAC3E,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAoD9F"}
@@ -0,0 +1,257 @@
1
+ /**
2
+ * MCP resources — read-only addressable data the server exposes.
3
+ *
4
+ * Resources mirror the read-only subset of the tool surface so MCP clients
5
+ * that prefer pull semantics (ReadResource) get equivalent data without a
6
+ * tool invocation.
7
+ *
8
+ * URI scheme:
9
+ * refrakt://detect — full detection result
10
+ * refrakt://reference — rune syntax reference (JSON)
11
+ * refrakt://contracts — structure contracts (JSON)
12
+ * refrakt://rune/<name> — identity transform output for one rune
13
+ * refrakt://plan/index — list of plan entities
14
+ * refrakt://plan/<type>/<id> — Markdoc source for one plan entity
15
+ * refrakt://plan/status — plan status payload
16
+ */
17
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
18
+ import { resolve, join } from 'node:path';
19
+ /** Static resource list — dynamic ones (e.g. refrakt://rune/<name>) are
20
+ * surfaced via templated entries the client can complete. */
21
+ export function listResources(ctx) {
22
+ const list = [
23
+ {
24
+ uri: 'refrakt://detect',
25
+ name: 'detect',
26
+ description: 'Auto-detection summary for the current project (plan dir, sites, plugins).',
27
+ mimeType: 'application/json',
28
+ },
29
+ ];
30
+ if (ctx.hasSites) {
31
+ list.push({
32
+ uri: 'refrakt://reference',
33
+ name: 'reference',
34
+ description: 'Rune syntax reference for the active package set.',
35
+ mimeType: 'application/json',
36
+ }, {
37
+ uri: 'refrakt://contracts',
38
+ name: 'contracts',
39
+ description: 'Structure contracts for every rune in the active package set.',
40
+ mimeType: 'application/json',
41
+ });
42
+ }
43
+ if (ctx.hasPlan) {
44
+ list.push({
45
+ uri: 'refrakt://plan/index',
46
+ name: 'plan-index',
47
+ description: 'Index of all plan entities (id, type, status, file path).',
48
+ mimeType: 'application/json',
49
+ }, {
50
+ uri: 'refrakt://plan/status',
51
+ name: 'plan-status',
52
+ description: 'Plan status summary (counts, milestone progress).',
53
+ mimeType: 'application/json',
54
+ });
55
+ }
56
+ return list;
57
+ }
58
+ /** Read the contents of a resource by URI. Returns the text payload (always
59
+ * JSON for now — markdown could be added later for plan entity reads). */
60
+ export async function readResource(uri, ctx) {
61
+ if (uri === 'refrakt://detect') {
62
+ const { detect } = await import('./detect.js');
63
+ const result = await detect(ctx.cwd);
64
+ return jsonContent(uri, result);
65
+ }
66
+ if (uri === 'refrakt://reference') {
67
+ return jsonContent(uri, await invokeCli(['reference', '--format', 'json'], ctx.cwd));
68
+ }
69
+ if (uri === 'refrakt://contracts') {
70
+ const stdout = await invokeCliText(['contracts', '-o', '/dev/stdout'], ctx.cwd);
71
+ const start = stdout.indexOf('{');
72
+ if (start === -1)
73
+ throw resourceError(uri, 'contracts produced no JSON output');
74
+ return { uri, mimeType: 'application/json', text: stdout.slice(start).trim() };
75
+ }
76
+ if (uri.startsWith('refrakt://rune/')) {
77
+ const rest = uri.slice('refrakt://rune/'.length);
78
+ const [name, query] = rest.split('?');
79
+ if (!name)
80
+ throw resourceError(uri, 'missing rune name');
81
+ const args = ['inspect', name, '--json'];
82
+ if (query) {
83
+ for (const pair of query.split('&')) {
84
+ const [k, v] = pair.split('=');
85
+ if (!k)
86
+ continue;
87
+ args.push(`--${k}=${v ?? ''}`);
88
+ }
89
+ }
90
+ return jsonContent(uri, await invokeCli(args, ctx.cwd));
91
+ }
92
+ if (uri === 'refrakt://plan/index') {
93
+ return jsonContent(uri, listPlanEntities(ctx.cwd));
94
+ }
95
+ if (uri === 'refrakt://plan/status') {
96
+ return jsonContent(uri, await invokeCli(['plan', 'status', '--format', 'json'], ctx.cwd));
97
+ }
98
+ if (uri.startsWith('refrakt://plan/')) {
99
+ // Single entity by type/id — refrakt://plan/work/WORK-001
100
+ const rest = uri.slice('refrakt://plan/'.length);
101
+ const slashIdx = rest.indexOf('/');
102
+ if (slashIdx === -1)
103
+ throw resourceError(uri, 'expected refrakt://plan/<type>/<id>');
104
+ const type = rest.slice(0, slashIdx);
105
+ const id = rest.slice(slashIdx + 1);
106
+ return readPlanEntity(uri, ctx.cwd, type, id);
107
+ }
108
+ throw resourceError(uri, `unknown resource URI`);
109
+ }
110
+ function listPlanEntities(cwd) {
111
+ const planDir = resolvePlanDir(cwd);
112
+ if (!planDir || !existsSync(planDir))
113
+ return { entities: [] };
114
+ const entities = [];
115
+ const stack = [planDir];
116
+ while (stack.length > 0) {
117
+ const current = stack.pop();
118
+ try {
119
+ for (const entry of readdirSync(current)) {
120
+ const full = join(current, entry);
121
+ if (statSync(full).isDirectory()) {
122
+ stack.push(full);
123
+ }
124
+ else if (entry.endsWith('.md')) {
125
+ try {
126
+ const text = readFileSync(full, 'utf-8');
127
+ const meta = parseFrontMatter(text);
128
+ if (meta) {
129
+ entities.push({
130
+ ...meta,
131
+ file: full.slice(planDir.length + 1),
132
+ });
133
+ }
134
+ }
135
+ catch {
136
+ // skip unreadable
137
+ }
138
+ }
139
+ }
140
+ }
141
+ catch {
142
+ // skip unreadable directory
143
+ }
144
+ }
145
+ return { entities };
146
+ }
147
+ function parseFrontMatter(text) {
148
+ const match = text.match(/\{%\s*(work|bug|spec|decision|milestone)\s+([^%]+)%\}/);
149
+ if (!match)
150
+ return undefined;
151
+ const type = match[1];
152
+ const attrs = match[2];
153
+ const idMatch = attrs.match(/(?:id|name)="([^"]+)"/);
154
+ if (!idMatch)
155
+ return undefined;
156
+ const statusMatch = attrs.match(/status="([^"]+)"/);
157
+ return {
158
+ id: idMatch[1],
159
+ type,
160
+ ...(statusMatch ? { status: statusMatch[1] } : {}),
161
+ };
162
+ }
163
+ function readPlanEntity(uri, cwd, type, id) {
164
+ const planDir = resolvePlanDir(cwd);
165
+ if (!planDir || !existsSync(planDir))
166
+ throw resourceError(uri, 'plan directory not found');
167
+ // Look in plan/<type>s/ first (the convention), then anywhere under plan/.
168
+ const candidates = [
169
+ join(planDir, `${type}s`),
170
+ join(planDir, type),
171
+ planDir,
172
+ ];
173
+ for (const dir of candidates) {
174
+ if (!existsSync(dir))
175
+ continue;
176
+ const found = findEntityFile(dir, id);
177
+ if (found) {
178
+ return {
179
+ uri,
180
+ mimeType: 'text/markdown',
181
+ text: readFileSync(found, 'utf-8'),
182
+ };
183
+ }
184
+ }
185
+ throw resourceError(uri, `plan entity ${id} not found`);
186
+ }
187
+ function findEntityFile(dir, id) {
188
+ const stack = [dir];
189
+ while (stack.length > 0) {
190
+ const current = stack.pop();
191
+ try {
192
+ for (const entry of readdirSync(current)) {
193
+ const full = join(current, entry);
194
+ try {
195
+ if (statSync(full).isDirectory())
196
+ stack.push(full);
197
+ else if (entry.endsWith('.md') && entry.includes(id))
198
+ return full;
199
+ }
200
+ catch {
201
+ // skip
202
+ }
203
+ }
204
+ }
205
+ catch {
206
+ // skip
207
+ }
208
+ }
209
+ return undefined;
210
+ }
211
+ function resolvePlanDir(cwd) {
212
+ const configPath = resolve(cwd, 'refrakt.config.json');
213
+ if (existsSync(configPath)) {
214
+ try {
215
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
216
+ if (config.plan?.dir)
217
+ return resolve(cwd, config.plan.dir);
218
+ }
219
+ catch {
220
+ // fall through to default
221
+ }
222
+ }
223
+ const fallback = resolve(cwd, 'plan');
224
+ return existsSync(fallback) ? fallback : undefined;
225
+ }
226
+ function jsonContent(uri, payload) {
227
+ return { uri, mimeType: 'application/json', text: JSON.stringify(payload, null, 2) };
228
+ }
229
+ function resourceError(uri, message) {
230
+ const err = new Error(`${message} (${uri})`);
231
+ err.errorCode = 'RESOURCE_FAILED';
232
+ return err;
233
+ }
234
+ /** CLI invocation that returns parsed JSON. */
235
+ async function invokeCli(args, cwd) {
236
+ const text = await invokeCliText(args, cwd);
237
+ return JSON.parse(text);
238
+ }
239
+ /** CLI invocation that returns raw stdout text. */
240
+ async function invokeCliText(args, cwd) {
241
+ const { execFileSync } = await import('node:child_process');
242
+ const { resolveCliBin } = await import('./cli-bin.js');
243
+ const bin = resolveCliBin();
244
+ try {
245
+ return execFileSync('node', [bin, ...args], {
246
+ encoding: 'utf-8',
247
+ cwd,
248
+ stdio: ['ignore', 'pipe', 'pipe'],
249
+ maxBuffer: 50 * 1024 * 1024,
250
+ });
251
+ }
252
+ catch (err) {
253
+ const stderr = (err.stderr ?? '').toString();
254
+ throw new Error(`refrakt ${args[0]} failed: ${stderr.trim() || err.message}`);
255
+ }
256
+ }
257
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * MCP server setup. Registers tools, hooks up the stdio transport, and
3
+ * dispatches incoming requests.
4
+ *
5
+ * The server reads `cwd` from process at start; a `--cwd <path>` flag on the
6
+ * bin handler can override it for clients that launch the server from outside
7
+ * the project root.
8
+ */
9
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
+ export interface CreateServerOptions {
11
+ cwd?: string;
12
+ }
13
+ export declare function createServer(options?: CreateServerOptions): Promise<Server<{
14
+ method: string;
15
+ params?: {
16
+ [x: string]: unknown;
17
+ _meta?: {
18
+ [x: string]: unknown;
19
+ progressToken?: string | number | undefined;
20
+ "io.modelcontextprotocol/related-task"?: {
21
+ taskId: string;
22
+ } | undefined;
23
+ } | undefined;
24
+ } | undefined;
25
+ }, {
26
+ method: string;
27
+ params?: {
28
+ [x: string]: unknown;
29
+ _meta?: {
30
+ [x: string]: unknown;
31
+ progressToken?: string | number | undefined;
32
+ "io.modelcontextprotocol/related-task"?: {
33
+ taskId: string;
34
+ } | undefined;
35
+ } | undefined;
36
+ } | undefined;
37
+ }, {
38
+ [x: string]: unknown;
39
+ _meta?: {
40
+ [x: string]: unknown;
41
+ progressToken?: string | number | undefined;
42
+ "io.modelcontextprotocol/related-task"?: {
43
+ taskId: string;
44
+ } | undefined;
45
+ } | undefined;
46
+ }>>;
47
+ export declare function runStdioServer(options?: CreateServerOptions): Promise<void>;
48
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAanE,MAAM,WAAW,mBAAmB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+FnE;AAED,wBAAsB,cAAc,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrF"}
package/dist/server.js ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * MCP server setup. Registers tools, hooks up the stdio transport, and
3
+ * dispatches incoming requests.
4
+ *
5
+ * The server reads `cwd` from process at start; a `--cwd <path>` flag on the
6
+ * bin handler can override it for clients that launch the server from outside
7
+ * the project root.
8
+ */
9
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
12
+ import { CORE_TOOLS } from './tools/core.js';
13
+ import { loadPluginTools } from './tools/plugins.js';
14
+ import { listResources, readResource } from './resources.js';
15
+ import { detect } from './detect.js';
16
+ export async function createServer(options = {}) {
17
+ const cwd = options.cwd ?? process.cwd();
18
+ // Detection happens once at startup so we can both decide which resources
19
+ // to expose and surface the detection result on `tools/list` for clients
20
+ // that want to understand the project before invoking anything.
21
+ const detection = await detect(cwd);
22
+ const pluginTools = await loadPluginTools(cwd);
23
+ const tools = [...CORE_TOOLS, ...pluginTools];
24
+ const server = new Server({
25
+ name: '@refrakt-md/mcp',
26
+ version: '0.10.1',
27
+ }, {
28
+ capabilities: {
29
+ tools: {},
30
+ resources: {},
31
+ },
32
+ });
33
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
34
+ return {
35
+ tools: tools.map((tool) => ({
36
+ name: tool.name,
37
+ description: tool.description,
38
+ inputSchema: tool.inputSchema,
39
+ })),
40
+ };
41
+ });
42
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
43
+ const tool = tools.find((t) => t.name === request.params.name);
44
+ if (!tool) {
45
+ return {
46
+ isError: true,
47
+ content: [
48
+ { type: 'text', text: `Unknown tool: ${request.params.name}` },
49
+ ],
50
+ _meta: {
51
+ errorCode: 'UNKNOWN_TOOL',
52
+ hint: `Available tools: ${tools.map((t) => t.name).join(', ')}`,
53
+ },
54
+ };
55
+ }
56
+ try {
57
+ const result = await tool.handler(request.params.arguments ?? {}, { cwd });
58
+ return {
59
+ content: [
60
+ {
61
+ type: 'text',
62
+ text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
63
+ },
64
+ ],
65
+ structuredContent: result,
66
+ };
67
+ }
68
+ catch (err) {
69
+ const error = err;
70
+ return {
71
+ isError: true,
72
+ content: [
73
+ { type: 'text', text: error.message ?? 'Tool invocation failed' },
74
+ ],
75
+ _meta: {
76
+ errorCode: error.errorCode ?? 'TOOL_FAILED',
77
+ ...(error.hint ? { hint: error.hint } : {}),
78
+ },
79
+ };
80
+ }
81
+ });
82
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
83
+ return {
84
+ resources: listResources({
85
+ cwd,
86
+ hasPlan: detection.plan !== null,
87
+ hasSites: detection.site !== null,
88
+ }),
89
+ };
90
+ });
91
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
92
+ try {
93
+ const content = await readResource(request.params.uri, { cwd });
94
+ return { contents: [content] };
95
+ }
96
+ catch (err) {
97
+ const error = err;
98
+ throw new Error(error.message ?? 'Failed to read resource');
99
+ }
100
+ });
101
+ return server;
102
+ }
103
+ export async function runStdioServer(options = {}) {
104
+ const server = await createServer(options);
105
+ const transport = new StdioServerTransport();
106
+ await server.connect(transport);
107
+ }
108
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Core refrakt CLI tools, exposed as MCP tools.
3
+ *
4
+ * Each tool delegates to the same underlying logic the `refrakt` CLI uses,
5
+ * but produces structured JSON output suitable for MCP. Where the underlying
6
+ * CLI command prints to stdout (rather than returning data), the tool here
7
+ * captures stdout via a child-process spawn — the cost is one extra fork per
8
+ * call but it preserves the exact output the user would see.
9
+ */
10
+ import type { JSONSchema7 } from '@refrakt-md/types';
11
+ /** Shared shape exported by the MCP server for each registered tool. */
12
+ export interface McpTool {
13
+ name: string;
14
+ description: string;
15
+ inputSchema: JSONSchema7;
16
+ handler: (input: unknown, ctx: {
17
+ cwd: string;
18
+ }) => Promise<unknown>;
19
+ }
20
+ export declare const referenceTool: McpTool;
21
+ export declare const contractsTool: McpTool;
22
+ export declare const inspectTool: McpTool;
23
+ export declare const inspectListTool: McpTool;
24
+ export declare const pluginsListTool: McpTool;
25
+ export declare const detectTool: McpTool;
26
+ export declare const CORE_TOOLS: McpTool[];
27
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/tools/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,wEAAwE;AACxE,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAWD,eAAO,MAAM,aAAa,EAAE,OAwB3B,CAAC;AAMF,eAAO,MAAM,aAAa,EAAE,OAsB3B,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,OA8BzB,CAAC;AAMF,eAAO,MAAM,eAAe,EAAE,OAc7B,CAAC;AAMF,eAAO,MAAM,eAAe,EAAE,OAO7B,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,OAQxB,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,OAAO,EAO/B,CAAC"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Core refrakt CLI tools, exposed as MCP tools.
3
+ *
4
+ * Each tool delegates to the same underlying logic the `refrakt` CLI uses,
5
+ * but produces structured JSON output suitable for MCP. Where the underlying
6
+ * CLI command prints to stdout (rather than returning data), the tool here
7
+ * captures stdout via a child-process spawn — the cost is one extra fork per
8
+ * call but it preserves the exact output the user would see.
9
+ */
10
+ import { execFileSync } from 'node:child_process';
11
+ import { resolveCliBin } from '../cli-bin.js';
12
+ const siteProp = {
13
+ type: 'string',
14
+ description: 'Site name (required for multi-site projects).',
15
+ };
16
+ // ----------------------------------------------------------------------------
17
+ // refrakt.reference — emit the rune syntax reference
18
+ // ----------------------------------------------------------------------------
19
+ export const referenceTool = {
20
+ name: 'refrakt.reference',
21
+ description: 'Emit the rune syntax reference for the active package set. Useful for AI agents that need to know which runes are available and how to use them.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {
25
+ format: { type: 'string', enum: ['markdown', 'json'], description: 'Output format. Default: json.' },
26
+ site: siteProp,
27
+ rune: { type: 'string', description: 'When set, emit reference for a single rune by name.' },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ async handler(input, ctx) {
32
+ const o = input;
33
+ const args = ['reference'];
34
+ if (o.rune)
35
+ args.push(o.rune);
36
+ args.push('--format', o.format ?? 'json');
37
+ if (o.site)
38
+ args.push('--site', o.site);
39
+ const stdout = invokeCli(args, ctx.cwd);
40
+ return o.format === 'markdown'
41
+ ? { format: 'markdown', text: stdout }
42
+ : tryParseJson(stdout);
43
+ },
44
+ };
45
+ // ----------------------------------------------------------------------------
46
+ // refrakt.contracts — generate structure contracts JSON
47
+ // ----------------------------------------------------------------------------
48
+ export const contractsTool = {
49
+ name: 'refrakt.contracts',
50
+ description: 'Generate the full structure contract for the active rune set: per-rune BEM block, modifiers, data attributes, structural elements. Useful for theme authors and CSS coverage tooling.',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: {
54
+ site: siteProp,
55
+ },
56
+ additionalProperties: false,
57
+ },
58
+ async handler(input, ctx) {
59
+ const o = input;
60
+ const args = ['contracts', '-o', '/dev/stdout'];
61
+ if (o.site)
62
+ args.push('--site', o.site);
63
+ const stdout = invokeCli(args, ctx.cwd);
64
+ // `refrakt contracts -o /dev/stdout` writes the JSON contract to stdout
65
+ // followed by a "Written ..." line on stderr — we only want the JSON.
66
+ const start = stdout.indexOf('{');
67
+ if (start === -1)
68
+ throw new Error('contracts produced no JSON output');
69
+ return JSON.parse(stdout.slice(start));
70
+ },
71
+ };
72
+ // ----------------------------------------------------------------------------
73
+ // refrakt.inspect — see the identity transform output for a rune
74
+ // ----------------------------------------------------------------------------
75
+ export const inspectTool = {
76
+ name: 'refrakt.inspect',
77
+ description: 'Show the identity transform output for a rune: the HTML it produces with BEM classes and data attributes for a given attribute set. Returns the JSON view (--json) so MCP clients can consume the structured contract.',
78
+ inputSchema: {
79
+ type: 'object',
80
+ required: ['rune'],
81
+ properties: {
82
+ rune: { type: 'string', description: 'Rune name (e.g. "hint", "hero").' },
83
+ attributes: {
84
+ type: 'object',
85
+ additionalProperties: { type: 'string' },
86
+ description: 'Rune attributes to set (e.g. { type: "warning" }).',
87
+ },
88
+ site: siteProp,
89
+ },
90
+ additionalProperties: false,
91
+ },
92
+ async handler(input, ctx) {
93
+ const o = input;
94
+ const args = ['inspect', o.rune, '--json'];
95
+ if (o.attributes) {
96
+ for (const [k, v] of Object.entries(o.attributes)) {
97
+ args.push(`--${k}=${v}`);
98
+ }
99
+ }
100
+ if (o.site)
101
+ args.push('--site', o.site);
102
+ const stdout = invokeCli(args, ctx.cwd);
103
+ return tryParseJson(stdout);
104
+ },
105
+ };
106
+ // ----------------------------------------------------------------------------
107
+ // refrakt.inspect_list — list all available runes
108
+ // ----------------------------------------------------------------------------
109
+ export const inspectListTool = {
110
+ name: 'refrakt.inspect_list',
111
+ description: 'List every rune available in the active package set.',
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: { site: siteProp },
115
+ additionalProperties: false,
116
+ },
117
+ async handler(input, ctx) {
118
+ const o = input;
119
+ const args = ['inspect', '--list', '--json'];
120
+ if (o.site)
121
+ args.push('--site', o.site);
122
+ return tryParseJson(invokeCli(args, ctx.cwd));
123
+ },
124
+ };
125
+ // ----------------------------------------------------------------------------
126
+ // refrakt.plugins_list — list installed plugins
127
+ // ----------------------------------------------------------------------------
128
+ export const pluginsListTool = {
129
+ name: 'refrakt.plugins_list',
130
+ description: 'List installed refrakt plugin packages with their commands and MCP schema availability.',
131
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
132
+ async handler(_input, ctx) {
133
+ return tryParseJson(invokeCli(['plugins', 'list', '--json'], ctx.cwd));
134
+ },
135
+ };
136
+ // ----------------------------------------------------------------------------
137
+ // refrakt.detect — return the detection result (also exposed as a resource)
138
+ // ----------------------------------------------------------------------------
139
+ export const detectTool = {
140
+ name: 'refrakt.detect',
141
+ description: 'Report the detected refrakt context (plan dir, declared sites, installed plugins, config source).',
142
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
143
+ async handler(_input, ctx) {
144
+ const { detect } = await import('../detect.js');
145
+ return detect(ctx.cwd);
146
+ },
147
+ };
148
+ // ----------------------------------------------------------------------------
149
+ // Aggregate set
150
+ // ----------------------------------------------------------------------------
151
+ export const CORE_TOOLS = [
152
+ detectTool,
153
+ pluginsListTool,
154
+ referenceTool,
155
+ contractsTool,
156
+ inspectTool,
157
+ inspectListTool,
158
+ ];
159
+ // ----------------------------------------------------------------------------
160
+ // Helpers
161
+ // ----------------------------------------------------------------------------
162
+ /** Resolve and invoke the refrakt CLI bin, returning stdout. Throws with the
163
+ * CLI's stderr on non-zero exit so the MCP handler surfaces the user-facing
164
+ * error message. */
165
+ function invokeCli(args, cwd) {
166
+ const bin = resolveCliBin();
167
+ try {
168
+ return execFileSync('node', [bin, ...args], {
169
+ encoding: 'utf-8',
170
+ cwd,
171
+ stdio: ['ignore', 'pipe', 'pipe'],
172
+ maxBuffer: 50 * 1024 * 1024,
173
+ });
174
+ }
175
+ catch (err) {
176
+ const stderr = (err.stderr ?? '').toString();
177
+ const stdout = (err.stdout ?? '').toString();
178
+ const message = stderr || stdout || err.message;
179
+ const wrapped = new Error(`refrakt ${args[0]} failed: ${message.trim()}`);
180
+ wrapped.errorCode = 'CLI_INVOCATION_FAILED';
181
+ throw wrapped;
182
+ }
183
+ }
184
+ function tryParseJson(text) {
185
+ const trimmed = text.trim();
186
+ if (!trimmed)
187
+ return null;
188
+ try {
189
+ return JSON.parse(trimmed);
190
+ }
191
+ catch {
192
+ // Some CLI commands print extra lines around the JSON; pull the first
193
+ // JSON-shaped substring.
194
+ const start = trimmed.indexOf('{');
195
+ const arrStart = trimmed.indexOf('[');
196
+ const idx = start === -1 ? arrStart : arrStart === -1 ? start : Math.min(start, arrStart);
197
+ if (idx === -1)
198
+ return { raw: trimmed };
199
+ return JSON.parse(trimmed.slice(idx));
200
+ }
201
+ }
202
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/tools/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Plugin-contributed MCP tools.
3
+ *
4
+ * Each command from a discovered plugin (e.g. @refrakt-md/plan) becomes an
5
+ * MCP tool under `<namespace>.<name>`. Commands that declare an `mcpHandler`
6
+ * are invoked directly with the structured input. Commands without one fall
7
+ * back to argv-shimming: the handler receives an object, we serialize it into
8
+ * argv strings, and call the existing CLI handler.
9
+ */
10
+ import type { McpTool } from './core.js';
11
+ /** Discover installed plugins and convert each command into an MCP tool. */
12
+ export declare function loadPluginTools(cwd: string): Promise<McpTool[]>;
13
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../src/tools/plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,4EAA4E;AAC5E,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAWrE"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Plugin-contributed MCP tools.
3
+ *
4
+ * Each command from a discovered plugin (e.g. @refrakt-md/plan) becomes an
5
+ * MCP tool under `<namespace>.<name>`. Commands that declare an `mcpHandler`
6
+ * are invoked directly with the structured input. Commands without one fall
7
+ * back to argv-shimming: the handler receives an object, we serialize it into
8
+ * argv strings, and call the existing CLI handler.
9
+ */
10
+ import { discoverPlugins } from '@refrakt-md/cli/lib/plugins.js';
11
+ /** Commands that should not be exposed via MCP — long-running servers,
12
+ * filesystem generators, etc. that don't fit the request/response model. */
13
+ const EXCLUDED_COMMANDS = new Set([
14
+ 'plan.serve',
15
+ 'plan.build',
16
+ ]);
17
+ /** Discover installed plugins and convert each command into an MCP tool. */
18
+ export async function loadPluginTools(cwd) {
19
+ const discovered = await discoverPlugins({ cwd, warn: false });
20
+ const tools = [];
21
+ for (const plugin of discovered) {
22
+ for (const command of plugin.commands) {
23
+ const toolName = `${plugin.namespace}.${command.name}`;
24
+ if (EXCLUDED_COMMANDS.has(toolName))
25
+ continue;
26
+ tools.push(buildPluginTool(toolName, command));
27
+ }
28
+ }
29
+ return tools;
30
+ }
31
+ function buildPluginTool(name, command) {
32
+ const inputSchema = command.inputSchema ?? {
33
+ type: 'object',
34
+ additionalProperties: true,
35
+ description: 'Free-form arguments — this command has no inputSchema yet, so MCP cannot validate inputs.',
36
+ };
37
+ return {
38
+ name,
39
+ description: command.description,
40
+ inputSchema,
41
+ handler: async (input) => {
42
+ if (command.mcpHandler) {
43
+ return command.mcpHandler(input);
44
+ }
45
+ // Fallback: serialize the input as argv and invoke the legacy
46
+ // handler. Captures stdout via a simple buffer hack.
47
+ const args = inputToArgv(input);
48
+ const captured = await captureStdout(() => command.handler(args));
49
+ return tryParseJson(captured);
50
+ },
51
+ };
52
+ }
53
+ /** Translate a structured input object into a flat argv array suitable for
54
+ * legacy `handler(args)` consumption. Boolean true → bare flag; everything
55
+ * else → `--key`, `value` pair. Nested objects/arrays are JSON-stringified. */
56
+ function inputToArgv(input) {
57
+ if (!input || typeof input !== 'object')
58
+ return [];
59
+ const args = [];
60
+ for (const [key, value] of Object.entries(input)) {
61
+ if (value === undefined || value === null)
62
+ continue;
63
+ if (value === true) {
64
+ args.push(`--${key}`);
65
+ continue;
66
+ }
67
+ if (value === false)
68
+ continue;
69
+ if (typeof value === 'string' || typeof value === 'number') {
70
+ args.push(`--${key}`, String(value));
71
+ continue;
72
+ }
73
+ args.push(`--${key}`, JSON.stringify(value));
74
+ }
75
+ return args;
76
+ }
77
+ /** Capture writes to process.stdout while running fn(). Restores stdout when
78
+ * done. Used as the legacy-handler fallback because most plugin commands
79
+ * print structured JSON to stdout when given `--format json`. */
80
+ async function captureStdout(fn) {
81
+ const chunks = [];
82
+ const originalWrite = process.stdout.write.bind(process.stdout);
83
+ process.stdout.write = (chunk) => {
84
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
85
+ return true;
86
+ };
87
+ try {
88
+ await fn();
89
+ }
90
+ finally {
91
+ process.stdout.write = originalWrite;
92
+ }
93
+ return Buffer.concat(chunks).toString('utf-8');
94
+ }
95
+ function tryParseJson(text) {
96
+ const trimmed = text.trim();
97
+ if (!trimmed)
98
+ return null;
99
+ try {
100
+ return JSON.parse(trimmed);
101
+ }
102
+ catch {
103
+ return { raw: trimmed };
104
+ }
105
+ }
106
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/tools/plugins.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@refrakt-md/mcp",
3
3
  "description": "Model Context Protocol server wrapping the refrakt CLI",
4
- "version": "0.11.0",
4
+ "version": "0.11.2",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -33,9 +33,9 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@modelcontextprotocol/sdk": "^1.29.0",
36
- "@refrakt-md/cli": "0.11.0",
37
- "@refrakt-md/runes": "0.11.0",
38
- "@refrakt-md/transform": "0.11.0",
39
- "@refrakt-md/types": "0.11.0"
36
+ "@refrakt-md/cli": "0.11.2",
37
+ "@refrakt-md/runes": "0.11.2",
38
+ "@refrakt-md/transform": "0.11.2",
39
+ "@refrakt-md/types": "0.11.2"
40
40
  }
41
41
  }