@cyanheads/workflows-mcp-server 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +376 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +306 -0
- package/changelog/0.1.x/0.1.0.md +19 -0
- package/changelog/0.1.x/0.1.1.md +25 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +13 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +30 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +132 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +14 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-create-temp.tool.d.ts +34 -0
- package/dist/mcp-server/tools/definitions/workflow-create-temp.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-create-temp.tool.js +132 -0
- package/dist/mcp-server/tools/definitions/workflow-create-temp.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-create.tool.d.ts +40 -0
- package/dist/mcp-server/tools/definitions/workflow-create.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-create.tool.js +153 -0
- package/dist/mcp-server/tools/definitions/workflow-create.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-get.tool.d.ts +52 -0
- package/dist/mcp-server/tools/definitions/workflow-get.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-get.tool.js +163 -0
- package/dist/mcp-server/tools/definitions/workflow-get.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-list.tool.d.ts +28 -0
- package/dist/mcp-server/tools/definitions/workflow-list.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/workflow-list.tool.js +148 -0
- package/dist/mcp-server/tools/definitions/workflow-list.tool.js.map +1 -0
- package/dist/services/workflow-index/types.d.ts +49 -0
- package/dist/services/workflow-index/types.d.ts.map +1 -0
- package/dist/services/workflow-index/types.js +6 -0
- package/dist/services/workflow-index/types.js.map +1 -0
- package/dist/services/workflow-index/workflow-index-service.d.ts +47 -0
- package/dist/services/workflow-index/workflow-index-service.d.ts.map +1 -0
- package/dist/services/workflow-index/workflow-index-service.js +395 -0
- package/dist/services/workflow-index/workflow-index-service.js.map +1 -0
- package/package.json +103 -0
- package/server.json +129 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview In-memory workflow index service with filesystem watcher.
|
|
3
|
+
* Loads, validates, and indexes YAML workflow files from the configured directory.
|
|
4
|
+
* Watches for changes and rebuilds the index with debouncing.
|
|
5
|
+
* @module services/workflow-index/workflow-index-service
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { logger } from '@cyanheads/mcp-ts-core/utils';
|
|
11
|
+
import * as semver from 'semver';
|
|
12
|
+
import { parse as parseYaml } from 'yaml';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Validation schemas
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const StepSchema = z.object({
|
|
17
|
+
server: z.string().min(1),
|
|
18
|
+
tool: z.string().min(1),
|
|
19
|
+
action: z.string().optional(),
|
|
20
|
+
description: z.string().optional(),
|
|
21
|
+
name: z.string().optional(),
|
|
22
|
+
params: z.record(z.string(), z.unknown()).optional(),
|
|
23
|
+
forEach: z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
const WorkflowSchema = z.object({
|
|
26
|
+
name: z.string().min(1),
|
|
27
|
+
version: z.string().regex(/^\d+\.\d+\.\d+/),
|
|
28
|
+
description: z.string().min(1),
|
|
29
|
+
author: z.string().min(1),
|
|
30
|
+
category: z.string().min(1).optional(),
|
|
31
|
+
tags: z
|
|
32
|
+
.array(z.string())
|
|
33
|
+
.nullable()
|
|
34
|
+
.optional()
|
|
35
|
+
.transform((v) => v ?? undefined),
|
|
36
|
+
created_date: z
|
|
37
|
+
.string()
|
|
38
|
+
.regex(/^\d{4}-\d{2}-\d{2}/)
|
|
39
|
+
.optional(),
|
|
40
|
+
last_updated_date: z
|
|
41
|
+
.string()
|
|
42
|
+
.regex(/^\d{4}-\d{2}-\d{2}/)
|
|
43
|
+
.optional(),
|
|
44
|
+
temporary: z.boolean().optional(),
|
|
45
|
+
steps: z.array(StepSchema).min(1),
|
|
46
|
+
});
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Slugification
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
/** Convert a display string to a filesystem-safe kebab-case slug. */
|
|
51
|
+
export function slugify(input) {
|
|
52
|
+
return input
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
55
|
+
.replace(/^-+|-+$/g, '');
|
|
56
|
+
}
|
|
57
|
+
/** Maximum slug length for a name used in a filename (leaves room for version + suffix). */
|
|
58
|
+
const MAX_NAME_SLUG_LENGTH = 200;
|
|
59
|
+
/** Throw a tagged error if the slug derived from a workflow name is empty or too long. */
|
|
60
|
+
function assertValidNameSlug(name, slug) {
|
|
61
|
+
if (!slug) {
|
|
62
|
+
throw Object.assign(new Error(`Workflow name "${name}" produces an empty slug`), {
|
|
63
|
+
_reason: 'invalid_name',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (slug.length > MAX_NAME_SLUG_LENGTH) {
|
|
67
|
+
throw Object.assign(new Error(`Workflow name is too long — keep it under ${MAX_NAME_SLUG_LENGTH} characters after slugification`), { _reason: 'name_too_long' });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Logging helpers (background/non-request context)
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
function logInfo(msg) {
|
|
74
|
+
logger.info(msg);
|
|
75
|
+
}
|
|
76
|
+
function logWarn(msg) {
|
|
77
|
+
logger.warning(msg);
|
|
78
|
+
}
|
|
79
|
+
function logError(msg, err) {
|
|
80
|
+
logger.error(msg, err instanceof Error ? err : new Error(String(err)));
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Service
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
export class WorkflowIndexService {
|
|
86
|
+
_index = new Map();
|
|
87
|
+
_ready = false;
|
|
88
|
+
_watcherController;
|
|
89
|
+
_debounceTimer;
|
|
90
|
+
workflowsDir;
|
|
91
|
+
globalInstructionsPath;
|
|
92
|
+
watcherDebounceMs;
|
|
93
|
+
constructor(workflowsDir, globalInstructionsPath, watcherDebounceMs) {
|
|
94
|
+
this.workflowsDir = workflowsDir;
|
|
95
|
+
this.globalInstructionsPath = globalInstructionsPath;
|
|
96
|
+
this.watcherDebounceMs = watcherDebounceMs;
|
|
97
|
+
}
|
|
98
|
+
// --- Public API ---
|
|
99
|
+
get ready() {
|
|
100
|
+
return this._ready;
|
|
101
|
+
}
|
|
102
|
+
/** The current in-memory index. */
|
|
103
|
+
get index() {
|
|
104
|
+
return this._index;
|
|
105
|
+
}
|
|
106
|
+
/** Initialize: build initial index and start filesystem watcher. */
|
|
107
|
+
async init() {
|
|
108
|
+
await this.rebuild();
|
|
109
|
+
this.startWatcher();
|
|
110
|
+
}
|
|
111
|
+
/** Tear down the watcher. */
|
|
112
|
+
shutdown() {
|
|
113
|
+
if (this._debounceTimer)
|
|
114
|
+
clearTimeout(this._debounceTimer);
|
|
115
|
+
this._watcherController?.abort();
|
|
116
|
+
}
|
|
117
|
+
// --- Lookup ---
|
|
118
|
+
/** Find all entries matching a name (across all versions). */
|
|
119
|
+
findByName(name) {
|
|
120
|
+
const results = [];
|
|
121
|
+
for (const entry of this._index.values()) {
|
|
122
|
+
if (entry.workflow.name === name)
|
|
123
|
+
results.push(entry);
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
/** Semver-aware lookup. Returns the highest version match if version is omitted. */
|
|
128
|
+
findWorkflow(name, version) {
|
|
129
|
+
if (version) {
|
|
130
|
+
return this._index.get(`${name}@${version}`);
|
|
131
|
+
}
|
|
132
|
+
const matches = this.findByName(name);
|
|
133
|
+
if (matches.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
matches.sort((a, b) => semver.rcompare(a.workflow.version, b.workflow.version));
|
|
136
|
+
return matches[0];
|
|
137
|
+
}
|
|
138
|
+
/** Read global_instructions.md content. Returns null if file missing. */
|
|
139
|
+
async readGlobalInstructions() {
|
|
140
|
+
try {
|
|
141
|
+
return await fs.readFile(this.globalInstructionsPath, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// --- Write operations ---
|
|
148
|
+
/** Write a permanent workflow YAML and rebuild the index. */
|
|
149
|
+
async writePermanent(workflow) {
|
|
150
|
+
const key = `${workflow.name}@${workflow.version}`;
|
|
151
|
+
const categorySlug = slugify(workflow.category ?? 'uncategorized');
|
|
152
|
+
const nameSlug = slugify(workflow.name);
|
|
153
|
+
const versionSlug = slugify(workflow.version);
|
|
154
|
+
assertValidNameSlug(workflow.name, nameSlug);
|
|
155
|
+
const categoryDir = path.join(this.workflowsDir, 'categories', categorySlug);
|
|
156
|
+
// Include version in filename so multiple versions coexist on disk.
|
|
157
|
+
const filePath = path.join(categoryDir, `${nameSlug}-${versionSlug}-workflow.yaml`);
|
|
158
|
+
await fs.mkdir(categoryDir, { recursive: true });
|
|
159
|
+
try {
|
|
160
|
+
// `wx` flag fails atomically if the file already exists, preventing TOCTOU races.
|
|
161
|
+
await fs.writeFile(filePath, buildYaml(workflow), { encoding: 'utf-8', flag: 'wx' });
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (err instanceof Error && err.code === 'EEXIST') {
|
|
165
|
+
throw Object.assign(new Error(`Workflow "${key}" already exists`), {
|
|
166
|
+
_reason: 'already_exists',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
// Immediately rebuild so the index is fresh for the caller.
|
|
172
|
+
// The watcher will also fire and trigger a redundant rebuild — that's fine (idempotent).
|
|
173
|
+
await this.rebuild();
|
|
174
|
+
return filePath;
|
|
175
|
+
}
|
|
176
|
+
/** Write a temporary workflow YAML and rebuild the index. */
|
|
177
|
+
async writeTemp(workflow) {
|
|
178
|
+
const nameSlug = slugify(workflow.name);
|
|
179
|
+
const versionSlug = slugify(workflow.version);
|
|
180
|
+
assertValidNameSlug(workflow.name, nameSlug);
|
|
181
|
+
const tempDir = path.join(this.workflowsDir, 'temp');
|
|
182
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
183
|
+
// Include version in filename so different versions are distinct files.
|
|
184
|
+
const filePath = path.join(tempDir, `${nameSlug}-${versionSlug}-workflow.yaml`);
|
|
185
|
+
await fs.writeFile(filePath, buildYaml(workflow), 'utf-8');
|
|
186
|
+
await this.rebuild();
|
|
187
|
+
return filePath;
|
|
188
|
+
}
|
|
189
|
+
// --- Internal ---
|
|
190
|
+
async rebuild() {
|
|
191
|
+
const newIndex = new Map();
|
|
192
|
+
try {
|
|
193
|
+
const categoriesDir = path.join(this.workflowsDir, 'categories');
|
|
194
|
+
await this.scanDirectory(categoriesDir, false, newIndex);
|
|
195
|
+
const tempDir = path.join(this.workflowsDir, 'temp');
|
|
196
|
+
await this.scanDirectory(tempDir, true, newIndex);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
logWarn(`Workflow index rebuild error: ${String(err)}`);
|
|
200
|
+
}
|
|
201
|
+
this._index = newIndex;
|
|
202
|
+
this._ready = true;
|
|
203
|
+
logInfo(`Workflow index rebuilt (${newIndex.size} entries)`);
|
|
204
|
+
// Write snapshot asynchronously — don't await
|
|
205
|
+
this.writeSnapshot(newIndex).catch((err) => {
|
|
206
|
+
logWarn(`Failed to write index snapshot: ${String(err)}`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
async scanDirectory(dir, isTemp, index) {
|
|
210
|
+
let entries;
|
|
211
|
+
try {
|
|
212
|
+
entries = await fs.readdir(dir, { withFileTypes: true, recursive: true, encoding: 'utf8' });
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Directory may not exist yet — that's fine
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
if (!entry.isFile())
|
|
220
|
+
continue;
|
|
221
|
+
const name = entry.name;
|
|
222
|
+
if (!name.endsWith('.yaml') && !name.endsWith('.yml'))
|
|
223
|
+
continue;
|
|
224
|
+
if (name === '_index.json')
|
|
225
|
+
continue;
|
|
226
|
+
// `recursive: true` sets `entry.parentPath` in Node 22+, falling back to `entry.path`
|
|
227
|
+
const parentDir = entry.parentPath ?? entry.path ?? dir;
|
|
228
|
+
const filePath = path.join(parentDir, name);
|
|
229
|
+
await this.loadFile(filePath, isTemp, index);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async loadFile(filePath, isTemp, index) {
|
|
233
|
+
let raw;
|
|
234
|
+
try {
|
|
235
|
+
raw = await fs.readFile(filePath, 'utf-8');
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
logWarn(`Failed to read workflow file ${filePath}: ${String(err)}`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
let parsed;
|
|
242
|
+
try {
|
|
243
|
+
parsed = parseYaml(raw);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
logWarn(`Failed to parse YAML at ${filePath}: ${String(err)}`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const result = WorkflowSchema.safeParse(parsed);
|
|
250
|
+
if (!result.success) {
|
|
251
|
+
logWarn(`Invalid workflow schema at ${filePath}: ${JSON.stringify(result.error.flatten().fieldErrors)}`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const workflow = result.data;
|
|
255
|
+
// Warn if a non-temp file is missing a category
|
|
256
|
+
if (!isTemp && !workflow.category) {
|
|
257
|
+
logWarn(`Permanent workflow missing category field: ${filePath} (name: ${workflow.name})`);
|
|
258
|
+
}
|
|
259
|
+
const key = `${workflow.name}@${workflow.version}`;
|
|
260
|
+
if (index.has(key)) {
|
|
261
|
+
logWarn(`Duplicate workflow key "${key}" — last write wins (file: ${filePath})`);
|
|
262
|
+
}
|
|
263
|
+
index.set(key, { workflow, filePath, isTemp });
|
|
264
|
+
}
|
|
265
|
+
async writeSnapshot(index) {
|
|
266
|
+
const snapshot = {
|
|
267
|
+
generatedAt: new Date().toISOString(),
|
|
268
|
+
count: index.size,
|
|
269
|
+
entries: {},
|
|
270
|
+
};
|
|
271
|
+
for (const [key, entry] of index) {
|
|
272
|
+
snapshot.entries[key] = {
|
|
273
|
+
filePath: entry.filePath,
|
|
274
|
+
isTemp: entry.isTemp,
|
|
275
|
+
name: entry.workflow.name,
|
|
276
|
+
version: entry.workflow.version,
|
|
277
|
+
...(entry.workflow.category !== undefined && { category: entry.workflow.category }),
|
|
278
|
+
...(entry.workflow.tags !== undefined && { tags: entry.workflow.tags }),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const snapshotPath = path.join(this.workflowsDir, '_index.json');
|
|
282
|
+
await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
283
|
+
}
|
|
284
|
+
startWatcher() {
|
|
285
|
+
this._watcherController = new AbortController();
|
|
286
|
+
const signal = this._watcherController.signal;
|
|
287
|
+
const debounceMs = this.watcherDebounceMs;
|
|
288
|
+
const rebuild = () => this.scheduledRebuild();
|
|
289
|
+
// Fire and forget — the loop runs in the background
|
|
290
|
+
void (async () => {
|
|
291
|
+
try {
|
|
292
|
+
const watcher = fs.watch(this.workflowsDir, { recursive: true, signal });
|
|
293
|
+
for await (const event of watcher) {
|
|
294
|
+
// Skip snapshot file events to avoid infinite loop
|
|
295
|
+
const filename = event.filename;
|
|
296
|
+
if (typeof filename === 'string' && filename.endsWith('_index.json')) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
// Debounce
|
|
300
|
+
if (this._debounceTimer)
|
|
301
|
+
clearTimeout(this._debounceTimer);
|
|
302
|
+
this._debounceTimer = setTimeout(rebuild, debounceMs);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
// AbortError is expected on shutdown — ignore it
|
|
307
|
+
if (err instanceof Error &&
|
|
308
|
+
(err.name === 'AbortError' || err.code === 'ABORT_ERR')) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
logWarn(`Filesystem watcher exited unexpectedly: ${String(err)}`);
|
|
312
|
+
}
|
|
313
|
+
})();
|
|
314
|
+
}
|
|
315
|
+
scheduledRebuild() {
|
|
316
|
+
this.rebuild().catch((err) => {
|
|
317
|
+
logWarn(`Debounced rebuild failed: ${String(err)}`);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
// YAML serialisation helper
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
function buildYaml(workflow) {
|
|
325
|
+
const lines = [];
|
|
326
|
+
lines.push(`name: ${quote(workflow.name)}`);
|
|
327
|
+
lines.push(`version: "${workflow.version}"`);
|
|
328
|
+
lines.push(`description: ${quote(workflow.description)}`);
|
|
329
|
+
lines.push(`author: ${quote(workflow.author)}`);
|
|
330
|
+
if (workflow.category)
|
|
331
|
+
lines.push(`category: ${quote(workflow.category)}`);
|
|
332
|
+
if (workflow.tags && workflow.tags.length > 0) {
|
|
333
|
+
lines.push('tags:');
|
|
334
|
+
for (const tag of workflow.tags)
|
|
335
|
+
lines.push(` - ${quote(tag)}`);
|
|
336
|
+
}
|
|
337
|
+
if (workflow.created_date)
|
|
338
|
+
lines.push(`created_date: "${workflow.created_date}"`);
|
|
339
|
+
if (workflow.last_updated_date)
|
|
340
|
+
lines.push(`last_updated_date: "${workflow.last_updated_date}"`);
|
|
341
|
+
if (workflow.temporary)
|
|
342
|
+
lines.push('temporary: true');
|
|
343
|
+
lines.push('steps:');
|
|
344
|
+
for (const step of workflow.steps) {
|
|
345
|
+
lines.push(` - server: ${quote(step.server)}`);
|
|
346
|
+
lines.push(` tool: ${quote(step.tool)}`);
|
|
347
|
+
if (step.action)
|
|
348
|
+
lines.push(` action: ${quote(step.action)}`);
|
|
349
|
+
if (step.description)
|
|
350
|
+
lines.push(` description: ${quote(step.description)}`);
|
|
351
|
+
if (step.name)
|
|
352
|
+
lines.push(` name: ${quote(step.name)}`);
|
|
353
|
+
if (step.forEach)
|
|
354
|
+
lines.push(` forEach: ${quote(step.forEach)}`);
|
|
355
|
+
if (step.params && Object.keys(step.params).length > 0) {
|
|
356
|
+
lines.push(' params:');
|
|
357
|
+
for (const [k, v] of Object.entries(step.params)) {
|
|
358
|
+
lines.push(` ${k}: ${yamlValue(v)}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return `${lines.join('\n')}\n`;
|
|
363
|
+
}
|
|
364
|
+
function quote(s) {
|
|
365
|
+
if (/[:#[\]{},&*?|<>=!%@`\\]|^[-?]/.test(s) || s.includes('\n')) {
|
|
366
|
+
return `"${s.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
367
|
+
}
|
|
368
|
+
return s;
|
|
369
|
+
}
|
|
370
|
+
function yamlValue(v) {
|
|
371
|
+
if (typeof v === 'string')
|
|
372
|
+
return quote(v);
|
|
373
|
+
if (typeof v === 'boolean' || typeof v === 'number')
|
|
374
|
+
return String(v);
|
|
375
|
+
if (v === null)
|
|
376
|
+
return 'null';
|
|
377
|
+
return JSON.stringify(v);
|
|
378
|
+
}
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
// Init/accessor pattern
|
|
381
|
+
// ---------------------------------------------------------------------------
|
|
382
|
+
let _service;
|
|
383
|
+
export function initWorkflowIndexService(_config, _storage, workflowsDir, globalInstructionsPath, watcherDebounceMs) {
|
|
384
|
+
_service = new WorkflowIndexService(workflowsDir, globalInstructionsPath, watcherDebounceMs);
|
|
385
|
+
_service.init().catch((err) => {
|
|
386
|
+
logError('WorkflowIndexService init failed', err);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
export function getWorkflowIndexService() {
|
|
390
|
+
if (!_service) {
|
|
391
|
+
throw new Error('WorkflowIndexService not initialized — call initWorkflowIndexService() in setup()');
|
|
392
|
+
}
|
|
393
|
+
return _service;
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=workflow-index-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-index-service.js","sourceRoot":"","sources":["../../../src/services/workflow-index/workflow-index-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cyanheads/workflows-mcp-server",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"mcpName": "io.github.cyanheads/workflows-mcp-server",
|
|
5
|
+
"description": "Store, query, and create YAML workflow playbooks for LLM agents via MCP. STDIO or Streamable HTTP.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"workflows-mcp-server": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"changelog/",
|
|
14
|
+
"dist/",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"CLAUDE.md",
|
|
18
|
+
"AGENTS.md",
|
|
19
|
+
"Dockerfile",
|
|
20
|
+
"server.json"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun run scripts/build.ts",
|
|
24
|
+
"rebuild": "bun run scripts/clean.ts && bun run build",
|
|
25
|
+
"clean": "bun run scripts/clean.ts",
|
|
26
|
+
"devcheck": "bun run scripts/devcheck.ts",
|
|
27
|
+
"audit:refresh": "rm -f bun.lock && bun install && bun audit",
|
|
28
|
+
"tree": "bun run scripts/tree.ts",
|
|
29
|
+
"list-skills": "bun run scripts/list-skills.ts",
|
|
30
|
+
"format": "biome check --write --unsafe",
|
|
31
|
+
"lint:mcp": "bun run scripts/lint-mcp.ts",
|
|
32
|
+
"lint:packaging": "bun run scripts/lint-packaging.ts",
|
|
33
|
+
"bundle": "bun run build && npx -y @anthropic-ai/mcpb pack . dist/workflows-mcp-server.mcpb",
|
|
34
|
+
"changelog:build": "bun run scripts/build-changelog.ts",
|
|
35
|
+
"changelog:check": "bun run scripts/build-changelog.ts --check",
|
|
36
|
+
"publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish",
|
|
37
|
+
"test": "bunx vitest run",
|
|
38
|
+
"start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
|
|
39
|
+
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"mcp",
|
|
43
|
+
"mcp-server",
|
|
44
|
+
"model-context-protocol",
|
|
45
|
+
"ai",
|
|
46
|
+
"llm",
|
|
47
|
+
"bun",
|
|
48
|
+
"stdio",
|
|
49
|
+
"streamable-http",
|
|
50
|
+
"workflows",
|
|
51
|
+
"yaml",
|
|
52
|
+
"playbook",
|
|
53
|
+
"automation",
|
|
54
|
+
"agent-tools"
|
|
55
|
+
],
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/cyanheads/workflows-mcp-server.git"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/cyanheads/workflows-mcp-server#readme",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/cyanheads/workflows-mcp-server/issues"
|
|
63
|
+
},
|
|
64
|
+
"author": "cyanheads <casey@caseyjhand.com> (https://github.com/cyanheads/workflows-mcp-server#readme)",
|
|
65
|
+
"funding": [
|
|
66
|
+
{
|
|
67
|
+
"type": "github",
|
|
68
|
+
"url": "https://github.com/sponsors/cyanheads"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"type": "buy_me_a_coffee",
|
|
72
|
+
"url": "https://www.buymeacoffee.com/cyanheads"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"license": "Apache-2.0",
|
|
76
|
+
"packageManager": "bun@1.3.2",
|
|
77
|
+
"engines": {
|
|
78
|
+
"bun": ">=1.3.2",
|
|
79
|
+
"node": ">=24.0.0"
|
|
80
|
+
},
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@cyanheads/mcp-ts-core": "^0.9.11",
|
|
86
|
+
"pino-pretty": "^13.1.3",
|
|
87
|
+
"semver": "^7.8.1",
|
|
88
|
+
"yaml": "^2.9.0",
|
|
89
|
+
"zod": "^4.4.3"
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@biomejs/biome": "^2.4.16",
|
|
93
|
+
"@types/node": "^25.9.1",
|
|
94
|
+
"@types/semver": "^7.7.1",
|
|
95
|
+
"@vitest/coverage-istanbul": "^4.1.7",
|
|
96
|
+
"depcheck": "^1.4.7",
|
|
97
|
+
"fast-check": "^4.8.0",
|
|
98
|
+
"ignore": "^7.0.5",
|
|
99
|
+
"tsc-alias": "^1.8.17",
|
|
100
|
+
"typescript": "^6.0.3",
|
|
101
|
+
"vitest": "^4.1.7"
|
|
102
|
+
}
|
|
103
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.cyanheads/workflows-mcp-server",
|
|
4
|
+
"description": "Store, query, and create YAML workflow playbooks for LLM agents.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/cyanheads/workflows-mcp-server",
|
|
7
|
+
"source": "github"
|
|
8
|
+
},
|
|
9
|
+
"version": "0.1.1",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
14
|
+
"identifier": "@cyanheads/workflows-mcp-server",
|
|
15
|
+
"runtimeHint": "bun",
|
|
16
|
+
"version": "0.1.1",
|
|
17
|
+
"packageArguments": [
|
|
18
|
+
{ "type": "positional", "value": "run" },
|
|
19
|
+
{ "type": "positional", "value": "start:stdio" }
|
|
20
|
+
],
|
|
21
|
+
"environmentVariables": [
|
|
22
|
+
{
|
|
23
|
+
"name": "WORKFLOWS_DIR",
|
|
24
|
+
"description": "Absolute or relative path to the workflows root directory.",
|
|
25
|
+
"format": "string",
|
|
26
|
+
"isRequired": false,
|
|
27
|
+
"default": "./workflows-yaml"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "GLOBAL_INSTRUCTIONS_PATH",
|
|
31
|
+
"description": "Path to the global instructions markdown file. Derives from WORKFLOWS_DIR when not set.",
|
|
32
|
+
"format": "string",
|
|
33
|
+
"isRequired": false,
|
|
34
|
+
"default": ""
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "WATCHER_DEBOUNCE_MS",
|
|
38
|
+
"description": "Milliseconds to debounce filesystem change events before rebuilding the index.",
|
|
39
|
+
"format": "string",
|
|
40
|
+
"isRequired": false,
|
|
41
|
+
"default": "500"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "MCP_LOG_LEVEL",
|
|
45
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
46
|
+
"format": "string",
|
|
47
|
+
"isRequired": false,
|
|
48
|
+
"default": "info"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"transport": {
|
|
52
|
+
"type": "stdio"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"registryType": "npm",
|
|
57
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
58
|
+
"identifier": "@cyanheads/workflows-mcp-server",
|
|
59
|
+
"runtimeHint": "bun",
|
|
60
|
+
"version": "0.1.1",
|
|
61
|
+
"packageArguments": [
|
|
62
|
+
{ "type": "positional", "value": "run" },
|
|
63
|
+
{ "type": "positional", "value": "start:http" }
|
|
64
|
+
],
|
|
65
|
+
"environmentVariables": [
|
|
66
|
+
{
|
|
67
|
+
"name": "WORKFLOWS_DIR",
|
|
68
|
+
"description": "Absolute or relative path to the workflows root directory.",
|
|
69
|
+
"format": "string",
|
|
70
|
+
"isRequired": false,
|
|
71
|
+
"default": "./workflows-yaml"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "GLOBAL_INSTRUCTIONS_PATH",
|
|
75
|
+
"description": "Path to the global instructions markdown file. Derives from WORKFLOWS_DIR when not set.",
|
|
76
|
+
"format": "string",
|
|
77
|
+
"isRequired": false,
|
|
78
|
+
"default": ""
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "WATCHER_DEBOUNCE_MS",
|
|
82
|
+
"description": "Milliseconds to debounce filesystem change events before rebuilding the index.",
|
|
83
|
+
"format": "string",
|
|
84
|
+
"isRequired": false,
|
|
85
|
+
"default": "500"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "MCP_HTTP_HOST",
|
|
89
|
+
"description": "The hostname for the HTTP server.",
|
|
90
|
+
"format": "string",
|
|
91
|
+
"isRequired": false,
|
|
92
|
+
"default": "127.0.0.1"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "MCP_HTTP_PORT",
|
|
96
|
+
"description": "The port to run the HTTP server on.",
|
|
97
|
+
"format": "string",
|
|
98
|
+
"isRequired": false,
|
|
99
|
+
"default": "3010"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "MCP_HTTP_ENDPOINT_PATH",
|
|
103
|
+
"description": "The endpoint path for the MCP server.",
|
|
104
|
+
"format": "string",
|
|
105
|
+
"isRequired": false,
|
|
106
|
+
"default": "/mcp"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "MCP_AUTH_MODE",
|
|
110
|
+
"description": "Authentication mode to use: 'none', 'jwt', or 'oauth'.",
|
|
111
|
+
"format": "string",
|
|
112
|
+
"isRequired": false,
|
|
113
|
+
"default": "none"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "MCP_LOG_LEVEL",
|
|
117
|
+
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
118
|
+
"format": "string",
|
|
119
|
+
"isRequired": false,
|
|
120
|
+
"default": "info"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"transport": {
|
|
124
|
+
"type": "streamable-http",
|
|
125
|
+
"url": "http://localhost:3010/mcp"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|