@kairos-sdk/core 0.3.2 → 0.4.5
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 +46 -11
- package/dist/{chunk-KQSNT3HZ.js → chunk-4TS6GW6O.js} +148 -368
- package/dist/chunk-4TS6GW6O.js.map +1 -0
- package/dist/chunk-6CLI43FI.js +315 -0
- package/dist/chunk-6CLI43FI.js.map +1 -0
- package/dist/chunk-6FOFWVMG.js +1 -0
- package/dist/chunk-6FOFWVMG.js.map +1 -0
- package/dist/{chunk-RYGYNOR6.js → chunk-6IXW3WCC.js} +936 -412
- package/dist/chunk-6IXW3WCC.js.map +1 -0
- package/dist/chunk-CR2NHLOH.js +523 -0
- package/dist/chunk-CR2NHLOH.js.map +1 -0
- package/dist/cli.cjs +1402 -170
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +140 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1262 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -537
- package/dist/index.d.ts +5 -537
- package/dist/index.js +8 -4
- package/dist/mcp-server.cjs +1259 -129
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/mcp-server.js +113 -8
- package/dist/mcp-server.js.map +1 -1
- package/dist/reader-CpUcHhKW.d.cts +566 -0
- package/dist/reader-CpUcHhKW.d.ts +566 -0
- package/dist/standalone.cjs +2460 -0
- package/dist/standalone.cjs.map +1 -0
- package/dist/standalone.d.cts +105 -0
- package/dist/standalone.d.ts +105 -0
- package/dist/standalone.js +58 -0
- package/dist/standalone.js.map +1 -0
- package/package.json +6 -1
- package/dist/chunk-KQSNT3HZ.js.map +0 -1
- package/dist/chunk-RYGYNOR6.js.map +0 -1
package/dist/mcp-server.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PromptBuilder,
|
|
4
|
+
inferWorkflowType
|
|
5
|
+
} from "./chunk-CR2NHLOH.js";
|
|
2
6
|
import {
|
|
3
7
|
DEFAULT_REGISTRY,
|
|
4
8
|
FileLibrary,
|
|
@@ -6,10 +10,12 @@ import {
|
|
|
6
10
|
N8nFieldStripper,
|
|
7
11
|
N8nValidator,
|
|
8
12
|
NodeRegistry,
|
|
9
|
-
|
|
13
|
+
PatternAnalyzer,
|
|
14
|
+
TelemetryCollector,
|
|
10
15
|
TelemetryReader,
|
|
16
|
+
generateUUID,
|
|
11
17
|
nullLogger
|
|
12
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-6IXW3WCC.js";
|
|
13
19
|
|
|
14
20
|
// src/mcp-server.ts
|
|
15
21
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -76,6 +82,7 @@ ${regularLines}`;
|
|
|
76
82
|
// src/mcp-server.ts
|
|
77
83
|
import { readFileSync } from "fs";
|
|
78
84
|
import { dirname, join } from "path";
|
|
85
|
+
import { homedir } from "os";
|
|
79
86
|
import { fileURLToPath } from "url";
|
|
80
87
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
81
88
|
var pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
@@ -84,7 +91,28 @@ var validator = new N8nValidator();
|
|
|
84
91
|
var nodeSyncer = new NodeSyncer();
|
|
85
92
|
var lastSync = null;
|
|
86
93
|
var stripper = new N8nFieldStripper();
|
|
87
|
-
var promptBuilder = new PromptBuilder();
|
|
94
|
+
var promptBuilder = new PromptBuilder(getMcpPatternsPath());
|
|
95
|
+
function getMcpTelemetry() {
|
|
96
|
+
const val = process.env["KAIROS_TELEMETRY"];
|
|
97
|
+
if (!val || val === "false") return null;
|
|
98
|
+
return val === "true" ? new TelemetryCollector() : new TelemetryCollector(val);
|
|
99
|
+
}
|
|
100
|
+
function getMcpPatternsPath() {
|
|
101
|
+
const val = process.env["KAIROS_TELEMETRY"];
|
|
102
|
+
if (val && val !== "false" && val !== "true") {
|
|
103
|
+
return join(val, "..", "patterns.json");
|
|
104
|
+
}
|
|
105
|
+
return join(homedir(), ".kairos", "patterns.json");
|
|
106
|
+
}
|
|
107
|
+
var mcpTelemetry = getMcpTelemetry();
|
|
108
|
+
var mcpSessions = /* @__PURE__ */ new Map();
|
|
109
|
+
var SESSION_TTL_MS = 60 * 60 * 1e3;
|
|
110
|
+
function evictStaleSessions() {
|
|
111
|
+
const cutoff = Date.now() - SESSION_TTL_MS;
|
|
112
|
+
for (const [id, session] of mcpSessions) {
|
|
113
|
+
if (session.startTime < cutoff) mcpSessions.delete(id);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
88
116
|
function getTelemetryReader() {
|
|
89
117
|
try {
|
|
90
118
|
return new TelemetryReader();
|
|
@@ -132,6 +160,7 @@ server.tool(
|
|
|
132
160
|
name: z.string().optional().describe("Optional workflow name override")
|
|
133
161
|
},
|
|
134
162
|
async ({ description, name }) => {
|
|
163
|
+
evictStaleSessions();
|
|
135
164
|
const baseUrl = process.env["N8N_BASE_URL"];
|
|
136
165
|
const apiKey = process.env["N8N_API_KEY"];
|
|
137
166
|
if (!baseUrl || !apiKey) {
|
|
@@ -143,6 +172,8 @@ server.tool(
|
|
|
143
172
|
isError: true
|
|
144
173
|
};
|
|
145
174
|
}
|
|
175
|
+
const runId = generateUUID();
|
|
176
|
+
const workflowType = inferWorkflowType(description);
|
|
146
177
|
await library.initialize();
|
|
147
178
|
const syncResult = await autoSync();
|
|
148
179
|
const matches = await library.search(description);
|
|
@@ -150,11 +181,22 @@ server.tool(
|
|
|
150
181
|
const failureRates = await telemetryReader?.getFailureRates() ?? [];
|
|
151
182
|
const request = { description, ...name ? { name } : {} };
|
|
152
183
|
const built = promptBuilder.build(request, matches, failureRates, syncResult?.catalogText);
|
|
184
|
+
if (mcpTelemetry) {
|
|
185
|
+
mcpSessions.set(runId, {
|
|
186
|
+
description,
|
|
187
|
+
startTime: Date.now(),
|
|
188
|
+
validateAttempts: 0,
|
|
189
|
+
warnedRules: promptBuilder.getWarnedRules(),
|
|
190
|
+
workflowType
|
|
191
|
+
});
|
|
192
|
+
await mcpTelemetry.emit("build_start", { description, model: "mcp-decomposed", dryRun: false }, runId);
|
|
193
|
+
}
|
|
153
194
|
const systemText = built.system.map((block) => block.text).join("\n\n---\n\n");
|
|
154
195
|
return {
|
|
155
196
|
content: [{
|
|
156
197
|
type: "text",
|
|
157
198
|
text: JSON.stringify({
|
|
199
|
+
kairos_run_id: runId,
|
|
158
200
|
mode: built.mode,
|
|
159
201
|
matchCount: matches.length,
|
|
160
202
|
topMatchScore: matches[0]?.score ?? null,
|
|
@@ -186,11 +228,12 @@ server.tool(
|
|
|
186
228
|
);
|
|
187
229
|
server.tool(
|
|
188
230
|
"kairos_validate",
|
|
189
|
-
"Validate n8n workflow JSON against
|
|
231
|
+
"Validate n8n workflow JSON against 26 structural rules. Returns pass/fail with specific issues. If validation fails, fix the issues and call this again. Errors block deployment; warnings are advisory.",
|
|
190
232
|
{
|
|
191
|
-
workflow: z.string().describe("The workflow JSON string to validate")
|
|
233
|
+
workflow: z.string().describe("The workflow JSON string to validate"),
|
|
234
|
+
kairos_run_id: z.string().optional().describe("Run ID from kairos_prompt \u2014 enables telemetry correlation")
|
|
192
235
|
},
|
|
193
|
-
async ({ workflow: workflowStr }) => {
|
|
236
|
+
async ({ workflow: workflowStr, kairos_run_id }) => {
|
|
194
237
|
let parsed;
|
|
195
238
|
try {
|
|
196
239
|
parsed = JSON.parse(workflowStr);
|
|
@@ -208,6 +251,24 @@ server.tool(
|
|
|
208
251
|
const result = validator.validate(parsed);
|
|
209
252
|
const errors = result.issues.filter((i) => i.severity === "error");
|
|
210
253
|
const warnings = result.issues.filter((i) => i.severity === "warn");
|
|
254
|
+
if (mcpTelemetry && kairos_run_id) {
|
|
255
|
+
const session = mcpSessions.get(kairos_run_id);
|
|
256
|
+
if (session) {
|
|
257
|
+
session.validateAttempts++;
|
|
258
|
+
await mcpTelemetry.emit("generation_attempt", {
|
|
259
|
+
description: session.description,
|
|
260
|
+
attempt: session.validateAttempts,
|
|
261
|
+
temperature: 0,
|
|
262
|
+
durationMs: 0,
|
|
263
|
+
tokensInput: 0,
|
|
264
|
+
tokensOutput: 0,
|
|
265
|
+
validationPassed: result.valid,
|
|
266
|
+
issueCount: result.issues.length,
|
|
267
|
+
issues: result.issues.map((i) => ({ rule: i.rule, severity: i.severity, message: i.message, nodeId: i.nodeId ?? null })),
|
|
268
|
+
workflowType: session.workflowType
|
|
269
|
+
}, kairos_run_id);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
211
272
|
return {
|
|
212
273
|
content: [{
|
|
213
274
|
type: "text",
|
|
@@ -236,9 +297,10 @@ server.tool(
|
|
|
236
297
|
"Deploy a validated workflow to n8n. Pass the workflow JSON that passed kairos_validate. Strips server-assigned fields automatically. Requires N8N_BASE_URL and N8N_API_KEY.",
|
|
237
298
|
{
|
|
238
299
|
workflow: z.string().describe("The validated workflow JSON string to deploy"),
|
|
239
|
-
activate: z.boolean().default(false).describe("Activate the workflow immediately after deployment")
|
|
300
|
+
activate: z.boolean().default(false).describe("Activate the workflow immediately after deployment"),
|
|
301
|
+
kairos_run_id: z.string().optional().describe("Run ID from kairos_prompt \u2014 enables telemetry correlation")
|
|
240
302
|
},
|
|
241
|
-
async ({ workflow: workflowStr, activate }) => {
|
|
303
|
+
async ({ workflow: workflowStr, activate, kairos_run_id }) => {
|
|
242
304
|
if (!isAllowed("deploy")) {
|
|
243
305
|
return {
|
|
244
306
|
content: [{
|
|
@@ -298,6 +360,28 @@ server.tool(
|
|
|
298
360
|
generationMode: "scratch",
|
|
299
361
|
generationAttempts: 1
|
|
300
362
|
});
|
|
363
|
+
if (mcpTelemetry && kairos_run_id) {
|
|
364
|
+
const session = mcpSessions.get(kairos_run_id);
|
|
365
|
+
if (session) {
|
|
366
|
+
await mcpTelemetry.emit("build_complete", {
|
|
367
|
+
description: session.description,
|
|
368
|
+
success: true,
|
|
369
|
+
totalAttempts: session.validateAttempts,
|
|
370
|
+
totalDurationMs: Date.now() - session.startTime,
|
|
371
|
+
totalTokensInput: 0,
|
|
372
|
+
totalTokensOutput: 0,
|
|
373
|
+
workflowName: response.name,
|
|
374
|
+
workflowId: response.id,
|
|
375
|
+
dryRun: false,
|
|
376
|
+
credentialsNeeded: 0,
|
|
377
|
+
warnedRules: session.warnedRules,
|
|
378
|
+
workflowType: session.workflowType
|
|
379
|
+
}, kairos_run_id);
|
|
380
|
+
mcpSessions.delete(kairos_run_id);
|
|
381
|
+
PatternAnalyzer.fromEnv().analyzeAndSave().catch(() => {
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
301
385
|
return {
|
|
302
386
|
content: [{
|
|
303
387
|
type: "text",
|
|
@@ -380,6 +464,27 @@ server.tool(
|
|
|
380
464
|
};
|
|
381
465
|
}
|
|
382
466
|
);
|
|
467
|
+
server.tool(
|
|
468
|
+
"kairos_patterns",
|
|
469
|
+
"Analyze telemetry data and return failure patterns, build stats, and credential breakdowns. Useful for understanding what goes wrong most often and how to prevent it.",
|
|
470
|
+
{
|
|
471
|
+
days: z.number().default(30).describe("Number of days of telemetry to analyze"),
|
|
472
|
+
limit: z.number().optional().describe("Maximum number of failure patterns to return")
|
|
473
|
+
},
|
|
474
|
+
async ({ days, limit }) => {
|
|
475
|
+
const analyzer = PatternAnalyzer.fromEnv();
|
|
476
|
+
const analysis = await analyzer.analyzeAndSave(days);
|
|
477
|
+
if (limit !== void 0 && limit > 0) {
|
|
478
|
+
analysis.topFailureRules = analysis.topFailureRules.slice(0, limit);
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
content: [{
|
|
482
|
+
type: "text",
|
|
483
|
+
text: JSON.stringify(analysis, null, 2)
|
|
484
|
+
}]
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
);
|
|
383
488
|
server.tool(
|
|
384
489
|
"kairos_list",
|
|
385
490
|
"List all workflows deployed on the connected n8n instance.",
|
package/dist/mcp-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-server.ts","../src/validation/node-syncer.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Kairos MCP Server — decomposed architecture.\n *\n * The host LLM (Claude, GPT, Gemini, whatever) generates the workflow.\n * Kairos provides the knowledge (system prompt, library, failure patterns)\n * and guardrails (validator, deployer). Zero Anthropic API key needed.\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\nimport { FileLibrary } from './library/file-library.js'\nimport { N8nValidator } from './validation/validator.js'\nimport { N8nFieldStripper } from './providers/n8n/stripper.js'\nimport { N8nApiClient } from './providers/n8n/api-client.js'\nimport { PromptBuilder } from './generation/prompt-builder.js'\nimport { TelemetryReader } from './telemetry/reader.js'\nimport { NodeSyncer, type SyncResult } from './validation/node-syncer.js'\nimport { nullLogger } from './utils/logger.js'\nimport type { N8nWorkflow } from './types/workflow.js'\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')) as { version: string }\n\nconst library = new FileLibrary()\nlet validator = new N8nValidator()\nconst nodeSyncer = new NodeSyncer()\nlet lastSync: SyncResult | null = null\nconst stripper = new N8nFieldStripper()\nconst promptBuilder = new PromptBuilder()\n\nfunction getTelemetryReader(): TelemetryReader | null {\n try {\n return new TelemetryReader()\n } catch {\n return null\n }\n}\n\nfunction isAllowed(action: 'deploy' | 'activate' | 'delete'): boolean {\n const key = `KAIROS_MCP_ALLOW_${action.toUpperCase()}`\n return process.env[key] === 'true'\n}\n\nfunction getApiClient(): N8nApiClient {\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n throw new Error('N8N_BASE_URL and N8N_API_KEY environment variables are required for n8n operations')\n }\n return new N8nApiClient(baseUrl, apiKey, nullLogger)\n}\n\nasync function autoSync(): Promise<SyncResult | null> {\n if (lastSync) return lastSync\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) return null\n try {\n const client = new N8nApiClient(baseUrl, apiKey, nullLogger)\n const nodeTypes = await client.getNodeTypes()\n if (nodeTypes.length === 0) return null\n lastSync = nodeSyncer.sync(nodeTypes)\n validator = new N8nValidator(lastSync.registry)\n return lastSync\n } catch {\n return null\n }\n}\n\nconst server = new McpServer({\n name: 'kairos',\n version: pkg.version,\n})\n\n// ── Core generation tools (no API key needed) ──────────────────────────────\n\nserver.tool(\n 'kairos_prompt',\n 'Get the specialized n8n workflow generation context. Returns a system prompt with node catalog, connection rules, validation rules, plus library matches and failure patterns for the given description. Feed this to yourself as context, then generate the workflow JSON.',\n {\n description: z.string().describe('Plain-English description of the workflow to build'),\n name: z.string().optional().describe('Optional workflow name override'),\n },\n async ({ description, name }) => {\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'N8N_BASE_URL and N8N_API_KEY are required. Kairos needs to sync your n8n instance\\'s node types to generate accurate workflows.' }),\n }],\n isError: true,\n }\n }\n\n await library.initialize()\n const syncResult = await autoSync()\n const matches = await library.search(description)\n const telemetryReader = getTelemetryReader()\n const failureRates = await telemetryReader?.getFailureRates() ?? []\n\n const request = { description, ...(name ? { name } : {}) }\n const built = promptBuilder.build(request, matches, failureRates, syncResult?.catalogText)\n\n const systemText = built.system.map(block => block.text).join('\\n\\n---\\n\\n')\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n mode: built.mode,\n matchCount: matches.length,\n topMatchScore: matches[0]?.score ?? null,\n nodeCatalog: syncResult ? 'synced' : 'static',\n nodeCount: syncResult?.nodeCount ?? null,\n ...(syncResult ? {} : { syncWarning: 'Could not sync node types from your n8n instance. Using static fallback catalog — generated workflows may not match your exact n8n setup.' }),\n systemPrompt: systemText,\n userMessage: built.userMessage,\n outputFormat: {\n description: 'Generate a JSON object with this exact structure. The workflow field contains the n8n workflow. credentialsNeeded lists services requiring credentials.',\n schema: {\n workflow: {\n name: 'string — descriptive workflow name',\n nodes: 'array — n8n node objects with id (UUID v4), type, typeVersion, name, position, parameters',\n connections: 'object — keyed by source node NAME, maps to target nodes',\n settings: 'object — include executionOrder: \"v1\"',\n },\n credentialsNeeded: [{\n service: 'string — e.g. \"Slack\"',\n credentialType: 'string — e.g. \"slackOAuth2Api\"',\n description: 'string — what the user needs to set up',\n }],\n },\n },\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_validate',\n 'Validate n8n workflow JSON against 23 structural rules. Returns pass/fail with specific issues. If validation fails, fix the issues and call this again. Errors block deployment; warnings are advisory.',\n {\n workflow: z.string().describe('The workflow JSON string to validate'),\n },\n async ({ workflow: workflowStr }) => {\n let parsed: N8nWorkflow\n try {\n parsed = JSON.parse(workflowStr) as N8nWorkflow\n } catch (e) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n valid: false,\n error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`,\n }, null, 2),\n }],\n }\n }\n\n const result = validator.validate(parsed)\n const errors = result.issues.filter(i => i.severity === 'error')\n const warnings = result.issues.filter(i => i.severity === 'warn')\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n valid: result.valid,\n errorCount: errors.length,\n warningCount: warnings.length,\n errors: errors.map(i => ({\n rule: i.rule,\n message: i.message,\n nodeId: i.nodeId ?? null,\n })),\n warnings: warnings.map(i => ({\n rule: i.rule,\n message: i.message,\n nodeId: i.nodeId ?? null,\n })),\n deployable: errors.length === 0,\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_deploy',\n 'Deploy a validated workflow to n8n. Pass the workflow JSON that passed kairos_validate. Strips server-assigned fields automatically. Requires N8N_BASE_URL and N8N_API_KEY.',\n {\n workflow: z.string().describe('The validated workflow JSON string to deploy'),\n activate: z.boolean().default(false).describe('Activate the workflow immediately after deployment'),\n },\n async ({ workflow: workflowStr, activate }) => {\n if (!isAllowed('deploy')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Deploy is disabled. Set KAIROS_MCP_ALLOW_DEPLOY=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n let parsed: N8nWorkflow\n try {\n parsed = JSON.parse(workflowStr) as N8nWorkflow\n } catch (e) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` }),\n }],\n }\n }\n\n const validation = validator.validate(parsed)\n const errors = validation.issues.filter(i => i.severity === 'error')\n if (errors.length > 0) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n error: 'Workflow has validation errors — fix them before deploying',\n errors: errors.map(i => ({ rule: i.rule, message: i.message })),\n }, null, 2),\n }],\n }\n }\n\n const client = getApiClient()\n const stripped = stripper.stripForCreate(parsed)\n const response = await client.createWorkflow(stripped)\n\n if (activate) {\n if (!isAllowed('activate')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n workflowId: response.id,\n name: response.name,\n activated: false,\n warning: 'Workflow deployed but activation is disabled. Set KAIROS_MCP_ALLOW_ACTIVATE=true to enable.',\n url: `${process.env['N8N_BASE_URL']}/workflow/${response.id}`,\n }, null, 2),\n }],\n }\n }\n await client.activateWorkflow(response.id)\n }\n\n // Save to library for future retrieval\n await library.initialize()\n await library.save(parsed, {\n description: parsed.name,\n generationMode: 'scratch',\n generationAttempts: 1,\n })\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n workflowId: response.id,\n name: response.name,\n activated: activate,\n url: `${process.env['N8N_BASE_URL']}/workflow/${response.id}`,\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_search',\n 'Search the local workflow library for similar past builds. Returns matching workflows with scores, useful for finding examples and reusing patterns.',\n {\n query: z.string().describe('Search query — a workflow description or keywords'),\n limit: z.number().default(5).describe('Maximum number of results'),\n },\n async ({ query, limit }) => {\n await library.initialize()\n const matches = await library.search(query)\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(\n matches.slice(0, limit).map(m => ({\n score: Number(m.score.toFixed(3)),\n mode: m.mode,\n description: m.workflow.description,\n nodeCount: m.workflow.workflow.nodes.length,\n nodes: m.workflow.workflow.nodes.map(n => n.name),\n failurePatterns: m.workflow.failurePatterns ?? [],\n })),\n null,\n 2,\n ),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_sync',\n 'Sync the node catalog from your live n8n instance. Fetches all installed node types and versions so Kairos knows exactly what your n8n supports. Automatically called by kairos_prompt when n8n credentials are set, but you can call this manually to force a refresh.',\n {},\n async () => {\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'N8N_BASE_URL and N8N_API_KEY are required for sync.' }),\n }],\n isError: true,\n }\n }\n\n lastSync = null\n const result = await autoSync()\n if (!result) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Failed to fetch node types from n8n. Check your credentials and that your instance is running.' }),\n }],\n isError: true,\n }\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n synced: true,\n nodeCount: result.nodeCount,\n newNodes: result.newNodes,\n message: `Synced ${result.nodeCount} node types from your n8n instance (${result.newNodes} not in default catalog).`,\n }, null, 2),\n }],\n }\n },\n)\n\n// ── n8n management tools (need N8N_BASE_URL + N8N_API_KEY) ─────────────────\n\nserver.tool(\n 'kairos_list',\n 'List all workflows deployed on the connected n8n instance.',\n {},\n async () => {\n const client = getApiClient()\n const workflows = await client.listWorkflows()\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(workflows, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_get',\n 'Get the full JSON definition of a specific workflow by ID.',\n {\n workflow_id: z.string().describe('The n8n workflow ID'),\n },\n async ({ workflow_id }) => {\n const client = getApiClient()\n const workflow = await client.getWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(workflow, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_activate',\n 'Activate a deployed workflow so it starts running on triggers.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to activate'),\n },\n async ({ workflow_id }) => {\n if (!isAllowed('activate')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Activate is disabled. Set KAIROS_MCP_ALLOW_ACTIVATE=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n const client = getApiClient()\n await client.activateWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Activated workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_deactivate',\n 'Deactivate a running workflow.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to deactivate'),\n },\n async ({ workflow_id }) => {\n const client = getApiClient()\n await client.deactivateWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Deactivated workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_delete',\n 'Delete a workflow from n8n. This is irreversible.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to delete'),\n },\n async ({ workflow_id }) => {\n if (!isAllowed('delete')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Delete is disabled. Set KAIROS_MCP_ALLOW_DELETE=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n const client = getApiClient()\n await client.deleteWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Deleted workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_executions',\n 'List recent executions for a workflow, showing status and timing.',\n {\n workflow_id: z.string().optional().describe('Filter to a specific workflow ID (omit for all)'),\n limit: z.number().default(20).describe('Maximum number of executions to return'),\n },\n async ({ workflow_id, limit }) => {\n const client = getApiClient()\n const executions = await client.getExecutions(workflow_id, { limit })\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(executions, null, 2),\n }],\n }\n },\n)\n\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch((err: unknown) => {\n console.error('Kairos MCP server failed to start:', err)\n process.exit(1)\n})\n","import type { N8nNodeTypeInfo } from '../providers/n8n/types.js'\nimport type { NodeDefinition } from './registry.js'\nimport { NodeRegistry, DEFAULT_REGISTRY } from './registry.js'\n\nconst TRIGGER_PATTERNS = [/trigger/i, /Trigger$/]\n\nexport interface SyncResult {\n registry: NodeRegistry\n catalogText: string\n nodeCount: number\n newNodes: number\n}\n\nexport class NodeSyncer {\n private readonly baseRegistry: Map<string, NodeDefinition>\n\n constructor() {\n this.baseRegistry = new Map(DEFAULT_REGISTRY.map(d => [d.type, d]))\n }\n\n sync(liveNodes: N8nNodeTypeInfo[]): SyncResult {\n const merged = new Map(this.baseRegistry)\n let newNodes = 0\n\n for (const node of liveNodes) {\n const versions = Array.isArray(node.version) ? node.version : [node.version]\n const isTrigger = TRIGGER_PATTERNS.some(p => p.test(node.name))\n const credentialType = node.credentials?.[0]?.name\n\n const existing = merged.get(node.name)\n if (existing) {\n const allVersions = new Set([...existing.safeTypeVersions, ...versions])\n merged.set(node.name, {\n ...existing,\n safeTypeVersions: [...allVersions].sort((a, b) => a - b),\n })\n } else {\n newNodes++\n merged.set(node.name, {\n type: node.name,\n safeTypeVersions: versions.sort((a, b) => a - b),\n requiredParams: [],\n ...(credentialType ? { credentialType } : {}),\n ...(isTrigger ? { isTrigger: true } : {}),\n })\n }\n }\n\n const definitions = [...merged.values()]\n const registry = new NodeRegistry(definitions)\n const catalogText = this.buildCatalog(definitions)\n\n return { registry, catalogText, nodeCount: definitions.length, newNodes }\n }\n\n private buildCatalog(definitions: NodeDefinition[]): string {\n const triggers = definitions.filter(d => d.isTrigger)\n const regular = definitions.filter(d => !d.isTrigger)\n\n const formatEntry = (d: NodeDefinition): string => {\n const versions = d.safeTypeVersions.join(', ')\n const cred = d.credentialType ? ` — cred: ${d.credentialType}` : ''\n return `${d.type} typeVersion: ${versions}${cred}`\n }\n\n const triggerLines = triggers.map(formatEntry).join('\\n')\n const regularLines = regular.map(formatEntry).join('\\n')\n\n return `## NODE CATALOG — synced from your n8n instance (${definitions.length} node types)\n\n### Triggers:\n${triggerLines}\n\n### Regular nodes:\n${regularLines}`\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAUA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;;;ACRlB,IAAM,mBAAmB,CAAC,YAAY,UAAU;AASzC,IAAM,aAAN,MAAiB;AAAA,EACL;AAAA,EAEjB,cAAc;AACZ,SAAK,eAAe,IAAI,IAAI,iBAAiB,IAAI,OAAK,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAAA,EACpE;AAAA,EAEA,KAAK,WAA0C;AAC7C,UAAM,SAAS,IAAI,IAAI,KAAK,YAAY;AACxC,QAAI,WAAW;AAEf,eAAW,QAAQ,WAAW;AAC5B,YAAM,WAAW,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAU,CAAC,KAAK,OAAO;AAC3E,YAAM,YAAY,iBAAiB,KAAK,OAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAC9D,YAAM,iBAAiB,KAAK,cAAc,CAAC,GAAG;AAE9C,YAAM,WAAW,OAAO,IAAI,KAAK,IAAI;AACrC,UAAI,UAAU;AACZ,cAAM,cAAc,oBAAI,IAAI,CAAC,GAAG,SAAS,kBAAkB,GAAG,QAAQ,CAAC;AACvE,eAAO,IAAI,KAAK,MAAM;AAAA,UACpB,GAAG;AAAA,UACH,kBAAkB,CAAC,GAAG,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,QACzD,CAAC;AAAA,MACH,OAAO;AACL;AACA,eAAO,IAAI,KAAK,MAAM;AAAA,UACpB,MAAM,KAAK;AAAA,UACX,kBAAkB,SAAS,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,UAC/C,gBAAgB,CAAC;AAAA,UACjB,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,UAC3C,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,QACzC,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,cAAc,CAAC,GAAG,OAAO,OAAO,CAAC;AACvC,UAAM,WAAW,IAAI,aAAa,WAAW;AAC7C,UAAM,cAAc,KAAK,aAAa,WAAW;AAEjD,WAAO,EAAE,UAAU,aAAa,WAAW,YAAY,QAAQ,SAAS;AAAA,EAC1E;AAAA,EAEQ,aAAa,aAAuC;AAC1D,UAAM,WAAW,YAAY,OAAO,OAAK,EAAE,SAAS;AACpD,UAAM,UAAU,YAAY,OAAO,OAAK,CAAC,EAAE,SAAS;AAEpD,UAAM,cAAc,CAAC,MAA8B;AACjD,YAAM,WAAW,EAAE,iBAAiB,KAAK,IAAI;AAC7C,YAAM,OAAO,EAAE,iBAAiB,iBAAY,EAAE,cAAc,KAAK;AACjE,aAAO,GAAG,EAAE,IAAI,kBAAkB,QAAQ,GAAG,IAAI;AAAA,IACnD;AAEA,UAAM,eAAe,SAAS,IAAI,WAAW,EAAE,KAAK,IAAI;AACxD,UAAM,eAAe,QAAQ,IAAI,WAAW,EAAE,KAAK,IAAI;AAEvD,WAAO,yDAAoD,YAAY,MAAM;AAAA;AAAA;AAAA,EAG/E,YAAY;AAAA;AAAA;AAAA,EAGZ,YAAY;AAAA,EACZ;AACF;;;ADtDA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAE9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAM,MAAM,KAAK,MAAM,aAAa,KAAK,WAAW,MAAM,cAAc,GAAG,OAAO,CAAC;AAEnF,IAAM,UAAU,IAAI,YAAY;AAChC,IAAI,YAAY,IAAI,aAAa;AACjC,IAAM,aAAa,IAAI,WAAW;AAClC,IAAI,WAA8B;AAClC,IAAM,WAAW,IAAI,iBAAiB;AACtC,IAAM,gBAAgB,IAAI,cAAc;AAExC,SAAS,qBAA6C;AACpD,MAAI;AACF,WAAO,IAAI,gBAAgB;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,QAAmD;AACpE,QAAM,MAAM,oBAAoB,OAAO,YAAY,CAAC;AACpD,SAAO,QAAQ,IAAI,GAAG,MAAM;AAC9B;AAEA,SAAS,eAA6B;AACpC,QAAM,UAAU,QAAQ,IAAI,cAAc;AAC1C,QAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,MAAI,CAAC,WAAW,CAAC,QAAQ;AACvB,UAAM,IAAI,MAAM,oFAAoF;AAAA,EACtG;AACA,SAAO,IAAI,aAAa,SAAS,QAAQ,UAAU;AACrD;AAEA,eAAe,WAAuC;AACpD,MAAI,SAAU,QAAO;AACrB,QAAM,UAAU,QAAQ,IAAI,cAAc;AAC1C,QAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,MAAI,CAAC,WAAW,CAAC,OAAQ,QAAO;AAChC,MAAI;AACF,UAAM,SAAS,IAAI,aAAa,SAAS,QAAQ,UAAU;AAC3D,UAAM,YAAY,MAAM,OAAO,aAAa;AAC5C,QAAI,UAAU,WAAW,EAAG,QAAO;AACnC,eAAW,WAAW,KAAK,SAAS;AACpC,gBAAY,IAAI,aAAa,SAAS,QAAQ;AAC9C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS,IAAI;AACf,CAAC;AAID,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,oDAAoD;AAAA,IACrF,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACxE;AAAA,EACA,OAAO,EAAE,aAAa,KAAK,MAAM;AAC/B,UAAM,UAAU,QAAQ,IAAI,cAAc;AAC1C,UAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,QAAI,CAAC,WAAW,CAAC,QAAQ;AACvB,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,iIAAkI,CAAC;AAAA,QACnK,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,QAAQ,WAAW;AACzB,UAAM,aAAa,MAAM,SAAS;AAClC,UAAM,UAAU,MAAM,QAAQ,OAAO,WAAW;AAChD,UAAM,kBAAkB,mBAAmB;AAC3C,UAAM,eAAe,MAAM,iBAAiB,gBAAgB,KAAK,CAAC;AAElE,UAAM,UAAU,EAAE,aAAa,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC,EAAG;AACzD,UAAM,QAAQ,cAAc,MAAM,SAAS,SAAS,cAAc,YAAY,WAAW;AAEzF,UAAM,aAAa,MAAM,OAAO,IAAI,WAAS,MAAM,IAAI,EAAE,KAAK,aAAa;AAE3E,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM,MAAM;AAAA,UACZ,YAAY,QAAQ;AAAA,UACpB,eAAe,QAAQ,CAAC,GAAG,SAAS;AAAA,UACpC,aAAa,aAAa,WAAW;AAAA,UACrC,WAAW,YAAY,aAAa;AAAA,UACpC,GAAI,aAAa,CAAC,IAAI,EAAE,aAAa,iJAA4I;AAAA,UACjL,cAAc;AAAA,UACd,aAAa,MAAM;AAAA,UACnB,cAAc;AAAA,YACZ,aAAa;AAAA,YACb,QAAQ;AAAA,cACN,UAAU;AAAA,gBACR,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,aAAa;AAAA,gBACb,UAAU;AAAA,cACZ;AAAA,cACA,mBAAmB,CAAC;AAAA,gBAClB,SAAS;AAAA,gBACT,gBAAgB;AAAA,gBAChB,aAAa;AAAA,cACf,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,GAAG,MAAM,CAAC;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,UAAU,EAAE,OAAO,EAAE,SAAS,sCAAsC;AAAA,EACtE;AAAA,EACA,OAAO,EAAE,UAAU,YAAY,MAAM;AACnC,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC,SAAS,GAAG;AACV,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB,OAAO;AAAA,YACP,OAAO,iBAAiB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,UACpE,GAAG,MAAM,CAAC;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,SAAS,UAAU,SAAS,MAAM;AACxC,UAAM,SAAS,OAAO,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO;AAC/D,UAAM,WAAW,OAAO,OAAO,OAAO,OAAK,EAAE,aAAa,MAAM;AAEhE,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO,OAAO;AAAA,UACd,YAAY,OAAO;AAAA,UACnB,cAAc,SAAS;AAAA,UACvB,QAAQ,OAAO,IAAI,QAAM;AAAA,YACvB,MAAM,EAAE;AAAA,YACR,SAAS,EAAE;AAAA,YACX,QAAQ,EAAE,UAAU;AAAA,UACtB,EAAE;AAAA,UACF,UAAU,SAAS,IAAI,QAAM;AAAA,YAC3B,MAAM,EAAE;AAAA,YACR,SAAS,EAAE;AAAA,YACX,QAAQ,EAAE,UAAU;AAAA,UACtB,EAAE;AAAA,UACF,YAAY,OAAO,WAAW;AAAA,QAChC,GAAG,MAAM,CAAC;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,UAAU,EAAE,OAAO,EAAE,SAAS,8CAA8C;AAAA,IAC5E,UAAU,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,oDAAoD;AAAA,EACpG;AAAA,EACA,OAAO,EAAE,UAAU,aAAa,SAAS,MAAM;AAC7C,QAAI,CAAC,UAAU,QAAQ,GAAG;AACxB,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,kEAAkE,CAAC;AAAA,QACnG,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,WAAW;AAAA,IACjC,SAAS,GAAG;AACV,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,iBAAiB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,GAAG,CAAC;AAAA,QAC/F,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,aAAa,UAAU,SAAS,MAAM;AAC5C,UAAM,SAAS,WAAW,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO;AACnE,QAAI,OAAO,SAAS,GAAG;AACrB,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB,OAAO;AAAA,YACP,QAAQ,OAAO,IAAI,QAAM,EAAE,MAAM,EAAE,MAAM,SAAS,EAAE,QAAQ,EAAE;AAAA,UAChE,GAAG,MAAM,CAAC;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,SAAS,aAAa;AAC5B,UAAM,WAAW,SAAS,eAAe,MAAM;AAC/C,UAAM,WAAW,MAAM,OAAO,eAAe,QAAQ;AAErD,QAAI,UAAU;AACZ,UAAI,CAAC,UAAU,UAAU,GAAG;AAC1B,eAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,YAAY,SAAS;AAAA,cACrB,MAAM,SAAS;AAAA,cACf,WAAW;AAAA,cACX,SAAS;AAAA,cACT,KAAK,GAAG,QAAQ,IAAI,cAAc,CAAC,aAAa,SAAS,EAAE;AAAA,YAC7D,GAAG,MAAM,CAAC;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,OAAO,iBAAiB,SAAS,EAAE;AAAA,IAC3C;AAGA,UAAM,QAAQ,WAAW;AACzB,UAAM,QAAQ,KAAK,QAAQ;AAAA,MACzB,aAAa,OAAO;AAAA,MACpB,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,IACtB,CAAC;AAED,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU;AAAA,UACnB,YAAY,SAAS;AAAA,UACrB,MAAM,SAAS;AAAA,UACf,WAAW;AAAA,UACX,KAAK,GAAG,QAAQ,IAAI,cAAc,CAAC,aAAa,SAAS,EAAE;AAAA,QAC7D,GAAG,MAAM,CAAC;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,OAAO,EAAE,OAAO,EAAE,SAAS,wDAAmD;AAAA,IAC9E,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,2BAA2B;AAAA,EACnE;AAAA,EACA,OAAO,EAAE,OAAO,MAAM,MAAM;AAC1B,UAAM,QAAQ,WAAW;AACzB,UAAM,UAAU,MAAM,QAAQ,OAAO,KAAK;AAE1C,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,UACT,QAAQ,MAAM,GAAG,KAAK,EAAE,IAAI,QAAM;AAAA,YAChC,OAAO,OAAO,EAAE,MAAM,QAAQ,CAAC,CAAC;AAAA,YAChC,MAAM,EAAE;AAAA,YACR,aAAa,EAAE,SAAS;AAAA,YACxB,WAAW,EAAE,SAAS,SAAS,MAAM;AAAA,YACrC,OAAO,EAAE,SAAS,SAAS,MAAM,IAAI,OAAK,EAAE,IAAI;AAAA,YAChD,iBAAiB,EAAE,SAAS,mBAAmB,CAAC;AAAA,UAClD,EAAE;AAAA,UACF;AAAA,UACA;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA,CAAC;AAAA,EACD,YAAY;AACV,UAAM,UAAU,QAAQ,IAAI,cAAc;AAC1C,UAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,QAAI,CAAC,WAAW,CAAC,QAAQ;AACvB,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,sDAAsD,CAAC;AAAA,QACvF,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,eAAW;AACX,UAAM,SAAS,MAAM,SAAS;AAC9B,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,iGAAiG,CAAC;AAAA,QAClI,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU;AAAA,UACnB,QAAQ;AAAA,UACR,WAAW,OAAO;AAAA,UAClB,UAAU,OAAO;AAAA,UACjB,SAAS,UAAU,OAAO,SAAS,uCAAuC,OAAO,QAAQ;AAAA,QAC3F,GAAG,MAAM,CAAC;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA,CAAC;AAAA,EACD,YAAY;AACV,UAAM,SAAS,aAAa;AAC5B,UAAM,YAAY,MAAM,OAAO,cAAc;AAE7C,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU,WAAW,MAAM,CAAC;AAAA,MACzC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,qBAAqB;AAAA,EACxD;AAAA,EACA,OAAO,EAAE,YAAY,MAAM;AACzB,UAAM,SAAS,aAAa;AAC5B,UAAM,WAAW,MAAM,OAAO,YAAY,WAAW;AAErD,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,iCAAiC;AAAA,EACpE;AAAA,EACA,OAAO,EAAE,YAAY,MAAM;AACzB,QAAI,CAAC,UAAU,UAAU,GAAG;AAC1B,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,sEAAsE,CAAC;AAAA,QACvG,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,SAAS,aAAa;AAC5B,UAAM,OAAO,iBAAiB,WAAW;AAEzC,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,sBAAsB,WAAW;AAAA,MACzC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,mCAAmC;AAAA,EACtE;AAAA,EACA,OAAO,EAAE,YAAY,MAAM;AACzB,UAAM,SAAS,aAAa;AAC5B,UAAM,OAAO,mBAAmB,WAAW;AAE3C,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,wBAAwB,WAAW;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,+BAA+B;AAAA,EAClE;AAAA,EACA,OAAO,EAAE,YAAY,MAAM;AACzB,QAAI,CAAC,UAAU,QAAQ,GAAG;AACxB,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,EAAE,OAAO,kEAAkE,CAAC;AAAA,QACnG,CAAC;AAAA,QACD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,SAAS,aAAa;AAC5B,UAAM,OAAO,eAAe,WAAW;AAEvC,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,oBAAoB,WAAW;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,iDAAiD;AAAA,IAC7F,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,wCAAwC;AAAA,EACjF;AAAA,EACA,OAAO,EAAE,aAAa,MAAM,MAAM;AAChC,UAAM,SAAS,aAAa;AAC5B,UAAM,aAAa,MAAM,OAAO,cAAc,aAAa,EAAE,MAAM,CAAC;AAEpE,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,KAAK,UAAU,YAAY,MAAM,CAAC;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,OAAO;AACpB,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAChC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAiB;AAC7B,UAAQ,MAAM,sCAAsC,GAAG;AACvD,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp-server.ts","../src/validation/node-syncer.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Kairos MCP Server — decomposed architecture.\n *\n * The host LLM (Claude, GPT, Gemini, whatever) generates the workflow.\n * Kairos provides the knowledge (system prompt, library, failure patterns)\n * and guardrails (validator, deployer). Zero Anthropic API key needed.\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\nimport { FileLibrary } from './library/file-library.js'\nimport { N8nValidator } from './validation/validator.js'\nimport { N8nFieldStripper } from './providers/n8n/stripper.js'\nimport { N8nApiClient } from './providers/n8n/api-client.js'\nimport { PromptBuilder } from './generation/prompt-builder.js'\nimport { TelemetryReader } from './telemetry/reader.js'\nimport { PatternAnalyzer } from './telemetry/pattern-analyzer.js'\nimport { NodeSyncer, type SyncResult } from './validation/node-syncer.js'\nimport { TelemetryCollector } from './telemetry/collector.js'\nimport { nullLogger } from './utils/logger.js'\nimport { generateUUID } from './utils/uuid.js'\nimport { inferWorkflowType } from './utils/workflow-type.js'\nimport type { N8nWorkflow } from './types/workflow.js'\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { homedir } from 'node:os'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')) as { version: string }\n\nconst library = new FileLibrary()\nlet validator = new N8nValidator()\nconst nodeSyncer = new NodeSyncer()\nlet lastSync: SyncResult | null = null\nconst stripper = new N8nFieldStripper()\nconst promptBuilder = new PromptBuilder(getMcpPatternsPath())\n\nfunction getMcpTelemetry(): TelemetryCollector | null {\n const val = process.env['KAIROS_TELEMETRY']\n if (!val || val === 'false') return null\n return val === 'true' ? new TelemetryCollector() : new TelemetryCollector(val)\n}\n\n/**\n * Derive the patterns.json path from KAIROS_TELEMETRY so the MCP server's\n * PromptBuilder reads from the same location that PatternAnalyzer.fromEnv() writes to.\n */\nfunction getMcpPatternsPath(): string {\n const val = process.env['KAIROS_TELEMETRY']\n if (val && val !== 'false' && val !== 'true') {\n return join(val, '..', 'patterns.json')\n }\n return join(homedir(), '.kairos', 'patterns.json')\n}\n\nconst mcpTelemetry = getMcpTelemetry()\n\ninterface McpBuildSession {\n description: string\n startTime: number\n validateAttempts: number\n warnedRules: number[]\n workflowType: string | null\n}\nconst mcpSessions = new Map<string, McpBuildSession>()\nconst SESSION_TTL_MS = 60 * 60 * 1000 // 1 hour: abandon sessions not completed by deploy\n\nfunction evictStaleSessions(): void {\n const cutoff = Date.now() - SESSION_TTL_MS\n for (const [id, session] of mcpSessions) {\n if (session.startTime < cutoff) mcpSessions.delete(id)\n }\n}\n\nfunction getTelemetryReader(): TelemetryReader | null {\n try {\n return new TelemetryReader()\n } catch {\n return null\n }\n}\n\nfunction isAllowed(action: 'deploy' | 'activate' | 'delete'): boolean {\n const key = `KAIROS_MCP_ALLOW_${action.toUpperCase()}`\n return process.env[key] === 'true'\n}\n\nfunction getApiClient(): N8nApiClient {\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n throw new Error('N8N_BASE_URL and N8N_API_KEY environment variables are required for n8n operations')\n }\n return new N8nApiClient(baseUrl, apiKey, nullLogger)\n}\n\nasync function autoSync(): Promise<SyncResult | null> {\n if (lastSync) return lastSync\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) return null\n try {\n const client = new N8nApiClient(baseUrl, apiKey, nullLogger)\n const nodeTypes = await client.getNodeTypes()\n if (nodeTypes.length === 0) return null\n lastSync = nodeSyncer.sync(nodeTypes)\n validator = new N8nValidator(lastSync.registry)\n return lastSync\n } catch {\n return null\n }\n}\n\nconst server = new McpServer({\n name: 'kairos',\n version: pkg.version,\n})\n\n// ── Core generation tools (no API key needed) ──────────────────────────────\n\nserver.tool(\n 'kairos_prompt',\n 'Get the specialized n8n workflow generation context. Returns a system prompt with node catalog, connection rules, validation rules, plus library matches and failure patterns for the given description. Feed this to yourself as context, then generate the workflow JSON.',\n {\n description: z.string().describe('Plain-English description of the workflow to build'),\n name: z.string().optional().describe('Optional workflow name override'),\n },\n async ({ description, name }) => {\n evictStaleSessions()\n\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'N8N_BASE_URL and N8N_API_KEY are required. Kairos needs to sync your n8n instance\\'s node types to generate accurate workflows.' }),\n }],\n isError: true,\n }\n }\n\n const runId = generateUUID()\n const workflowType = inferWorkflowType(description)\n\n await library.initialize()\n const syncResult = await autoSync()\n const matches = await library.search(description)\n const telemetryReader = getTelemetryReader()\n const failureRates = await telemetryReader?.getFailureRates() ?? []\n\n const request = { description, ...(name ? { name } : {}) }\n const built = promptBuilder.build(request, matches, failureRates, syncResult?.catalogText)\n\n if (mcpTelemetry) {\n mcpSessions.set(runId, {\n description,\n startTime: Date.now(),\n validateAttempts: 0,\n warnedRules: promptBuilder.getWarnedRules(),\n workflowType,\n })\n await mcpTelemetry.emit('build_start', { description, model: 'mcp-decomposed', dryRun: false }, runId)\n }\n\n const systemText = built.system.map(block => block.text).join('\\n\\n---\\n\\n')\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n kairos_run_id: runId,\n mode: built.mode,\n matchCount: matches.length,\n topMatchScore: matches[0]?.score ?? null,\n nodeCatalog: syncResult ? 'synced' : 'static',\n nodeCount: syncResult?.nodeCount ?? null,\n ...(syncResult ? {} : { syncWarning: 'Could not sync node types from your n8n instance. Using static fallback catalog — generated workflows may not match your exact n8n setup.' }),\n systemPrompt: systemText,\n userMessage: built.userMessage,\n outputFormat: {\n description: 'Generate a JSON object with this exact structure. The workflow field contains the n8n workflow. credentialsNeeded lists services requiring credentials.',\n schema: {\n workflow: {\n name: 'string — descriptive workflow name',\n nodes: 'array — n8n node objects with id (UUID v4), type, typeVersion, name, position, parameters',\n connections: 'object — keyed by source node NAME, maps to target nodes',\n settings: 'object — include executionOrder: \"v1\"',\n },\n credentialsNeeded: [{\n service: 'string — e.g. \"Slack\"',\n credentialType: 'string — e.g. \"slackOAuth2Api\"',\n description: 'string — what the user needs to set up',\n }],\n },\n },\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_validate',\n 'Validate n8n workflow JSON against 26 structural rules. Returns pass/fail with specific issues. If validation fails, fix the issues and call this again. Errors block deployment; warnings are advisory.',\n {\n workflow: z.string().describe('The workflow JSON string to validate'),\n kairos_run_id: z.string().optional().describe('Run ID from kairos_prompt — enables telemetry correlation'),\n },\n async ({ workflow: workflowStr, kairos_run_id }) => {\n let parsed: N8nWorkflow\n try {\n parsed = JSON.parse(workflowStr) as N8nWorkflow\n } catch (e) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n valid: false,\n error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`,\n }, null, 2),\n }],\n }\n }\n\n const result = validator.validate(parsed)\n const errors = result.issues.filter(i => i.severity === 'error')\n const warnings = result.issues.filter(i => i.severity === 'warn')\n\n if (mcpTelemetry && kairos_run_id) {\n const session = mcpSessions.get(kairos_run_id)\n if (session) {\n session.validateAttempts++\n await mcpTelemetry.emit('generation_attempt', {\n description: session.description,\n attempt: session.validateAttempts,\n temperature: 0,\n durationMs: 0,\n tokensInput: 0,\n tokensOutput: 0,\n validationPassed: result.valid,\n issueCount: result.issues.length,\n issues: result.issues.map(i => ({ rule: i.rule, severity: i.severity, message: i.message, nodeId: i.nodeId ?? null })),\n workflowType: session.workflowType,\n }, kairos_run_id)\n }\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n valid: result.valid,\n errorCount: errors.length,\n warningCount: warnings.length,\n errors: errors.map(i => ({\n rule: i.rule,\n message: i.message,\n nodeId: i.nodeId ?? null,\n })),\n warnings: warnings.map(i => ({\n rule: i.rule,\n message: i.message,\n nodeId: i.nodeId ?? null,\n })),\n deployable: errors.length === 0,\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_deploy',\n 'Deploy a validated workflow to n8n. Pass the workflow JSON that passed kairos_validate. Strips server-assigned fields automatically. Requires N8N_BASE_URL and N8N_API_KEY.',\n {\n workflow: z.string().describe('The validated workflow JSON string to deploy'),\n activate: z.boolean().default(false).describe('Activate the workflow immediately after deployment'),\n kairos_run_id: z.string().optional().describe('Run ID from kairos_prompt — enables telemetry correlation'),\n },\n async ({ workflow: workflowStr, activate, kairos_run_id }) => {\n if (!isAllowed('deploy')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Deploy is disabled. Set KAIROS_MCP_ALLOW_DEPLOY=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n let parsed: N8nWorkflow\n try {\n parsed = JSON.parse(workflowStr) as N8nWorkflow\n } catch (e) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` }),\n }],\n }\n }\n\n const validation = validator.validate(parsed)\n const errors = validation.issues.filter(i => i.severity === 'error')\n if (errors.length > 0) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n error: 'Workflow has validation errors — fix them before deploying',\n errors: errors.map(i => ({ rule: i.rule, message: i.message })),\n }, null, 2),\n }],\n }\n }\n\n const client = getApiClient()\n const stripped = stripper.stripForCreate(parsed)\n const response = await client.createWorkflow(stripped)\n\n if (activate) {\n if (!isAllowed('activate')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n workflowId: response.id,\n name: response.name,\n activated: false,\n warning: 'Workflow deployed but activation is disabled. Set KAIROS_MCP_ALLOW_ACTIVATE=true to enable.',\n url: `${process.env['N8N_BASE_URL']}/workflow/${response.id}`,\n }, null, 2),\n }],\n }\n }\n await client.activateWorkflow(response.id)\n }\n\n // Save to library for future retrieval\n await library.initialize()\n await library.save(parsed, {\n description: parsed.name,\n generationMode: 'scratch',\n generationAttempts: 1,\n })\n\n if (mcpTelemetry && kairos_run_id) {\n const session = mcpSessions.get(kairos_run_id)\n if (session) {\n await mcpTelemetry.emit('build_complete', {\n description: session.description,\n success: true,\n totalAttempts: session.validateAttempts,\n totalDurationMs: Date.now() - session.startTime,\n totalTokensInput: 0,\n totalTokensOutput: 0,\n workflowName: response.name,\n workflowId: response.id,\n dryRun: false,\n credentialsNeeded: 0,\n warnedRules: session.warnedRules,\n workflowType: session.workflowType,\n }, kairos_run_id)\n mcpSessions.delete(kairos_run_id)\n PatternAnalyzer.fromEnv().analyzeAndSave().catch(() => {})\n }\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n workflowId: response.id,\n name: response.name,\n activated: activate,\n url: `${process.env['N8N_BASE_URL']}/workflow/${response.id}`,\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_search',\n 'Search the local workflow library for similar past builds. Returns matching workflows with scores, useful for finding examples and reusing patterns.',\n {\n query: z.string().describe('Search query — a workflow description or keywords'),\n limit: z.number().default(5).describe('Maximum number of results'),\n },\n async ({ query, limit }) => {\n await library.initialize()\n const matches = await library.search(query)\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(\n matches.slice(0, limit).map(m => ({\n score: Number(m.score.toFixed(3)),\n mode: m.mode,\n description: m.workflow.description,\n nodeCount: m.workflow.workflow.nodes.length,\n nodes: m.workflow.workflow.nodes.map(n => n.name),\n failurePatterns: m.workflow.failurePatterns ?? [],\n })),\n null,\n 2,\n ),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_sync',\n 'Sync the node catalog from your live n8n instance. Fetches all installed node types and versions so Kairos knows exactly what your n8n supports. Automatically called by kairos_prompt when n8n credentials are set, but you can call this manually to force a refresh.',\n {},\n async () => {\n const baseUrl = process.env['N8N_BASE_URL']\n const apiKey = process.env['N8N_API_KEY']\n if (!baseUrl || !apiKey) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'N8N_BASE_URL and N8N_API_KEY are required for sync.' }),\n }],\n isError: true,\n }\n }\n\n lastSync = null\n const result = await autoSync()\n if (!result) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Failed to fetch node types from n8n. Check your credentials and that your instance is running.' }),\n }],\n isError: true,\n }\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n synced: true,\n nodeCount: result.nodeCount,\n newNodes: result.newNodes,\n message: `Synced ${result.nodeCount} node types from your n8n instance (${result.newNodes} not in default catalog).`,\n }, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_patterns',\n 'Analyze telemetry data and return failure patterns, build stats, and credential breakdowns. Useful for understanding what goes wrong most often and how to prevent it.',\n {\n days: z.number().default(30).describe('Number of days of telemetry to analyze'),\n limit: z.number().optional().describe('Maximum number of failure patterns to return'),\n },\n async ({ days, limit }) => {\n const analyzer = PatternAnalyzer.fromEnv()\n const analysis = await analyzer.analyzeAndSave(days)\n\n if (limit !== undefined && limit > 0) {\n analysis.topFailureRules = analysis.topFailureRules.slice(0, limit)\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(analysis, null, 2),\n }],\n }\n },\n)\n\n// ── n8n management tools (need N8N_BASE_URL + N8N_API_KEY) ─────────────────\n\nserver.tool(\n 'kairos_list',\n 'List all workflows deployed on the connected n8n instance.',\n {},\n async () => {\n const client = getApiClient()\n const workflows = await client.listWorkflows()\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(workflows, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_get',\n 'Get the full JSON definition of a specific workflow by ID.',\n {\n workflow_id: z.string().describe('The n8n workflow ID'),\n },\n async ({ workflow_id }) => {\n const client = getApiClient()\n const workflow = await client.getWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(workflow, null, 2),\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_activate',\n 'Activate a deployed workflow so it starts running on triggers.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to activate'),\n },\n async ({ workflow_id }) => {\n if (!isAllowed('activate')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Activate is disabled. Set KAIROS_MCP_ALLOW_ACTIVATE=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n const client = getApiClient()\n await client.activateWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Activated workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_deactivate',\n 'Deactivate a running workflow.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to deactivate'),\n },\n async ({ workflow_id }) => {\n const client = getApiClient()\n await client.deactivateWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Deactivated workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_delete',\n 'Delete a workflow from n8n. This is irreversible.',\n {\n workflow_id: z.string().describe('The n8n workflow ID to delete'),\n },\n async ({ workflow_id }) => {\n if (!isAllowed('delete')) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({ error: 'Delete is disabled. Set KAIROS_MCP_ALLOW_DELETE=true to enable.' }),\n }],\n isError: true,\n }\n }\n\n const client = getApiClient()\n await client.deleteWorkflow(workflow_id)\n\n return {\n content: [{\n type: 'text' as const,\n text: `Deleted workflow ${workflow_id}`,\n }],\n }\n },\n)\n\nserver.tool(\n 'kairos_executions',\n 'List recent executions for a workflow, showing status and timing.',\n {\n workflow_id: z.string().optional().describe('Filter to a specific workflow ID (omit for all)'),\n limit: z.number().default(20).describe('Maximum number of executions to return'),\n },\n async ({ workflow_id, limit }) => {\n const client = getApiClient()\n const executions = await client.getExecutions(workflow_id, { limit })\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(executions, null, 2),\n }],\n }\n },\n)\n\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch((err: unknown) => {\n console.error('Kairos MCP server failed to start:', err)\n process.exit(1)\n})\n","import type { N8nNodeTypeInfo } from '../providers/n8n/types.js'\nimport type { NodeDefinition } from './registry.js'\nimport { NodeRegistry, DEFAULT_REGISTRY } from './registry.js'\n\nconst TRIGGER_PATTERNS = [/trigger/i, /Trigger$/]\n\nexport interface SyncResult {\n registry: NodeRegistry\n catalogText: string\n nodeCount: number\n newNodes: number\n}\n\nexport class NodeSyncer {\n private readonly baseRegistry: Map<string, NodeDefinition>\n\n constructor() {\n this.baseRegistry = new Map(DEFAULT_REGISTRY.map(d => [d.type, d]))\n }\n\n sync(liveNodes: N8nNodeTypeInfo[]): SyncResult {\n const merged = new Map(this.baseRegistry)\n let newNodes = 0\n\n for (const node of liveNodes) {\n const versions = Array.isArray(node.version) ? node.version : [node.version]\n const isTrigger = TRIGGER_PATTERNS.some(p => p.test(node.name))\n const credentialType = node.credentials?.[0]?.name\n\n const existing = merged.get(node.name)\n if (existing) {\n const allVersions = new Set([...existing.safeTypeVersions, ...versions])\n merged.set(node.name, {\n ...existing,\n safeTypeVersions: [...allVersions].sort((a, b) => a - b),\n })\n } else {\n newNodes++\n merged.set(node.name, {\n type: node.name,\n safeTypeVersions: versions.sort((a, b) => a - b),\n requiredParams: [],\n ...(credentialType ? { credentialType } : {}),\n ...(isTrigger ? { isTrigger: true } : {}),\n })\n }\n }\n\n const definitions = [...merged.values()]\n const registry = new NodeRegistry(definitions)\n const catalogText = this.buildCatalog(definitions)\n\n return { registry, catalogText, nodeCount: definitions.length, newNodes }\n }\n\n private buildCatalog(definitions: NodeDefinition[]): string {\n const triggers = definitions.filter(d => d.isTrigger)\n const regular = definitions.filter(d => !d.isTrigger)\n\n const formatEntry = (d: NodeDefinition): string => {\n const versions = d.safeTypeVersions.join(', ')\n const cred = d.credentialType ? ` — cred: ${d.credentialType}` : ''\n return `${d.type} typeVersion: ${versions}${cred}`\n }\n\n const triggerLines = triggers.map(formatEntry).join('\\n')\n const regularLines = regular.map(formatEntry).join('\\n')\n\n return `## NODE CATALOG — synced from your n8n instance (${definitions.length} node types)\n\n### Triggers:\n${triggerLines}\n\n### Regular nodes:\n${regularLines}`\n }\n}\n"],"mappings":"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","names":[]}
|