@leclabs/agent-flow-navigator-mcp 1.0.0 → 1.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.
Files changed (4) hide show
  1. package/README.md +17 -17
  2. package/index.js +23 -6
  3. package/package.json +1 -1
  4. package/store.js +40 -8
package/README.md CHANGED
@@ -60,34 +60,34 @@ Navigator returns: Step 2 of 8 - "Implement changes"
60
60
 
61
61
  ## MCP Tools Reference
62
62
 
63
- | Tool | Description |
64
- | ---- | ----------- |
65
- | `Navigate` | Start a workflow, get current state, or advance to next step |
66
- | `Diagram` | Generate a mermaid flowchart for a workflow |
67
- | `ListWorkflows` | List all available workflows |
68
- | `SelectWorkflow` | Get workflow selection dialog for user interaction |
69
- | `CopyWorkflows` | Copy workflows from catalog to project |
70
- | `ListCatalog` | List workflows available in the catalog |
63
+ | Tool | Description |
64
+ | ---------------- | ------------------------------------------------------------ |
65
+ | `Navigate` | Start a workflow, get current state, or advance to next step |
66
+ | `Diagram` | Generate a mermaid flowchart for a workflow |
67
+ | `ListWorkflows` | List all available workflows |
68
+ | `SelectWorkflow` | Get workflow selection dialog for user interaction |
69
+ | `CopyWorkflows` | Copy workflows from catalog to project |
70
+ | `ListCatalog` | List workflows available in the catalog |
71
71
 
72
72
  ### Navigate
73
73
 
74
74
  The primary tool for workflow navigation.
75
75
 
76
- | Parameter | Type | Description |
77
- | --------- | ---- | ----------- |
78
- | `workflowType` | string | Workflow ID (for start only, e.g., "feature-development") |
79
- | `description` | string | User's task description (for start) |
80
- | `taskFilePath` | string | Path to task file (for advance/current) |
81
- | `result` | "passed" \| "failed" | Step result (for advance) |
76
+ | Parameter | Type | Description |
77
+ | -------------- | -------------------- | --------------------------------------------------------- |
78
+ | `workflowType` | string | Workflow ID (for start only, e.g., "feature-development") |
79
+ | `description` | string | User's task description (for start) |
80
+ | `taskFilePath` | string | Path to task file (for advance/current) |
81
+ | `result` | "passed" \| "failed" | Step result (for advance) |
82
82
 
83
83
  ### Diagram
84
84
 
85
85
  Generates a mermaid diagram for visualizing workflow structure.
86
86
 
87
- | Parameter | Type | Description |
88
- | --------- | ---- | ----------- |
87
+ | Parameter | Type | Description |
88
+ | -------------- | ------ | ----------------------------------- |
89
89
  | `workflowType` | string | Workflow ID to visualize (required) |
90
- | `currentStep` | string | Optional step to highlight |
90
+ | `currentStep` | string | Optional step to highlight |
91
91
 
92
92
  ## Architecture Overview
93
93
 
package/index.js CHANGED
@@ -64,7 +64,7 @@ function loadProjectWorkflows(dirPath) {
64
64
  try {
65
65
  const content = JSON.parse(readFileSync(workflowFile, "utf-8"));
66
66
  if (validateWorkflow(id, content)) {
67
- store.loadDefinition(id, content);
67
+ store.loadDefinition(id, content, "project");
68
68
  loaded.push(id);
69
69
  }
70
70
  } catch (e) {
@@ -90,7 +90,7 @@ function loadCatalogWorkflows(dirPath) {
90
90
  try {
91
91
  const content = JSON.parse(readFileSync(join(dirPath, file), "utf-8"));
92
92
  if (validateWorkflow(id, content)) {
93
- store.loadDefinition(id, content);
93
+ store.loadDefinition(id, content, "catalog");
94
94
  loaded.push(id);
95
95
  }
96
96
  } catch (e) {
@@ -157,10 +157,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
157
157
  },
158
158
  {
159
159
  name: "ListWorkflows",
160
- description: "List all available workflows. Returns data only, no dialog.",
160
+ description: "List available workflows. Filters by source when project workflows exist.",
161
161
  inputSchema: {
162
162
  type: "object",
163
- properties: {},
163
+ properties: {
164
+ source: {
165
+ type: "string",
166
+ enum: ["all", "project", "catalog"],
167
+ description: "Filter by source. Default: 'project' if project workflows exist, else 'all'.",
168
+ },
169
+ },
164
170
  },
165
171
  },
166
172
  {
@@ -228,9 +234,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
228
234
  }
229
235
 
230
236
  case "ListWorkflows": {
237
+ // Default to project-only if project workflows exist
238
+ const hasProject = store.hasProjectWorkflows();
239
+ const filter = args.source || (hasProject ? "project" : "all");
240
+ const workflows = store.listWorkflows(filter);
231
241
  return jsonResponse({
232
242
  schemaVersion: 2,
233
- workflows: store.listWorkflows(),
243
+ workflows,
244
+ filter,
245
+ hasProjectWorkflows: hasProject,
246
+ hint:
247
+ hasProject && filter === "project"
248
+ ? "Showing project workflows. Use source='all' to include catalog."
249
+ : undefined,
234
250
  });
235
251
  }
236
252
 
@@ -245,6 +261,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
245
261
  throw new Error(`Workflow '${args.workflowType}' not found`);
246
262
  }
247
263
 
264
+ const source = store.getSource(args.workflowType);
248
265
  const markdown = generateDiagram(wfDef, args.currentStep);
249
266
 
250
267
  // Save diagram to file
@@ -254,7 +271,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
254
271
  const filePath = join(DIAGRAMS_PATH, `${args.workflowType}.md`);
255
272
  writeFileSync(filePath, markdown);
256
273
 
257
- return jsonResponse({ savedTo: filePath });
274
+ return jsonResponse({ savedTo: filePath, source });
258
275
  }
259
276
 
260
277
  case "CopyWorkflows": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leclabs/agent-flow-navigator-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server that navigates agents through DAG-based workflows",
5
5
  "license": "MIT",
6
6
  "author": "leclabs",
package/store.js CHANGED
@@ -29,16 +29,19 @@ export function validateWorkflow(id, content) {
29
29
  export class WorkflowStore {
30
30
  constructor() {
31
31
  this.workflows = new Map();
32
+ this.sources = new Map(); // Track source: "catalog" | "project"
32
33
  }
33
34
 
34
35
  /**
35
36
  * Load a workflow definition into the store
36
37
  * @param {string} id - Workflow identifier
37
38
  * @param {Object} workflow - Workflow definition
39
+ * @param {string} source - Source: "catalog" | "project"
38
40
  * @returns {string} The workflow id
39
41
  */
40
- loadDefinition(id, workflow) {
42
+ loadDefinition(id, workflow, source = "catalog") {
41
43
  this.workflows.set(id, workflow);
44
+ this.sources.set(id, source);
42
45
  return id;
43
46
  }
44
47
 
@@ -53,15 +56,43 @@ export class WorkflowStore {
53
56
 
54
57
  /**
55
58
  * List all loaded workflows with metadata
59
+ * @param {string} filter - Filter by source: "all" | "project" | "catalog"
56
60
  * @returns {Array} Array of workflow summaries
57
61
  */
58
- listWorkflows() {
59
- return Array.from(this.workflows.entries()).map(([id, wf]) => ({
60
- id,
61
- name: wf.name || id,
62
- description: wf.description || "",
63
- stepCount: Object.keys(wf.nodes || {}).length,
64
- }));
62
+ listWorkflows(filter = "all") {
63
+ const results = [];
64
+ for (const [id, wf] of this.workflows.entries()) {
65
+ const source = this.sources.get(id) || "catalog";
66
+ if (filter !== "all" && source !== filter) continue;
67
+ results.push({
68
+ id,
69
+ name: wf.name || id,
70
+ description: wf.description || "",
71
+ stepCount: Object.keys(wf.nodes || {}).length,
72
+ source,
73
+ });
74
+ }
75
+ return results;
76
+ }
77
+
78
+ /**
79
+ * Check if any project workflows exist
80
+ * @returns {boolean}
81
+ */
82
+ hasProjectWorkflows() {
83
+ for (const source of this.sources.values()) {
84
+ if (source === "project") return true;
85
+ }
86
+ return false;
87
+ }
88
+
89
+ /**
90
+ * Get the source of a workflow
91
+ * @param {string} id - Workflow identifier
92
+ * @returns {string|undefined} Source or undefined
93
+ */
94
+ getSource(id) {
95
+ return this.sources.get(id);
65
96
  }
66
97
 
67
98
  /**
@@ -78,6 +109,7 @@ export class WorkflowStore {
78
109
  */
79
110
  clear() {
80
111
  this.workflows.clear();
112
+ this.sources.clear();
81
113
  }
82
114
 
83
115
  /**