@codai/axiom-mcp 1.0.23 → 2.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/dist/mcp-stdio.js DELETED
@@ -1,368 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
- import { parseAxiomSource } from "@codai/axiom-core/dist/parser.js";
6
- import { validateIR } from "@codai/axiom-core/dist/validator.js";
7
- import { AxiomIR } from "@codai/axiom-core/dist/ir.js";
8
- import { generate } from "@codai/axiom-engine/dist/generate.js";
9
- import { check } from "@codai/axiom-engine/dist/check.js";
10
- import { reverseIR } from "@codai/axiom-engine/dist/reverse-ir.js";
11
- import { diff } from "@codai/axiom-engine/dist/axpatch.js";
12
- import { apply } from "@codai/axiom-engine/dist/apply.js";
13
- import { readFileSync } from "node:fs";
14
- import { fileURLToPath } from "node:url";
15
- import { dirname, join } from "node:path";
16
- // Read version from package.json
17
- const __filename = fileURLToPath(import.meta.url);
18
- const __dirname = dirname(__filename);
19
- const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
20
- const MCP_VERSION = packageJson.version;
21
- // Helper to add version metadata to all responses
22
- function addVersionMetadata(result) {
23
- return {
24
- ...result,
25
- _axiom_mcp_version: MCP_VERSION,
26
- _axiom_engine_version: packageJson.dependencies?.["@codai/axiom-engine"] || "unknown"
27
- };
28
- }
29
- const server = new Server({
30
- name: "axiom-mcp",
31
- version: MCP_VERSION, // Use dynamic version from package.json
32
- }, {
33
- capabilities: {
34
- tools: {},
35
- },
36
- });
37
- server.setRequestHandler(ListToolsRequestSchema, async () => {
38
- return {
39
- tools: [
40
- {
41
- name: "axiom_parse",
42
- description: "Parse .axm source code to IR (Intermediate Representation)",
43
- inputSchema: {
44
- type: "object",
45
- properties: {
46
- source: {
47
- type: "string",
48
- description: "AXIOM source code (.axm)",
49
- },
50
- },
51
- required: ["source"],
52
- },
53
- },
54
- {
55
- name: "axiom_validate",
56
- description: "Validate IR semantics and constraints",
57
- inputSchema: {
58
- type: "object",
59
- properties: {
60
- ir: {
61
- type: "object",
62
- description: "AXIOM IR object",
63
- },
64
- },
65
- required: ["ir"],
66
- },
67
- },
68
- {
69
- name: "axiom_generate",
70
- description: "Generate artifacts and manifest from IR",
71
- inputSchema: {
72
- type: "object",
73
- properties: {
74
- ir: {
75
- type: "object",
76
- description: "AXIOM IR object",
77
- },
78
- profile: {
79
- type: "string",
80
- description: "Profile name (e.g., 'edge', 'budget')",
81
- },
82
- },
83
- required: ["ir"],
84
- },
85
- },
86
- {
87
- name: "axiom_check",
88
- description: "Run policy checks on manifest",
89
- inputSchema: {
90
- type: "object",
91
- properties: {
92
- manifest: {
93
- type: "object",
94
- description: "Generated manifest",
95
- },
96
- ir: {
97
- type: "object",
98
- description: "Optional IR for context",
99
- },
100
- },
101
- required: ["manifest"],
102
- },
103
- },
104
- {
105
- name: "axiom_reverse",
106
- description: "Reverse engineer IR from existing repository",
107
- inputSchema: {
108
- type: "object",
109
- properties: {
110
- repoPath: {
111
- type: "string",
112
- description: "Path to repository",
113
- },
114
- outDir: {
115
- type: "string",
116
- description: "Output directory to scan",
117
- default: "out",
118
- },
119
- },
120
- },
121
- },
122
- {
123
- name: "axiom_diff",
124
- description: "Generate diff patches between two IR versions",
125
- inputSchema: {
126
- type: "object",
127
- properties: {
128
- oldIr: {
129
- type: "object",
130
- description: "Old IR version",
131
- },
132
- newIr: {
133
- type: "object",
134
- description: "New IR version",
135
- },
136
- },
137
- required: ["oldIr", "newIr"],
138
- },
139
- },
140
- {
141
- name: "axiom_apply",
142
- description: "Apply manifest changes to filesystem",
143
- inputSchema: {
144
- type: "object",
145
- properties: {
146
- manifest: {
147
- type: "object",
148
- description: "Manifest to apply",
149
- },
150
- mode: {
151
- type: "string",
152
- enum: ["fs", "pr"],
153
- description: "Application mode: 'fs' for direct filesystem, 'pr' for pull request",
154
- default: "fs",
155
- },
156
- repoPath: {
157
- type: "string",
158
- description: "Repository path",
159
- },
160
- branchName: {
161
- type: "string",
162
- description: "Branch name for PR mode",
163
- },
164
- commitMessage: {
165
- type: "string",
166
- description: "Commit message for PR mode",
167
- },
168
- },
169
- required: ["manifest"],
170
- },
171
- },
172
- ],
173
- };
174
- });
175
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
176
- try {
177
- const { name, arguments: args } = request.params;
178
- switch (name) {
179
- case "axiom_parse": {
180
- const { source } = args;
181
- const { ir, diagnostics } = parseAxiomSource(source);
182
- return {
183
- content: [
184
- {
185
- type: "text",
186
- text: JSON.stringify(addVersionMetadata({ ir, diagnostics }), null, 2),
187
- },
188
- ],
189
- };
190
- }
191
- case "axiom_validate": {
192
- const { ir } = args;
193
- const parse = AxiomIR.safeParse(ir);
194
- if (!parse.success) {
195
- return {
196
- content: [
197
- {
198
- type: "text",
199
- text: JSON.stringify(addVersionMetadata({ ok: false, diagnostics: parse.error.issues }), null, 2),
200
- },
201
- ],
202
- };
203
- }
204
- const result = validateIR(parse.data);
205
- return {
206
- content: [
207
- {
208
- type: "text",
209
- text: JSON.stringify(addVersionMetadata(result), null, 2),
210
- },
211
- ],
212
- };
213
- }
214
- case "axiom_generate": {
215
- const { ir, profile } = args;
216
- const parse = AxiomIR.safeParse(ir);
217
- if (!parse.success) {
218
- return {
219
- content: [
220
- {
221
- type: "text",
222
- text: JSON.stringify({ error: parse.error.issues }, null, 2),
223
- },
224
- ],
225
- isError: true,
226
- };
227
- }
228
- const { artifacts, manifest } = await generate(parse.data, process.cwd(), profile);
229
- // DEBUG: Log artifact paths to stderr for debugging
230
- console.error("[MCP DEBUG] artifacts from generate():", JSON.stringify(artifacts.map(a => a.path)));
231
- console.error("[MCP DEBUG] manifest.artifacts:", JSON.stringify(manifest.artifacts.map(a => a.path)));
232
- return {
233
- content: [
234
- {
235
- type: "text",
236
- text: JSON.stringify(addVersionMetadata({ artifacts, manifest }), null, 2),
237
- },
238
- ],
239
- };
240
- }
241
- case "axiom_check": {
242
- const { manifest, ir } = args;
243
- const irParsed = ir ? AxiomIR.safeParse(ir) : null;
244
- const result = await check(manifest, irParsed?.success ? irParsed.data : undefined, process.cwd());
245
- return {
246
- content: [
247
- {
248
- type: "text",
249
- text: JSON.stringify(addVersionMetadata(result), null, 2),
250
- },
251
- ],
252
- };
253
- }
254
- case "axiom_reverse": {
255
- const { repoPath, outDir } = args;
256
- const ir = await reverseIR({
257
- repoPath: repoPath || process.cwd(),
258
- outDir: outDir || "out",
259
- });
260
- return {
261
- content: [
262
- {
263
- type: "text",
264
- text: JSON.stringify(addVersionMetadata({ ir, diagnostics: [] }), null, 2),
265
- },
266
- ],
267
- };
268
- }
269
- case "axiom_diff": {
270
- const { oldIr, newIr } = args;
271
- const oldParse = AxiomIR.safeParse(oldIr);
272
- const newParse = AxiomIR.safeParse(newIr);
273
- if (!oldParse.success || !newParse.success) {
274
- return {
275
- content: [
276
- {
277
- type: "text",
278
- text: JSON.stringify({
279
- error: "Invalid IR",
280
- oldIr: oldParse.success ? null : oldParse.error.issues,
281
- newIr: newParse.success ? null : newParse.error.issues,
282
- }, null, 2),
283
- },
284
- ],
285
- isError: true,
286
- };
287
- }
288
- const patch = await diff(oldParse.data, newParse.data);
289
- return {
290
- content: [
291
- {
292
- type: "text",
293
- text: JSON.stringify(addVersionMetadata({ patch }), null, 2),
294
- },
295
- ],
296
- };
297
- }
298
- case "axiom_apply": {
299
- const { manifest, mode, repoPath, branchName, commitMessage } = args;
300
- const result = await apply({
301
- manifest,
302
- mode: mode || "fs",
303
- repoPath: repoPath || process.cwd(),
304
- branchName,
305
- commitMessage,
306
- });
307
- return {
308
- content: [
309
- {
310
- type: "text",
311
- text: JSON.stringify(addVersionMetadata(result), null, 2),
312
- },
313
- ],
314
- };
315
- }
316
- default:
317
- return {
318
- content: [
319
- {
320
- type: "text",
321
- text: `Unknown tool: ${name}`,
322
- },
323
- ],
324
- isError: true,
325
- };
326
- }
327
- }
328
- catch (error) {
329
- return {
330
- content: [
331
- {
332
- type: "text",
333
- text: `Error: ${error.message || String(error)}`,
334
- },
335
- ],
336
- isError: true,
337
- };
338
- }
339
- });
340
- async function main() {
341
- console.error("[AXIOM MCP] Starting server initialization...");
342
- console.error(`[AXIOM MCP] Process: Node ${process.version}, PID ${process.pid}`);
343
- console.error(`[AXIOM MCP] Working directory: ${process.cwd()}`);
344
- // CRITICAL: Give VS Code time to attach stdio pipes
345
- // Without this delay, VS Code may miss early stderr output
346
- await new Promise(resolve => setTimeout(resolve, 100));
347
- console.error("[AXIOM MCP] Stdio pipes ready, proceeding with initialization...");
348
- try {
349
- const transport = new StdioServerTransport();
350
- console.error("[AXIOM MCP] Transport created, connecting...");
351
- await server.connect(transport);
352
- console.error("[AXIOM MCP] Server connected successfully");
353
- console.error(`[AXIOM MCP] Version ${MCP_VERSION}, Engine ${packageJson.dependencies?.["@codai/axiom-engine"]}`);
354
- console.error("[AXIOM MCP] Ready to receive requests via stdio");
355
- console.error("[AXIOM MCP] Waiting for initialize request from client...");
356
- // Keep process alive - MCP SDK handles stdin/stdout
357
- // No explicit exit - let MCP SDK manage lifecycle
358
- }
359
- catch (error) {
360
- console.error("[AXIOM MCP] FATAL - Initialization failed:", error.message || String(error));
361
- console.error("[AXIOM MCP] Stack trace:", error.stack);
362
- process.exit(1);
363
- }
364
- }
365
- main().catch((error) => {
366
- console.error("[AXIOM MCP] FATAL - Uncaught error in main():", error);
367
- process.exit(1);
368
- });
@@ -1,31 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- // Skip postinstall if running via npx (to avoid mutex issues)
5
- if (process.env.npm_command === 'exec' || process.env.npm_execpath?.includes('npx')) {
6
- console.log("⏭️ Skipping MCP config install (npx mode)");
7
- process.exit(0);
8
- }
9
- const mcpDir = path.join(os.homedir(), ".mcp", "servers");
10
- fs.mkdirSync(mcpDir, { recursive: true });
11
- const mcpConfig = {
12
- command: "npx",
13
- args: ["@codai/axiom-mcp"],
14
- env: {
15
- AXIOM_MCP_PORT: "3411"
16
- },
17
- description: "AXIOM - AI-native intention language with deterministic manifest generation",
18
- endpoints: [
19
- "/parse - Parse .axm source to IR",
20
- "/validate - Validate IR semantics",
21
- "/generate - Generate artifacts from IR",
22
- "/check - Run policy checks",
23
- "/reverse - Reverse engineer IR from repo",
24
- "/diff - Generate IR diff patches",
25
- "/apply - Apply patches to filesystem"
26
- ]
27
- };
28
- fs.writeFileSync(path.join(mcpDir, "axiom.json"), JSON.stringify(mcpConfig, null, 2));
29
- console.log("✅ AXIOM MCP config installed at ~/.mcp/servers/axiom.json");
30
- console.log(" Start server: npx axiom-mcp");
31
- console.log(" Default port: 3411");
package/dist/server.js DELETED
@@ -1,115 +0,0 @@
1
- import http from "node:http";
2
- import { parseAxiomSource } from "@codai/axiom-core/dist/parser.js";
3
- import { validateIR } from "@codai/axiom-core/dist/validator.js";
4
- import { AxiomIR } from "@codai/axiom-core/dist/ir.js";
5
- import { generate } from "@codai/axiom-engine/dist/generate.js";
6
- import { check } from "@codai/axiom-engine/dist/check.js";
7
- import { reverseIR } from "@codai/axiom-engine/dist/reverse-ir.js";
8
- import { diff } from "@codai/axiom-engine/dist/axpatch.js";
9
- import { apply } from "@codai/axiom-engine/dist/apply.js";
10
- const PORT = Number(process.env.AXIOM_MCP_PORT || 3411);
11
- function send(res, code, obj) {
12
- const body = JSON.stringify(obj, null, 2);
13
- res.writeHead(code, { "content-type": "application/json" });
14
- res.end(body);
15
- }
16
- const server = http.createServer(async (req, res) => {
17
- try {
18
- const chunks = [];
19
- req.on("data", (c) => chunks.push(c));
20
- req.on("end", async () => {
21
- const input = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf-8")) : {};
22
- if (req.method === "POST" && req.url === "/parse") {
23
- const { source } = input;
24
- const { ir, diagnostics } = parseAxiomSource(String(source ?? ""));
25
- return send(res, 200, { ir, diagnostics });
26
- }
27
- if (req.method === "POST" && req.url === "/validate") {
28
- const parse = AxiomIR.safeParse(input.ir);
29
- if (!parse.success)
30
- return send(res, 400, { ok: false, diagnostics: parse.error.issues });
31
- const result = validateIR(parse.data);
32
- return send(res, 200, result);
33
- }
34
- if (req.method === "POST" && req.url === "/generate") {
35
- const parse = AxiomIR.safeParse(input.ir);
36
- if (!parse.success)
37
- return send(res, 400, { error: parse.error.issues });
38
- const { artifacts, manifest } = await generate(parse.data, process.cwd(), input.profile);
39
- return send(res, 200, { artifacts, manifest });
40
- }
41
- if (req.method === "POST" && req.url === "/check") {
42
- const parse = input.ir ? AxiomIR.safeParse(input.ir) : null;
43
- const ir = parse?.success ? parse.data : undefined;
44
- const result = await check(input.manifest, ir, input.outRoot || process.cwd());
45
- return send(res, 200, result);
46
- }
47
- if (req.method === "POST" && req.url === "/reverse") {
48
- const ir = await reverseIR({
49
- repoPath: input.repoPath || process.cwd(),
50
- outDir: input.outDir || "out",
51
- });
52
- return send(res, 200, { ir, diagnostics: [] });
53
- }
54
- if (req.method === "POST" && req.url === "/diff") {
55
- const oldParse = AxiomIR.safeParse(input.oldIr);
56
- const newParse = AxiomIR.safeParse(input.newIr);
57
- if (!oldParse.success)
58
- return send(res, 400, { error: "Invalid oldIr", details: oldParse.error.issues });
59
- if (!newParse.success)
60
- return send(res, 400, { error: "Invalid newIr", details: newParse.error.issues });
61
- const patch = diff(oldParse.data, newParse.data);
62
- return send(res, 200, { patch });
63
- }
64
- if (req.method === "POST" && req.url === "/apply") {
65
- if (!input.manifest)
66
- return send(res, 400, { error: "Missing manifest" });
67
- const mode = input.mode || "fs";
68
- try {
69
- const result = await apply({
70
- manifest: input.manifest,
71
- mode: mode,
72
- repoPath: input.repoPath, // Optional - va folosi process.cwd() dacă lipsește
73
- branchName: input.branchName,
74
- commitMessage: input.commitMessage,
75
- });
76
- // Check for ERR_REPOPATH_RELATIVE_UNSAFE and provide friendly guidance
77
- if (!result.success && result.error?.includes("ERR_REPOPATH_RELATIVE_UNSAFE")) {
78
- return send(res, 200, {
79
- ...result,
80
- errorCode: "ERR_REPOPATH_RELATIVE_UNSAFE",
81
- hint: "Furnizează repoPath absolut sau setează AXIOM_REPO_ROOT la rădăcina repo-ului."
82
- });
83
- }
84
- return send(res, 200, result);
85
- }
86
- catch (err) {
87
- // Catch any other apply errors
88
- return send(res, 500, {
89
- success: false,
90
- mode,
91
- filesWritten: [],
92
- error: err.message
93
- });
94
- }
95
- }
96
- if (req.method === "POST" && req.url === "/fs-probe-write") {
97
- // Independent cross-drive write testing
98
- const { fs_probe_write } = await import("./tools/fs-probe-write.js");
99
- const result = await fs_probe_write({
100
- destAbs: input.destAbs,
101
- contentUtf8: input.contentUtf8,
102
- contentBase64: input.contentBase64
103
- });
104
- return send(res, 200, result);
105
- }
106
- send(res, 404, { error: "Not found" });
107
- });
108
- }
109
- catch (e) {
110
- send(res, 500, { error: String(e?.message || e) });
111
- }
112
- });
113
- server.listen(PORT, () => {
114
- console.log(`[axiom-mcp] listening on http://localhost:${PORT}`);
115
- });
@@ -1,81 +0,0 @@
1
- import fs from "node:fs";
2
- import crypto from "node:crypto";
3
- import path from "node:path";
4
- /**
5
- * fs_probe_write - Independent cross-drive write testing tool
6
- *
7
- * Tests filesystem write capabilities independently of AXIOM manifest logic.
8
- * Useful for validating cross-drive writes and arbitrary path support.
9
- */
10
- export async function fs_probe_write(args) {
11
- const { destAbs, contentUtf8, contentBase64 } = args;
12
- try {
13
- console.error(`[fs-probe-write] Testing write to: ${destAbs}`);
14
- // Determine content source
15
- let content;
16
- if (contentBase64) {
17
- console.error(`[fs-probe-write] Source: contentBase64 (${contentBase64.length} chars)`);
18
- content = Buffer.from(contentBase64, "base64");
19
- }
20
- else if (contentUtf8) {
21
- console.error(`[fs-probe-write] Source: contentUtf8 (${contentUtf8.length} chars)`);
22
- content = Buffer.from(contentUtf8, "utf8");
23
- }
24
- else {
25
- throw new Error("ERR_NO_CONTENT: Must provide either contentUtf8 or contentBase64");
26
- }
27
- console.error(`[fs-probe-write] Buffer size: ${content.length} bytes`);
28
- // Create parent directory
29
- const dir = path.dirname(destAbs);
30
- console.error(`[fs-probe-write] mkdir: ${dir}`);
31
- await fs.promises.mkdir(dir, { recursive: true });
32
- // Write file
33
- console.error(`[fs-probe-write] Writing...`);
34
- await fs.promises.writeFile(destAbs, content);
35
- // Read back and verify
36
- console.error(`[fs-probe-write] Reading back...`);
37
- const readBack = fs.readFileSync(destAbs);
38
- const hash = crypto.createHash("sha256").update(readBack).digest("hex");
39
- const size = readBack.length;
40
- console.error(`[fs-probe-write] ✓ Read-back size: ${size} bytes`);
41
- console.error(`[fs-probe-write] ✓ Read-back SHA256: ${hash}`);
42
- return {
43
- success: true,
44
- absPath: destAbs,
45
- hash,
46
- size
47
- };
48
- }
49
- catch (error) {
50
- console.error(`[fs-probe-write] ✗ ERROR: ${error.message}`);
51
- return {
52
- success: false,
53
- absPath: destAbs,
54
- hash: "",
55
- size: 0,
56
- error: error.message
57
- };
58
- }
59
- }
60
- export const fs_probe_write_def = {
61
- name: "fs_probe_write",
62
- description: "Independent cross-drive write testing tool for validating filesystem capabilities",
63
- inputSchema: {
64
- type: "object",
65
- properties: {
66
- destAbs: {
67
- type: "string",
68
- description: "Absolute destination path (can be on any drive)"
69
- },
70
- contentUtf8: {
71
- type: "string",
72
- description: "Optional UTF-8 content to write"
73
- },
74
- contentBase64: {
75
- type: "string",
76
- description: "Optional Base64-encoded content to write"
77
- }
78
- },
79
- required: ["destAbs"]
80
- }
81
- };
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * AXIOM MCP Prepublish Script
4
- *
5
- * Bundles all internal workspace dependencies into axiom-mcp dist/
6
- * so that the published package is self-contained and doesn't require workspace:* protocol.
7
- */
8
-
9
- import { copyFileSync, mkdirSync, readdirSync, statSync } from 'fs';
10
- import { join, dirname } from 'path';
11
- import { fileURLToPath } from 'url';
12
-
13
- const __dirname = dirname(fileURLToPath(import.meta.url));
14
-
15
- const INTERNAL_PACKAGES = [
16
- 'axiom-core',
17
- 'axiom-engine',
18
- 'axiom-policies',
19
- 'axiom-emitter-apiservice',
20
- 'axiom-emitter-batchjob',
21
- 'axiom-emitter-docker',
22
- 'axiom-emitter-webapp'
23
- ];
24
-
25
- function copyDir(src, dest) {
26
- mkdirSync(dest, { recursive: true });
27
-
28
- for (const file of readdirSync(src)) {
29
- const srcPath = join(src, file);
30
- const destPath = join(dest, file);
31
-
32
- if (statSync(srcPath).isDirectory()) {
33
- copyDir(srcPath, destPath);
34
- } else if (file.endsWith('.js') || file.endsWith('.d.ts')) {
35
- copyFileSync(srcPath, destPath);
36
- console.log(` ✓ ${file}`);
37
- }
38
- }
39
- }
40
-
41
- console.log('📦 Bundling internal dependencies...\n');
42
-
43
- for (const pkg of INTERNAL_PACKAGES) {
44
- const srcDir = join(__dirname, '..', '..', pkg, 'dist');
45
- const destDir = join(__dirname, '..', 'dist', 'vendor', pkg);
46
-
47
- console.log(`Bundling @codai/${pkg}:`);
48
- copyDir(srcDir, destDir);
49
- console.log('');
50
- }
51
-
52
- console.log('✅ Bundle complete! Package is self-contained.\n');