crukx-mcp 0.1.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/README.md +47 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +82 -0
- package/dist/chunk-5FGEDZZW.js +55 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +232 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# crukx-mcp
|
|
2
|
+
|
|
3
|
+
Crukx MCP server — reliability control plane for autonomous software engineering.
|
|
4
|
+
|
|
5
|
+
Connect Cursor, Claude Desktop, or any MCP-compatible IDE to the Crukx 7-agent swarm.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g crukx-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Login
|
|
16
|
+
```bash
|
|
17
|
+
crukx login
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Add to Cursor / Claude Desktop
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"crukx": {
|
|
26
|
+
"command": "crukx",
|
|
27
|
+
"args": ["mcp"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Tools
|
|
34
|
+
|
|
35
|
+
| Tool | Description |
|
|
36
|
+
|------|-------------|
|
|
37
|
+
| `swarm_audit` | Full 7-agent reliability audit |
|
|
38
|
+
| `security_scan` | Targeted security analysis |
|
|
39
|
+
| `reliability_score` | Quick reliability score |
|
|
40
|
+
| `report_fetch` | Fetch audit report by ID |
|
|
41
|
+
| `suggest_fix` | Remediation suggestions |
|
|
42
|
+
| `crukx_health` | Check gateway connectivity |
|
|
43
|
+
|
|
44
|
+
## Links
|
|
45
|
+
|
|
46
|
+
- [crukx.dev](https://crukx.dev)
|
|
47
|
+
- [GitHub](https://github.com/Shafwansafi06/observability-hub)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
import {
|
|
4
|
+
CONFIG_PATH,
|
|
5
|
+
clearAuth,
|
|
6
|
+
getConfig,
|
|
7
|
+
loadAuth,
|
|
8
|
+
saveAuth
|
|
9
|
+
} from "../chunk-5FGEDZZW.js";
|
|
10
|
+
|
|
11
|
+
// src/bin/cli.ts
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
import { mkdirSync } from "fs";
|
|
14
|
+
import { dirname } from "path";
|
|
15
|
+
import { createInterface } from "readline";
|
|
16
|
+
import { spawn } from "child_process";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
import { join, dirname as pathDirname } from "path";
|
|
19
|
+
var __dirname = pathDirname(fileURLToPath(import.meta.url));
|
|
20
|
+
var program = new Command();
|
|
21
|
+
program.name("crukx").description("Crukx CLI \u2014 reliability control plane for autonomous software engineering").version("0.1.0");
|
|
22
|
+
program.command("login").description("Authenticate with Crukx").option("--api-url <url>", "Crukx gateway URL", getConfig().CRUKX_API_URL).option("--workspace-id <id>", "Workspace ID").action(async (opts) => {
|
|
23
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
24
|
+
const ask = (q) => new Promise((r) => rl.question(q, r));
|
|
25
|
+
try {
|
|
26
|
+
const email = await ask("Email: ");
|
|
27
|
+
const password = await ask("Password: ");
|
|
28
|
+
const workspaceId = opts.workspaceId ?? await ask("Workspace ID: ");
|
|
29
|
+
rl.close();
|
|
30
|
+
process.stderr.write("Authenticating...\n");
|
|
31
|
+
const res = await fetch(`${opts.apiUrl}/v1/mcp/auth/login`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify({ email, password, workspace_id: workspaceId })
|
|
35
|
+
});
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
const err = await res.json();
|
|
38
|
+
process.stderr.write(`Login failed: ${err.error ?? res.status}
|
|
39
|
+
`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const data = await res.json();
|
|
43
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
44
|
+
saveAuth({
|
|
45
|
+
access_token: data.access_token,
|
|
46
|
+
workspace_id: data.workspace_id,
|
|
47
|
+
expires_at: data.expires_at,
|
|
48
|
+
api_url: opts.apiUrl
|
|
49
|
+
});
|
|
50
|
+
process.stderr.write(`\u2705 Logged in. Config saved to ${CONFIG_PATH}
|
|
51
|
+
`);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
rl.close();
|
|
54
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
55
|
+
`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
program.command("logout").description("Revoke current session").action(() => {
|
|
60
|
+
clearAuth();
|
|
61
|
+
process.stderr.write("Logged out.\n");
|
|
62
|
+
});
|
|
63
|
+
program.command("whoami").description("Show current auth status").action(() => {
|
|
64
|
+
const auth = loadAuth();
|
|
65
|
+
if (!auth?.access_token) {
|
|
66
|
+
process.stderr.write("Not logged in. Run: crukx login\n");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
process.stdout.write(`Workspace: ${auth.workspace_id}
|
|
70
|
+
Expires: ${auth.expires_at}
|
|
71
|
+
API: ${auth.api_url}
|
|
72
|
+
`);
|
|
73
|
+
});
|
|
74
|
+
program.command("mcp").description("Start the Crukx MCP server (stdio transport)").action(() => {
|
|
75
|
+
const serverPath = join(__dirname, "server.js");
|
|
76
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
77
|
+
stdio: "inherit",
|
|
78
|
+
env: process.env
|
|
79
|
+
});
|
|
80
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
81
|
+
});
|
|
82
|
+
program.parse();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/config/index.ts
|
|
4
|
+
import "dotenv/config";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { readFileSync, existsSync } from "fs";
|
|
9
|
+
var ConfigSchema = z.object({
|
|
10
|
+
CRUKX_API_URL: z.string().url().default("https://crukx-gateway.salmonisland-7ebc5692.centralindia.azurecontainerapps.io"),
|
|
11
|
+
CRUKX_ACCESS_TOKEN: z.string().optional(),
|
|
12
|
+
CRUKX_WORKSPACE_ID: z.string().optional()
|
|
13
|
+
});
|
|
14
|
+
function loadLocalConfig() {
|
|
15
|
+
const configPath = join(homedir(), ".crukx", "config.json");
|
|
16
|
+
if (!existsSync(configPath)) return {};
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function getConfig() {
|
|
24
|
+
const local = loadLocalConfig();
|
|
25
|
+
return ConfigSchema.parse({ ...local, ...process.env });
|
|
26
|
+
}
|
|
27
|
+
var CONFIG_PATH = join(homedir(), ".crukx", "config.json");
|
|
28
|
+
|
|
29
|
+
// src/auth/index.ts
|
|
30
|
+
import { mkdirSync, writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
31
|
+
import { dirname } from "path";
|
|
32
|
+
function saveAuth(auth) {
|
|
33
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
34
|
+
const existing = loadAuth() ?? {};
|
|
35
|
+
writeFileSync(CONFIG_PATH, JSON.stringify({ ...existing, ...auth }, null, 2));
|
|
36
|
+
}
|
|
37
|
+
function loadAuth() {
|
|
38
|
+
if (!existsSync2(CONFIG_PATH)) return null;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function clearAuth() {
|
|
46
|
+
if (existsSync2(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
getConfig,
|
|
51
|
+
CONFIG_PATH,
|
|
52
|
+
saveAuth,
|
|
53
|
+
loadAuth,
|
|
54
|
+
clearAuth
|
|
55
|
+
};
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getConfig,
|
|
4
|
+
loadAuth
|
|
5
|
+
} from "./chunk-5FGEDZZW.js";
|
|
6
|
+
|
|
7
|
+
// src/server.ts
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
|
|
11
|
+
// src/tools/index.ts
|
|
12
|
+
import { z as z2 } from "zod";
|
|
13
|
+
|
|
14
|
+
// src/api/client.ts
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { randomUUID } from "crypto";
|
|
17
|
+
var TIMEOUT_MS = 6e4;
|
|
18
|
+
var AuditResultSchema = z.object({
|
|
19
|
+
auditId: z.string(),
|
|
20
|
+
findings: z.array(z.object({
|
|
21
|
+
id: z.string(),
|
|
22
|
+
rule: z.string(),
|
|
23
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]),
|
|
24
|
+
message: z.string(),
|
|
25
|
+
file: z.string(),
|
|
26
|
+
line: z.number(),
|
|
27
|
+
suggestion: z.string().optional(),
|
|
28
|
+
confidence: z.number(),
|
|
29
|
+
category: z.string()
|
|
30
|
+
})),
|
|
31
|
+
summary: z.object({
|
|
32
|
+
totalFindings: z.number(),
|
|
33
|
+
criticalCount: z.number(),
|
|
34
|
+
highCount: z.number(),
|
|
35
|
+
mediumCount: z.number(),
|
|
36
|
+
lowCount: z.number(),
|
|
37
|
+
infoCount: z.number(),
|
|
38
|
+
reliabilityScore: z.number(),
|
|
39
|
+
confidence: z.number()
|
|
40
|
+
}),
|
|
41
|
+
metadata: z.object({
|
|
42
|
+
processingTimeMs: z.number(),
|
|
43
|
+
agentsUsed: z.array(z.string()),
|
|
44
|
+
swarmId: z.string()
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
async function request(path, init = {}) {
|
|
48
|
+
const auth = loadAuth();
|
|
49
|
+
const cfg = getConfig();
|
|
50
|
+
const baseUrl = auth?.api_url ?? cfg.CRUKX_API_URL;
|
|
51
|
+
const token = auth?.access_token ?? cfg.CRUKX_ACCESS_TOKEN;
|
|
52
|
+
if (!token) throw new Error("Not authenticated. Run: crukx login");
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
57
|
+
...init,
|
|
58
|
+
signal: controller.signal,
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
Authorization: `Bearer ${token}`,
|
|
62
|
+
"X-Crukx-Source": "mcp",
|
|
63
|
+
...init.headers
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (res.status === 401) throw new Error("Token expired or invalid. Run: crukx login");
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const body = await res.text().catch(() => "");
|
|
69
|
+
throw new Error(`Crukx API ${res.status}: ${body}`);
|
|
70
|
+
}
|
|
71
|
+
return res.json();
|
|
72
|
+
} finally {
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function swarmAudit(params) {
|
|
77
|
+
const auth = loadAuth();
|
|
78
|
+
const body = {
|
|
79
|
+
jobId: randomUUID(),
|
|
80
|
+
repository: { id: 0, owner: "mcp", name: "audit", fullName: "mcp/audit" },
|
|
81
|
+
pullRequest: {
|
|
82
|
+
number: 0,
|
|
83
|
+
headSha: randomUUID().replace(/-/g, "").slice(0, 40),
|
|
84
|
+
baseSha: randomUUID().replace(/-/g, "").slice(0, 40),
|
|
85
|
+
headRef: "main",
|
|
86
|
+
baseRef: "main",
|
|
87
|
+
title: params.focus ?? "MCP Audit"
|
|
88
|
+
},
|
|
89
|
+
diff: params.diff ?? `# Audit request
|
|
90
|
+
focus: ${params.focus ?? "general"}
|
|
91
|
+
path: ${params.repoPath ?? "."}`,
|
|
92
|
+
triggeredBy: "mcp",
|
|
93
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94
|
+
workspace_id: params.workspaceId ?? auth?.workspace_id
|
|
95
|
+
};
|
|
96
|
+
const raw = await request("/v1/mcp/swarm/audit", { method: "POST", body: JSON.stringify(body) });
|
|
97
|
+
return AuditResultSchema.parse(raw);
|
|
98
|
+
}
|
|
99
|
+
async function fetchReport(reportId) {
|
|
100
|
+
return request(`/v1/mcp/reports/${reportId}`);
|
|
101
|
+
}
|
|
102
|
+
async function healthCheck() {
|
|
103
|
+
return request("/v1/mcp/health");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/tools/index.ts
|
|
107
|
+
function formatFindings(result) {
|
|
108
|
+
const { summary, findings, metadata } = result;
|
|
109
|
+
const grade = summary.reliabilityScore >= 90 ? "A" : summary.reliabilityScore >= 80 ? "B" : summary.reliabilityScore >= 70 ? "C" : "D";
|
|
110
|
+
const lines = [
|
|
111
|
+
`## Crukx Reliability Score: ${summary.reliabilityScore}/100 (Grade ${grade})`,
|
|
112
|
+
`Confidence: ${summary.confidence}% | Agents: ${metadata.agentsUsed.join(", ")} | Time: ${metadata.processingTimeMs}ms`,
|
|
113
|
+
``,
|
|
114
|
+
`| Severity | Count |`,
|
|
115
|
+
`|----------|-------|`,
|
|
116
|
+
`| Critical | ${summary.criticalCount} |`,
|
|
117
|
+
`| High | ${summary.highCount} |`,
|
|
118
|
+
`| Medium | ${summary.mediumCount} |`,
|
|
119
|
+
`| Low | ${summary.lowCount} |`,
|
|
120
|
+
`| Info | ${summary.infoCount} |`
|
|
121
|
+
];
|
|
122
|
+
if (findings.length > 0) {
|
|
123
|
+
lines.push("", "### Findings");
|
|
124
|
+
for (const f of findings.slice(0, 20)) {
|
|
125
|
+
lines.push(`- **[${f.severity.toUpperCase()}]** \`${f.file}:${f.line}\` \u2014 ${f.message}`);
|
|
126
|
+
if (f.suggestion) lines.push(` > ${f.suggestion}`);
|
|
127
|
+
}
|
|
128
|
+
if (findings.length > 20) lines.push(` ... and ${findings.length - 20} more`);
|
|
129
|
+
}
|
|
130
|
+
return lines.join("\n");
|
|
131
|
+
}
|
|
132
|
+
function registerTools(server2) {
|
|
133
|
+
server2.tool(
|
|
134
|
+
"swarm_audit",
|
|
135
|
+
"Run a full Crukx 7-agent swarm audit on code. Returns reliability score, findings, and recommendations.",
|
|
136
|
+
{
|
|
137
|
+
diff: z2.string().optional().describe("Unified diff or code snippet to audit"),
|
|
138
|
+
repoPath: z2.string().optional().describe("Repository path or name for context"),
|
|
139
|
+
focus: z2.string().optional().describe('Specific area to focus on (e.g. "security", "concurrency")')
|
|
140
|
+
},
|
|
141
|
+
async ({ diff, repoPath, focus }) => {
|
|
142
|
+
const result = await swarmAudit({ diff, repoPath, focus });
|
|
143
|
+
return { content: [{ type: "text", text: formatFindings(result) }] };
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
server2.tool(
|
|
147
|
+
"security_scan",
|
|
148
|
+
"Run a targeted security scan using the Red Teamer and Hunter agents.",
|
|
149
|
+
{
|
|
150
|
+
diff: z2.string().describe("Code diff or snippet to scan for security issues")
|
|
151
|
+
},
|
|
152
|
+
async ({ diff }) => {
|
|
153
|
+
const result = await swarmAudit({ diff, focus: "security vulnerabilities, injection attacks, secrets, authentication flaws" });
|
|
154
|
+
const secFindings = result.findings.filter((f) => f.category === "security" || f.severity === "critical" || f.severity === "high");
|
|
155
|
+
const lines = secFindings.length === 0 ? ["\u2705 No security issues detected."] : secFindings.map((f) => `- **[${f.severity.toUpperCase()}]** ${f.message}
|
|
156
|
+
File: \`${f.file}:${f.line}\`${f.suggestion ? `
|
|
157
|
+
Fix: ${f.suggestion}` : ""}`);
|
|
158
|
+
return { content: [{ type: "text", text: `## Security Scan Results
|
|
159
|
+
|
|
160
|
+
${lines.join("\n")}` }] };
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
server2.tool(
|
|
164
|
+
"reliability_score",
|
|
165
|
+
"Get a reliability score for a code change without full findings detail.",
|
|
166
|
+
{
|
|
167
|
+
diff: z2.string().describe("Code diff to score")
|
|
168
|
+
},
|
|
169
|
+
async ({ diff }) => {
|
|
170
|
+
const result = await swarmAudit({ diff });
|
|
171
|
+
const { reliabilityScore, confidence, criticalCount, highCount } = result.summary;
|
|
172
|
+
const passed = criticalCount === 0 && highCount === 0;
|
|
173
|
+
const text = [
|
|
174
|
+
`**Score:** ${reliabilityScore}/100`,
|
|
175
|
+
`**Gate:** ${passed ? "\u2705 PASSED" : "\u274C FAILED"}`,
|
|
176
|
+
`**Confidence:** ${confidence}%`,
|
|
177
|
+
`**Critical:** ${criticalCount} | **High:** ${highCount}`
|
|
178
|
+
].join("\n");
|
|
179
|
+
return { content: [{ type: "text", text }] };
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
server2.tool(
|
|
183
|
+
"report_fetch",
|
|
184
|
+
"Fetch a previously generated Crukx audit report by ID.",
|
|
185
|
+
{
|
|
186
|
+
report_id: z2.string().uuid().describe("Audit run ID to fetch")
|
|
187
|
+
},
|
|
188
|
+
async ({ report_id }) => {
|
|
189
|
+
const report = await fetchReport(report_id);
|
|
190
|
+
return { content: [{ type: "text", text: JSON.stringify(report, null, 2) }] };
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
server2.tool(
|
|
194
|
+
"suggest_fix",
|
|
195
|
+
"Get remediation suggestions for a specific finding or code issue.",
|
|
196
|
+
{
|
|
197
|
+
issue: z2.string().describe("Description of the issue or paste the problematic code"),
|
|
198
|
+
severity: z2.enum(["critical", "high", "medium", "low"]).optional().describe("Severity level")
|
|
199
|
+
},
|
|
200
|
+
async ({ issue, severity }) => {
|
|
201
|
+
const focus = `remediation and fix suggestions for: ${issue}. Severity: ${severity ?? "unknown"}`;
|
|
202
|
+
const result = await swarmAudit({ diff: issue, focus });
|
|
203
|
+
const suggestions = result.findings.filter((f) => f.suggestion).map((f) => `- **${f.rule}**: ${f.suggestion}`).join("\n");
|
|
204
|
+
return {
|
|
205
|
+
content: [{
|
|
206
|
+
type: "text",
|
|
207
|
+
text: suggestions.length > 0 ? `## Remediation Suggestions
|
|
208
|
+
|
|
209
|
+
${suggestions}` : "\u2705 No specific remediation needed \u2014 code looks clean."
|
|
210
|
+
}]
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
server2.tool(
|
|
215
|
+
"crukx_health",
|
|
216
|
+
"Check Crukx gateway connectivity and authentication status.",
|
|
217
|
+
{},
|
|
218
|
+
async () => {
|
|
219
|
+
const result = await healthCheck();
|
|
220
|
+
return { content: [{ type: "text", text: `Crukx gateway: ${result.status} \u2705` }] };
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/server.ts
|
|
226
|
+
var server = new McpServer({
|
|
227
|
+
name: "crukx",
|
|
228
|
+
version: "0.1.0"
|
|
229
|
+
});
|
|
230
|
+
registerTools(server);
|
|
231
|
+
var transport = new StdioServerTransport();
|
|
232
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crukx-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Crukx MCP server — reliability control plane for autonomous software engineering",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"crukx": "./dist/bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": ["mcp", "crukx", "reliability", "ai", "llm", "code-review", "swarm"],
|
|
15
|
+
"author": "Crukx",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Shafwansafi06/observability-hub"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsx src/server.ts",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
+
"commander": "^12.1.0",
|
|
30
|
+
"dotenv": "^16.4.5",
|
|
31
|
+
"zod": "^3.23.8"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.14.0",
|
|
35
|
+
"tsup": "^8.1.0",
|
|
36
|
+
"tsx": "^4.15.0",
|
|
37
|
+
"typescript": "^5.4.5"
|
|
38
|
+
}
|
|
39
|
+
}
|