mcpgraph 0.1.6 → 0.1.8
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/execution/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAgD,MAAM,oBAAoB,CAAC;AACvG,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAGf,mBAAmB,IAAI,oBAAoB,EAC5C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAQ1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,UAAU,CAAoC;gBAE1C,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB;IAMnE,aAAa,IAAI,oBAAoB,GAAG,IAAI;IAI5C,QAAQ,IAAI,KAAK;IAIjB,SAAS,IAAI,cAAc;IAI3B,OAAO,CAAC,eAAe;IAOjB,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/execution/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAgD,MAAM,oBAAoB,CAAC;AACvG,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAGf,mBAAmB,IAAI,oBAAoB,EAC5C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAQ1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,UAAU,CAAoC;gBAE1C,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB;IAMnE,aAAa,IAAI,oBAAoB,GAAG,IAAI;IAI5C,QAAQ,IAAI,KAAK;IAIjB,SAAS,IAAI,cAAc;IAI3B,OAAO,CAAC,eAAe;IAOjB,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;IAkN3B,OAAO,CAAC,cAAc;CAgCvB"}
|
|
@@ -72,7 +72,7 @@ export class GraphExecutor {
|
|
|
72
72
|
this.controller.setStatus("running");
|
|
73
73
|
}
|
|
74
74
|
// Execute nodes until we reach the exit node
|
|
75
|
-
while (
|
|
75
|
+
while (true) {
|
|
76
76
|
const node = this.graph.getNode(currentNodeId);
|
|
77
77
|
if (!node) {
|
|
78
78
|
throw new Error(`Node not found: ${currentNodeId}`);
|
|
@@ -166,30 +166,17 @@ export class GraphExecutor {
|
|
|
166
166
|
}
|
|
167
167
|
if (result.nextNode) {
|
|
168
168
|
currentNodeId = result.nextNode;
|
|
169
|
+
// If next node is the exit node, continue to process it in next iteration
|
|
170
|
+
if (currentNodeId === exitNode.id) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
169
173
|
}
|
|
170
174
|
else {
|
|
171
175
|
throw new Error(`Node ${currentNodeId} has no next node and is not the exit node`);
|
|
172
176
|
}
|
|
173
177
|
}
|
|
174
|
-
// Should not reach here
|
|
175
|
-
|
|
176
|
-
if (finalExitNode && finalExitNode.type === "exit") {
|
|
177
|
-
const result = executeExitNode(finalExitNode, context, Date.now());
|
|
178
|
-
if (this.controller) {
|
|
179
|
-
this.controller.setStatus("finished");
|
|
180
|
-
this.controller.setCurrentNode(null);
|
|
181
|
-
}
|
|
182
|
-
const endTime = Date.now();
|
|
183
|
-
const telemetry = enableTelemetry
|
|
184
|
-
? this.buildTelemetry(context, startTime, endTime)
|
|
185
|
-
: undefined;
|
|
186
|
-
return {
|
|
187
|
-
result: result.output,
|
|
188
|
-
executionHistory: context.getHistory(),
|
|
189
|
-
telemetry,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
throw new Error(`Exit node ${exitNode.id} not found or invalid`);
|
|
178
|
+
// Should not reach here - exit node should have been processed and returned
|
|
179
|
+
throw new Error(`Exit node was not reached`);
|
|
193
180
|
}
|
|
194
181
|
catch (error) {
|
|
195
182
|
if (this.controller) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/execution/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,OAAO,aAAa;IAChB,MAAM,CAAiB;IACvB,KAAK,CAAQ;IACb,aAAa,CAAmB;IAChC,UAAU,GAA+B,IAAI,CAAC;IAEtD,YAAY,MAAsB,EAAE,aAA+B;QACjE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,eAAe,CAAC,UAAkB;QACxC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,WAAW,CACf,QAAgB,EAChB,SAAkC,EAClC,OAA0B;QAE1B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QAE3C,+BAA+B;QAC/B,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;QAC7B,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;QAC/C,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,KAAK,CAAC;QAE1D,6DAA6D;QAC7D,IAAI,KAAK,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,UAAU,GAAG,IAAI,mBAAmB,EAAE,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC3C,CAAC;QAED,gCAAgC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAK,CAAsB,CAAC,IAAI,KAAK,QAAQ,CACvE,CAAC;QACF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,+BAA+B;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAK,CAAsB,CAAC,IAAI,KAAK,QAAQ,CACtE,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,aAAa,GAAG,SAAS,CAAC,EAAE,CAAC;QAEjC,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACvC,CAAC;YAED,6CAA6C;YAC7C,OAAO,
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/execution/executor.ts"],"names":[],"mappings":"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"}
|
package/docs/design.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# mcpGraph Design Document
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document memorializes the high-level design and tooling recommendations for mcpGraph, a product similar to n8n that surfaces an MCP interface and internally implements a directed graph of MCP server calls. The system enables filtering and reformatting data between nodes, makes routing decisions based on node output, and maintains a declarative, observable configuration without embedding a full programming language.
|
|
6
|
+
|
|
7
|
+
## Core Architecture: The Orchestrator
|
|
8
|
+
|
|
9
|
+
### Recommended Platform: TypeScript (Node.js)
|
|
10
|
+
|
|
11
|
+
**Rationale:**
|
|
12
|
+
- The MCP SDK is most mature in TypeScript
|
|
13
|
+
- Frontend tools for visual graph editing (like React Flow) are industry standard
|
|
14
|
+
- Strong ecosystem for both backend orchestration and frontend visualization
|
|
15
|
+
|
|
16
|
+
### Graph Execution Engine
|
|
17
|
+
|
|
18
|
+
The system implements a custom graph execution engine that orchestrates the directed graph of MCP server calls.
|
|
19
|
+
|
|
20
|
+
**Design Approach:**
|
|
21
|
+
- **Custom Execution Loop**: A lightweight, sequential execution loop that provides full control over execution flow
|
|
22
|
+
- **Simple Architecture**: Direct mapping from YAML node definitions to execution, avoiding abstraction layers
|
|
23
|
+
- **Data Flow**: Execution context maintains state and data flow between nodes
|
|
24
|
+
- **Control Flow**: Supports conditional routing via switch nodes; cycles are supported for future loop constructs
|
|
25
|
+
- **Observability**: Built-in execution history tracking for debugging and introspection
|
|
26
|
+
|
|
27
|
+
**Implementation:**
|
|
28
|
+
The YAML configuration is parsed into a graph structure (`Graph` class) and executed by a custom `GraphExecutor` that:
|
|
29
|
+
- Starts at the tool's entry node
|
|
30
|
+
- Executes nodes sequentially based on the graph structure
|
|
31
|
+
- Tracks execution state and history
|
|
32
|
+
- Routes conditionally via switch nodes
|
|
33
|
+
- Continues until the exit node is reached
|
|
34
|
+
|
|
35
|
+
### MCP Integration
|
|
36
|
+
|
|
37
|
+
- Use `@modelcontextprotocol/sdk`
|
|
38
|
+
- The system exposes an MCP server interface
|
|
39
|
+
- The YAML configuration defines the MCP server metadata and the tools it exposes
|
|
40
|
+
- Each tool definition includes standard MCP tool metadata (name, description, input/output parameters)
|
|
41
|
+
- Each tool's graph has an explicit entry node that receives tool arguments and initializes execution
|
|
42
|
+
- Each tool's graph has an explicit exit node that returns the final result to the MCP tool caller
|
|
43
|
+
- Execution flows through the graph from entry node to exit node
|
|
44
|
+
|
|
45
|
+
## Declarative Logic & Data Transformation
|
|
46
|
+
|
|
47
|
+
To avoid embedding a full programming language while maintaining declarative, observable configurations, the system uses standardized expression engines.
|
|
48
|
+
|
|
49
|
+
### Data Reformatting: JSONata
|
|
50
|
+
|
|
51
|
+
**Why JSONata:**
|
|
52
|
+
- Declarative query and transformation language for JSON
|
|
53
|
+
- Single string expression enables clear observability
|
|
54
|
+
- Can log input, expression, and output to debug transformations
|
|
55
|
+
|
|
56
|
+
**Resources:** [JSONata Documentation](https://jsonata.org/)
|
|
57
|
+
|
|
58
|
+
**YAML Example:**
|
|
59
|
+
```yaml
|
|
60
|
+
transform:
|
|
61
|
+
expr: "$merge([payload, {'timestamp': $now()}])"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Routing Decisions: JSON Logic
|
|
65
|
+
|
|
66
|
+
**Why JSON Logic:**
|
|
67
|
+
- Allows complex rules (e.g., "if price > 100 and status == 'active'") as pure JSON objects
|
|
68
|
+
- Declarative and observable
|
|
69
|
+
- No embedded code execution
|
|
70
|
+
|
|
71
|
+
**Resources:** [JSON Logic Documentation](https://jsonlogic.com/)
|
|
72
|
+
|
|
73
|
+
**YAML Example:**
|
|
74
|
+
```yaml
|
|
75
|
+
condition:
|
|
76
|
+
and:
|
|
77
|
+
- ">": [{ var: "price" }, 100]
|
|
78
|
+
- "==": [{ var: "status" }, "active"]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## High-Level Design: The Graph Runner
|
|
82
|
+
|
|
83
|
+
The system exposes an MCP server that reads a YAML configuration file. When a tool is called on this MCP server, it executes the corresponding graph starting at the tool's entry node and continuing until the exit node is reached.
|
|
84
|
+
|
|
85
|
+
### The Workflow Lifecycle
|
|
86
|
+
|
|
87
|
+
1. **Parse**: Read the YAML configuration into a structure containing MCP server metadata, tool definitions, and the directed graph of nodes
|
|
88
|
+
2. **Initialize MCP Server**: Expose the MCP server with the tools defined in the configuration
|
|
89
|
+
3. **Tool Invocation**: When a tool is called:
|
|
90
|
+
- Receive tool arguments from the MCP client
|
|
91
|
+
- Start graph execution at the tool's entry node
|
|
92
|
+
- Entry node receives tool arguments and initializes the execution context
|
|
93
|
+
4. **Execute Node**:
|
|
94
|
+
- **Entry Node**: Receives tool arguments, initializes execution context, passes to next node
|
|
95
|
+
- **Pre-transform**: Apply JSONata to the incoming data to format the tool arguments (if node is an MCP tool call)
|
|
96
|
+
- **Call Tool**: Use the MCP SDK to `callTool` on the target server (if node is an MCP tool call)
|
|
97
|
+
- **Transform**: Apply JSONata expressions to transform data (if node is a transform node)
|
|
98
|
+
- **Route**: Evaluate JSON Logic against the current data state to decide which edge to follow next (if node is a switch/conditional)
|
|
99
|
+
- **Track History**: Record node execution with inputs and outputs for observability
|
|
100
|
+
5. **Exit Node**: When execution reaches the exit node, extract the final result and return it to the MCP tool caller
|
|
101
|
+
|
|
102
|
+
## Visual Tooling & Observability
|
|
103
|
+
|
|
104
|
+
### Component Recommendations
|
|
105
|
+
|
|
106
|
+
| Component | Tooling Recommendation |
|
|
107
|
+
|-----------|----------------------|
|
|
108
|
+
| **Visual Editor** | **React Flow** - Industry standard for node-based UIs, used by companies like Stripe and Typeform. Provides customizable nodes, edges, zooming, panning, and built-in components like MiniMap and Controls. [React Flow Documentation](https://reactflow.dev/) |
|
|
109
|
+
| **Observability** | OpenTelemetry - wrap each node execution in a "Span" to see the "Trace" of data through the graph in tools like Jaeger |
|
|
110
|
+
|
|
111
|
+
## Implementation Strategy: The YAML Standard
|
|
112
|
+
|
|
113
|
+
Graph definitions should feel like Kubernetes manifests or GitHub Actions - declarative and version-controlled.
|
|
114
|
+
|
|
115
|
+
### Configuration Structure
|
|
116
|
+
|
|
117
|
+
The YAML configuration centers around MCP server and tool definitions:
|
|
118
|
+
|
|
119
|
+
1. **MCP Server Metadata**: Defines the MCP server information (name, version, description)
|
|
120
|
+
2. **Tools**: Array of tool definitions, each containing:
|
|
121
|
+
- Standard MCP tool metadata (name, description)
|
|
122
|
+
- Input parameters schema (MCP tool parameter definitions)
|
|
123
|
+
- Output schema (what the tool returns)
|
|
124
|
+
- Note: Entry and exit nodes are defined in the nodes section with a `tool` field indicating which tool they belong to
|
|
125
|
+
3. **Nodes**: The directed graph of nodes that execute when tools are called. Node types include:
|
|
126
|
+
- **`entry`**: Entry point for a tool's graph execution. Receives tool arguments and initializes execution context.
|
|
127
|
+
- **`mcp`**: Calls an MCP tool on an internal or external MCP server using `callTool`
|
|
128
|
+
- **`transform`**: Applies JSONata expressions to transform data between nodes
|
|
129
|
+
- **`switch`**: Uses JSON Logic to conditionally route to different nodes based on data
|
|
130
|
+
- **`exit`**: Exit point for a tool's graph execution. Extracts and returns the final result to the MCP tool caller
|
|
131
|
+
|
|
132
|
+
### Example YAML Structure: count_files Tool
|
|
133
|
+
|
|
134
|
+
This example defines a `count_files` tool that takes a directory, lists its contents using the filesystem MCP server, counts the files, and returns the count:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
version: "1.0"
|
|
138
|
+
|
|
139
|
+
# MCP Server Metadata
|
|
140
|
+
server:
|
|
141
|
+
name: "fileUtils"
|
|
142
|
+
version: "1.0.0"
|
|
143
|
+
description: "File utilities"
|
|
144
|
+
|
|
145
|
+
# Tool Definitions
|
|
146
|
+
tools:
|
|
147
|
+
- name: "count_files"
|
|
148
|
+
description: "Counts the number of files in a directory"
|
|
149
|
+
inputSchema:
|
|
150
|
+
type: "object"
|
|
151
|
+
properties:
|
|
152
|
+
directory:
|
|
153
|
+
type: "string"
|
|
154
|
+
description: "The directory path to count files in"
|
|
155
|
+
required:
|
|
156
|
+
- directory
|
|
157
|
+
outputSchema:
|
|
158
|
+
type: "object"
|
|
159
|
+
properties:
|
|
160
|
+
count:
|
|
161
|
+
type: "number"
|
|
162
|
+
description: "The number of files in the directory"
|
|
163
|
+
|
|
164
|
+
# MCP Servers used by the graph
|
|
165
|
+
servers:
|
|
166
|
+
filesystem:
|
|
167
|
+
command: "npx"
|
|
168
|
+
args:
|
|
169
|
+
- "-y"
|
|
170
|
+
- "@modelcontextprotocol/server-filesystem"
|
|
171
|
+
- "./tests/files"
|
|
172
|
+
|
|
173
|
+
# Graph Nodes
|
|
174
|
+
nodes:
|
|
175
|
+
# Entry node: Receives tool arguments
|
|
176
|
+
- id: "entry_count_files"
|
|
177
|
+
type: "entry"
|
|
178
|
+
tool: "count_files"
|
|
179
|
+
next: "list_directory_node"
|
|
180
|
+
|
|
181
|
+
# List directory contents
|
|
182
|
+
- id: "list_directory_node"
|
|
183
|
+
type: "mcp"
|
|
184
|
+
server: "filesystem"
|
|
185
|
+
tool: "list_directory"
|
|
186
|
+
args:
|
|
187
|
+
path: "$.input.directory"
|
|
188
|
+
next: "count_files_node"
|
|
189
|
+
|
|
190
|
+
# Transform and count files
|
|
191
|
+
- id: "count_files_node"
|
|
192
|
+
type: "transform"
|
|
193
|
+
transform:
|
|
194
|
+
expr: |
|
|
195
|
+
{ "count": $count($split(list_directory_node, "\n")) }
|
|
196
|
+
next: "exit_count_files"
|
|
197
|
+
|
|
198
|
+
# Exit node: Returns the count
|
|
199
|
+
- id: "exit_count_files"
|
|
200
|
+
type: "exit"
|
|
201
|
+
tool: "count_files"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Key Design Principles
|
|
205
|
+
|
|
206
|
+
1. **Declarative Configuration**: All logic expressed in YAML using standard expression languages (JSONata, JSON Logic)
|
|
207
|
+
2. **Observability**: Every transformation and decision is traceable and loggable
|
|
208
|
+
3. **No Embedded Code**: Avoid full programming languages to maintain clarity and safety
|
|
209
|
+
4. **Standard-Based**: Favor existing standards (JSONata, JSON Logic) over custom solutions
|
|
210
|
+
5. **Visual First**: Graph should be viewable and editable through a visual interface
|
|
211
|
+
6. **Execution Transparency**: Ability to observe graph execution in real-time
|
|
212
|
+
|
|
213
|
+
## System Components
|
|
214
|
+
|
|
215
|
+
1. **Executable**: Exposes an MCP server to run the graph (`mcpgraph` CLI)
|
|
216
|
+
2. **Programmatic API**: Exports `McpGraphApi` class for programmatic use (e.g., by visualizer applications)
|
|
217
|
+
3. **Graph Executor**: Core orchestration engine that executes the directed graph sequentially
|
|
218
|
+
4. **Execution Context**: Tracks execution state, data flow, and history
|
|
219
|
+
5. **Visual Editor**: Tools to visually view and edit the graph (future)
|
|
220
|
+
6. **Execution Observer**: Ability to observe and debug graph execution (future - see `docs/future-introspection-debugging.md`)
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# mcpGraph Implementation
|
|
2
|
+
|
|
3
|
+
This document describes the implementation of the mcpGraph MCP server with graph execution capabilities. The visual editor/UX is deferred to a later phase.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The implementation creates a working MCP server that can:
|
|
8
|
+
1. Parse YAML configuration files
|
|
9
|
+
2. Expose MCP tools defined in the configuration
|
|
10
|
+
3. Execute directed graphs of nodes when tools are called
|
|
11
|
+
4. Handle data transformation and routing between nodes
|
|
12
|
+
|
|
13
|
+
## Phase 1: Foundation & Configuration Parsing
|
|
14
|
+
|
|
15
|
+
### 1.1 Project Setup & Dependencies
|
|
16
|
+
|
|
17
|
+
**Implemented:**
|
|
18
|
+
- TypeScript project initialized
|
|
19
|
+
- Logger (stderr only) implemented in `src/logger.ts`
|
|
20
|
+
- All dependencies added:
|
|
21
|
+
- `@modelcontextprotocol/sdk` - MCP SDK
|
|
22
|
+
- `jsonata` - Data transformation
|
|
23
|
+
- `json-logic-js` - Conditional routing
|
|
24
|
+
- `js-yaml` - YAML parsing
|
|
25
|
+
- `zod` - Schema validation
|
|
26
|
+
|
|
27
|
+
**Note:** A custom execution loop was implemented to provide full control over execution flow and enable future introspection/debugging capabilities.
|
|
28
|
+
|
|
29
|
+
### 1.2 Type Definitions
|
|
30
|
+
|
|
31
|
+
**File: `src/types/config.ts`**
|
|
32
|
+
|
|
33
|
+
All TypeScript interfaces defined:
|
|
34
|
+
- `McpGraphConfig` - Root configuration structure
|
|
35
|
+
- `ServerMetadata` - MCP server metadata
|
|
36
|
+
- `ToolDefinition` - Tool definition with input/output schemas (entry/exit nodes are defined in nodes with `tool` field)
|
|
37
|
+
- `NodeDefinition` - Base node interface
|
|
38
|
+
- `EntryNode` - Entry point node that receives tool arguments
|
|
39
|
+
- `ExitNode` - Exit point node that returns final result
|
|
40
|
+
- `McpNode` - MCP tool call node
|
|
41
|
+
- `TransformNode` - JSONata transformation node
|
|
42
|
+
- `SwitchNode` - JSON Logic routing node
|
|
43
|
+
|
|
44
|
+
### 1.3 YAML Schema & Validation
|
|
45
|
+
|
|
46
|
+
**File: `src/config/schema.ts`**
|
|
47
|
+
|
|
48
|
+
Zod schemas implemented to validate YAML structure on load with clear error messages for invalid configurations.
|
|
49
|
+
|
|
50
|
+
### 1.4 YAML Parser
|
|
51
|
+
|
|
52
|
+
**File: `src/config/parser.ts`**
|
|
53
|
+
|
|
54
|
+
YAML file parsing into structured configuration with validation against schema. Handles file I/O errors gracefully.
|
|
55
|
+
|
|
56
|
+
### 1.5 Configuration Loader
|
|
57
|
+
|
|
58
|
+
**File: `src/config/loader.ts`**
|
|
59
|
+
|
|
60
|
+
Loads configuration from file path and returns parsed and validated configuration object.
|
|
61
|
+
|
|
62
|
+
## Phase 2: Graph Structure & Representation
|
|
63
|
+
|
|
64
|
+
### 2.1 Graph Data Structure
|
|
65
|
+
|
|
66
|
+
**File: `src/graph/graph.ts`**
|
|
67
|
+
|
|
68
|
+
Directed graph implementation from node definitions:
|
|
69
|
+
- Node adjacency (edges) storage
|
|
70
|
+
- Graph traversal utilities
|
|
71
|
+
- Support for cycles
|
|
72
|
+
|
|
73
|
+
### 2.2 Node Registry
|
|
74
|
+
|
|
75
|
+
**Note:** Not implemented as separate file - functionality integrated into `Graph` class and `validator.ts`:
|
|
76
|
+
- Node ID to node definition mapping
|
|
77
|
+
- Node reference validation (tool references in entry/exit nodes, next, switch targets)
|
|
78
|
+
- Orphaned node detection
|
|
79
|
+
- Graph connectivity validation
|
|
80
|
+
|
|
81
|
+
### 2.3 Graph Validator
|
|
82
|
+
|
|
83
|
+
**File: `src/graph/validator.ts`**
|
|
84
|
+
|
|
85
|
+
Graph structure validation:
|
|
86
|
+
- All referenced nodes exist
|
|
87
|
+
- All tools have exactly one entry and one exit node
|
|
88
|
+
- Entry nodes are only referenced as tool entry points
|
|
89
|
+
- Exit nodes are only referenced as tool exit points
|
|
90
|
+
- Exit nodes are reachable from entry nodes
|
|
91
|
+
- Detailed validation error messages
|
|
92
|
+
|
|
93
|
+
## Phase 3: MCP Server Foundation
|
|
94
|
+
|
|
95
|
+
### 3.1 MCP Server Setup
|
|
96
|
+
|
|
97
|
+
**Note:** Not implemented as separate file - functionality integrated into `src/main.ts`:
|
|
98
|
+
- MCP server initialization using `@modelcontextprotocol/sdk`
|
|
99
|
+
- Stdio transport setup
|
|
100
|
+
- Server lifecycle management
|
|
101
|
+
|
|
102
|
+
### 3.2 Tool Registration
|
|
103
|
+
|
|
104
|
+
**Note:** Not implemented as separate file - functionality integrated into `src/main.ts`:
|
|
105
|
+
- Tool definitions converted to MCP tool schemas
|
|
106
|
+
- Tools registered with MCP server
|
|
107
|
+
- Tool names mapped to execution handlers
|
|
108
|
+
|
|
109
|
+
### 3.3 Tool Execution Handler
|
|
110
|
+
|
|
111
|
+
**Note:** Not implemented as separate file - functionality integrated into `src/main.ts`:
|
|
112
|
+
- Tool invocation request handling
|
|
113
|
+
- Tool argument extraction
|
|
114
|
+
- Graph execution initiation at tool's entry node
|
|
115
|
+
- Result return to MCP client
|
|
116
|
+
|
|
117
|
+
## Phase 4: Expression Engines Integration
|
|
118
|
+
|
|
119
|
+
### 4.1 JSONata Integration
|
|
120
|
+
|
|
121
|
+
**File: `src/expressions/jsonata.ts`**
|
|
122
|
+
|
|
123
|
+
JSONata library wrapper:
|
|
124
|
+
- Expression evaluation with context data
|
|
125
|
+
- Error handling
|
|
126
|
+
- Support for JSONata references (e.g., `$.input.directory`)
|
|
127
|
+
|
|
128
|
+
### 4.2 JSON Logic Integration
|
|
129
|
+
|
|
130
|
+
**File: `src/expressions/json-logic.ts`**
|
|
131
|
+
|
|
132
|
+
JSON Logic library wrapper:
|
|
133
|
+
- Rule evaluation with context data
|
|
134
|
+
- Boolean results for routing decisions
|
|
135
|
+
- Error handling
|
|
136
|
+
|
|
137
|
+
### 4.3 Expression Context
|
|
138
|
+
|
|
139
|
+
**File: `src/execution/context.ts`**
|
|
140
|
+
|
|
141
|
+
Expression evaluation context building:
|
|
142
|
+
- Tool input arguments
|
|
143
|
+
- Previous node outputs
|
|
144
|
+
- Execution state
|
|
145
|
+
- Data access for expressions
|
|
146
|
+
|
|
147
|
+
**Note:** `src/expressions/context.ts` exists but functionality is primarily in `src/execution/context.ts`.
|
|
148
|
+
|
|
149
|
+
## Phase 5: Node Execution
|
|
150
|
+
|
|
151
|
+
### 5.1 Node Executor Base
|
|
152
|
+
|
|
153
|
+
**Note:** Not implemented as separate base class - each executor is standalone with consistent execution pattern:
|
|
154
|
+
- Pre-execution validation
|
|
155
|
+
- Execute node logic
|
|
156
|
+
- Post-execution processing
|
|
157
|
+
- Determine next node(s)
|
|
158
|
+
|
|
159
|
+
### 5.2 MCP Tool Node Executor
|
|
160
|
+
|
|
161
|
+
**File: `src/execution/nodes/mcp-tool-executor.ts`**
|
|
162
|
+
|
|
163
|
+
MCP tool node execution:
|
|
164
|
+
- Pre-transform: Apply JSONata to format tool arguments
|
|
165
|
+
- Call MCP tool using MCP client
|
|
166
|
+
- Handle MCP call errors
|
|
167
|
+
- Return output and next node
|
|
168
|
+
|
|
169
|
+
### 5.3 Transform Node Executor
|
|
170
|
+
|
|
171
|
+
**File: `src/execution/nodes/transform-executor.ts`**
|
|
172
|
+
|
|
173
|
+
Transform node execution:
|
|
174
|
+
- Apply JSONata transformation expression
|
|
175
|
+
- Pass through data with transformation
|
|
176
|
+
- Return transformed output and next node
|
|
177
|
+
|
|
178
|
+
### 5.4 Switch Node Executor
|
|
179
|
+
|
|
180
|
+
**File: `src/execution/nodes/switch-executor.ts`**
|
|
181
|
+
|
|
182
|
+
Switch node execution:
|
|
183
|
+
- Evaluate JSON Logic conditions in order
|
|
184
|
+
- Select target node based on first matching condition
|
|
185
|
+
- Handle default/fallback case (conditions without rules)
|
|
186
|
+
- Return next node based on condition result
|
|
187
|
+
|
|
188
|
+
### 5.5 Entry Node Executor
|
|
189
|
+
|
|
190
|
+
**File: `src/execution/nodes/entry-executor.ts`**
|
|
191
|
+
|
|
192
|
+
Entry node execution:
|
|
193
|
+
- Receive tool arguments from MCP client
|
|
194
|
+
- Initialize execution context with tool arguments
|
|
195
|
+
- Make tool arguments available to subsequent nodes (e.g., `$.input.*`)
|
|
196
|
+
- Pass execution to next node
|
|
197
|
+
|
|
198
|
+
### 5.6 Exit Node Executor
|
|
199
|
+
|
|
200
|
+
**File: `src/execution/nodes/exit-executor.ts`**
|
|
201
|
+
|
|
202
|
+
Exit node execution:
|
|
203
|
+
- Extract final result from execution context
|
|
204
|
+
- Signal execution completion
|
|
205
|
+
- Return final result to MCP tool caller
|
|
206
|
+
|
|
207
|
+
## Phase 6: Graph Execution Engine
|
|
208
|
+
|
|
209
|
+
### 6.1 Execution Context
|
|
210
|
+
|
|
211
|
+
**File: `src/execution/context.ts`**
|
|
212
|
+
|
|
213
|
+
Execution state management:
|
|
214
|
+
- Current node tracking
|
|
215
|
+
- Data context (tool inputs, node outputs)
|
|
216
|
+
- Execution history
|
|
217
|
+
- Error state
|
|
218
|
+
- Data access for expressions
|
|
219
|
+
|
|
220
|
+
### 6.2 Graph Executor
|
|
221
|
+
|
|
222
|
+
**File: `src/execution/executor.ts`**
|
|
223
|
+
|
|
224
|
+
Main graph execution orchestrator:
|
|
225
|
+
- Custom sequential execution loop
|
|
226
|
+
- Start at tool's entry node
|
|
227
|
+
- Execute current node based on type (entry, mcp, transform, switch, exit)
|
|
228
|
+
- Move to next node based on node's `next` field or switch routing
|
|
229
|
+
- Continue until exit node is reached
|
|
230
|
+
- Track execution history (node inputs/outputs)
|
|
231
|
+
- Handle errors with context
|
|
232
|
+
|
|
233
|
+
**Note:** The execution loop supports cycles (directed graphs with cycles), but infinite loops are prevented by the exit node check. Future loop node types can leverage this cycle support.
|
|
234
|
+
|
|
235
|
+
### 6.3 Execution Flow
|
|
236
|
+
|
|
237
|
+
**Note:** Not implemented as separate file - functionality integrated into `executor.ts`:
|
|
238
|
+
- Node execution sequence coordination
|
|
239
|
+
- Data flow between nodes
|
|
240
|
+
- Branching (switch nodes)
|
|
241
|
+
- Parallel execution support deferred
|
|
242
|
+
|
|
243
|
+
## Phase 7: MCP Client for External Servers
|
|
244
|
+
|
|
245
|
+
### 7.1 MCP Client Manager
|
|
246
|
+
|
|
247
|
+
**File: `src/mcp/client-manager.ts`**
|
|
248
|
+
|
|
249
|
+
MCP client connection management:
|
|
250
|
+
- Connections to external MCP servers
|
|
251
|
+
- Client connection caching
|
|
252
|
+
- Connection lifecycle handling
|
|
253
|
+
- Support for multiple concurrent servers
|
|
254
|
+
|
|
255
|
+
### 7.2 MCP Client Factory
|
|
256
|
+
|
|
257
|
+
**Note:** Not implemented as separate file - client creation functionality is in `client-manager.ts`:
|
|
258
|
+
- MCP client creation for different server types
|
|
259
|
+
- Stdio transport support
|
|
260
|
+
- Client configuration
|
|
261
|
+
|
|
262
|
+
### 7.3 Tool Call Handler
|
|
263
|
+
|
|
264
|
+
**Note:** Not implemented as separate file - tool calling functionality is in `mcp-tool-executor.ts`:
|
|
265
|
+
- `callTool` request execution to external MCP servers
|
|
266
|
+
- Tool argument handling
|
|
267
|
+
- Tool response processing
|
|
268
|
+
- Error and timeout handling
|
|
269
|
+
|
|
270
|
+
## Phase 8: Error Handling & Observability
|
|
271
|
+
|
|
272
|
+
### 8.1 Error Types
|
|
273
|
+
|
|
274
|
+
**Note:** Not implemented - using standard Error types:
|
|
275
|
+
- Basic error handling works with standard Error
|
|
276
|
+
- Custom error types (ConfigError, GraphError, ExecutionError, NodeError, McpError) would improve developer experience but are not required
|
|
277
|
+
|
|
278
|
+
### 8.2 Error Handling
|
|
279
|
+
|
|
280
|
+
**Note:** Basic error handling implemented throughout - centralized handler not implemented:
|
|
281
|
+
- Error logging with context (via logger)
|
|
282
|
+
- Error propagation through execution
|
|
283
|
+
- Basic user-friendly error messages
|
|
284
|
+
- Centralized error handler would be a nice-to-have enhancement
|
|
285
|
+
|
|
286
|
+
### 8.3 Execution Logging
|
|
287
|
+
|
|
288
|
+
**Note:** Basic logging implemented - structured execution logger not implemented:
|
|
289
|
+
- Node execution events logged via basic logger
|
|
290
|
+
- Structured logging would be valuable for debugging but basic logger works
|
|
291
|
+
|
|
292
|
+
## Phase 9: Integration & Testing
|
|
293
|
+
|
|
294
|
+
### 9.1 Main Entry Point
|
|
295
|
+
|
|
296
|
+
**File: `src/main.ts`**
|
|
297
|
+
|
|
298
|
+
Main entry point implementation:
|
|
299
|
+
- Command-line argument parsing (config file path)
|
|
300
|
+
- Configuration loading
|
|
301
|
+
- Graph validation
|
|
302
|
+
- MCP server startup
|
|
303
|
+
- Tool registration
|
|
304
|
+
- Tool execution handling
|
|
305
|
+
- Graceful shutdown handling
|
|
306
|
+
|
|
307
|
+
### 9.2 Integration Tests
|
|
308
|
+
|
|
309
|
+
**Files: `tests/files.test.ts`, `tests/mcp-server.test.ts`, `tests/switch.test.ts`**
|
|
310
|
+
|
|
311
|
+
Integration tests implemented:
|
|
312
|
+
- Full execution flow with sample configs
|
|
313
|
+
- Different node types tested
|
|
314
|
+
- MCP client integration tested
|
|
315
|
+
- Switch node conditional routing tested
|
|
316
|
+
|
|
317
|
+
### 9.3 Sample Configurations
|
|
318
|
+
|
|
319
|
+
**File: `examples/count_files.yaml`**
|
|
320
|
+
|
|
321
|
+
Sample configuration implemented demonstrating:
|
|
322
|
+
- Tool definition
|
|
323
|
+
- Entry/exit nodes
|
|
324
|
+
- MCP tool node
|
|
325
|
+
- Transform node with JSONata
|
|
326
|
+
|
|
327
|
+
## Phase 10: Polish & Documentation
|
|
328
|
+
|
|
329
|
+
### 10.1 Code Documentation
|
|
330
|
+
|
|
331
|
+
Basic JSDoc comments present on key functions. Comprehensive documentation would be a nice-to-have enhancement.
|
|
332
|
+
|
|
333
|
+
### 10.2 Error Messages
|
|
334
|
+
|
|
335
|
+
Basic error messages implemented. More helpful suggestions and context would improve developer experience.
|
|
336
|
+
|
|
337
|
+
### 10.3 README Updates
|
|
338
|
+
|
|
339
|
+
**File: `README.md`**
|
|
340
|
+
|
|
341
|
+
README updated with:
|
|
342
|
+
- Usage instructions
|
|
343
|
+
- Installation from npm
|
|
344
|
+
- MCP server configuration examples
|
|
345
|
+
- Examples and configuration format documentation
|
|
346
|
+
|
|
347
|
+
## Implementation Decisions
|
|
348
|
+
|
|
349
|
+
1. **Custom Execution Engine**: A custom execution loop was implemented to provide full control over execution flow, enable observability (execution history), and support future debugging/introspection features.
|
|
350
|
+
|
|
351
|
+
2. **Expression Evaluation**: All expressions (JSONata, JSON Logic) are evaluated with a consistent context that includes tool inputs and previous node outputs.
|
|
352
|
+
|
|
353
|
+
3. **Data Flow**: Data flows through nodes as a JSON object that accumulates results. Each node can read from and write to this context.
|
|
354
|
+
|
|
355
|
+
4. **Error Handling**: Errors at any node are caught, logged, and propagated. Basic error handling works; custom error types would be an enhancement.
|
|
356
|
+
|
|
357
|
+
5. **MCP Client Management**: External MCP servers are managed as separate clients. The system maintains a registry of available MCP servers and their tools.
|
|
358
|
+
|
|
359
|
+
6. **Code Organization**: Some planned separate files were integrated into existing files (e.g., server setup in main.ts, tool registration in main.ts). This works well and keeps the codebase simpler.
|
|
360
|
+
|
|
361
|
+
## Future Considerations
|
|
362
|
+
|
|
363
|
+
See `docs/future-introspection-debugging.md` for planned introspection and debugging features.
|
|
364
|
+
|
|
365
|
+
Other future enhancements:
|
|
366
|
+
- Visual editor/UX
|
|
367
|
+
- Hot-reload of configuration
|
|
368
|
+
- Loop node types (for, while, foreach)
|
|
369
|
+
- Parallel node execution
|
|
370
|
+
- Retry logic for failed nodes
|
|
371
|
+
- Execution history persistence
|
|
372
|
+
- Performance monitoring/metrics
|
|
373
|
+
- OpenTelemetry integration
|
|
374
|
+
- Custom error types
|
|
375
|
+
- Structured execution logging
|
|
376
|
+
- Centralized error handler
|
|
377
|
+
|
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
# Graph Introspection & Debugging
|
|
2
|
+
|
|
3
|
+
This document explains how to use mcpGraph's introspection and debugging features to build visualizer applications, debuggers, and observability tools.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
mcpGraph provides comprehensive introspection and debugging capabilities that allow you to:
|
|
8
|
+
|
|
9
|
+
- **Observe execution in real-time** using execution hooks
|
|
10
|
+
- **Control execution flow** with pause, resume, and step operations
|
|
11
|
+
- **Set breakpoints** on specific nodes
|
|
12
|
+
- **Collect telemetry** including timing and performance metrics
|
|
13
|
+
- **Inspect execution state** at any point during execution
|
|
14
|
+
- **Access execution history** with detailed timing information
|
|
15
|
+
|
|
16
|
+
All debugging features are **non-intrusive** - they only activate when explicitly enabled, ensuring normal execution remains unaffected.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { McpGraphApi, type ExecutionHooks } from 'mcpgraph';
|
|
22
|
+
|
|
23
|
+
const api = new McpGraphApi('config.yaml');
|
|
24
|
+
|
|
25
|
+
// Execute with debugging enabled
|
|
26
|
+
const result = await api.executeTool('count_files', {
|
|
27
|
+
directory: './tests/files'
|
|
28
|
+
}, {
|
|
29
|
+
hooks: {
|
|
30
|
+
onNodeStart: async (nodeId, node) => {
|
|
31
|
+
console.log(`Starting node: ${nodeId} (${node.type})`);
|
|
32
|
+
},
|
|
33
|
+
onNodeComplete: async (nodeId, node, input, output, duration) => {
|
|
34
|
+
console.log(`Node ${nodeId} completed in ${duration}ms`);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
enableTelemetry: true
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Access execution history and telemetry
|
|
41
|
+
console.log('History:', result.executionHistory);
|
|
42
|
+
console.log('Telemetry:', result.telemetry);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Execution Hooks
|
|
46
|
+
|
|
47
|
+
Execution hooks allow you to observe and control execution at key points. All hooks are optional and are async functions. If you don't need to perform async operations, you can simply not use `await` - the function will still work correctly.
|
|
48
|
+
|
|
49
|
+
### Available Hooks
|
|
50
|
+
|
|
51
|
+
All hooks are async functions that return Promises:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface ExecutionHooks {
|
|
55
|
+
/**
|
|
56
|
+
* Called before a node executes
|
|
57
|
+
* Return false to pause execution (acts as a breakpoint)
|
|
58
|
+
*/
|
|
59
|
+
onNodeStart?: (
|
|
60
|
+
nodeId: string,
|
|
61
|
+
node: NodeDefinition,
|
|
62
|
+
context: ExecutionContext
|
|
63
|
+
) => Promise<boolean>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Called after a node completes successfully
|
|
67
|
+
*/
|
|
68
|
+
onNodeComplete?: (
|
|
69
|
+
nodeId: string,
|
|
70
|
+
node: NodeDefinition,
|
|
71
|
+
input: unknown,
|
|
72
|
+
output: unknown,
|
|
73
|
+
duration: number
|
|
74
|
+
) => Promise<void>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Called when a node encounters an error
|
|
78
|
+
*/
|
|
79
|
+
onNodeError?: (
|
|
80
|
+
nodeId: string,
|
|
81
|
+
node: NodeDefinition,
|
|
82
|
+
error: Error,
|
|
83
|
+
context: ExecutionContext
|
|
84
|
+
) => Promise<void>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Called when execution pauses (breakpoint hit or manual pause)
|
|
88
|
+
*/
|
|
89
|
+
onPause?: (nodeId: string, context: ExecutionContext) => Promise<void>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Called when execution resumes
|
|
93
|
+
*/
|
|
94
|
+
onResume?: () => Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Example: Real-time UI Updates
|
|
99
|
+
|
|
100
|
+
All hooks are async functions. If you don't need async operations, you can simply not use `await`:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const hooks: ExecutionHooks = {
|
|
104
|
+
// Async function - no await needed if you don't have async operations
|
|
105
|
+
onNodeStart: async (nodeId, node, context) => {
|
|
106
|
+
// Update UI synchronously
|
|
107
|
+
updateNodeStatus(nodeId, 'running');
|
|
108
|
+
highlightNode(nodeId);
|
|
109
|
+
return true; // Continue execution
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
// Async function - can use await if needed
|
|
113
|
+
onNodeComplete: async (nodeId, node, input, output, duration) => {
|
|
114
|
+
// Update UI synchronously
|
|
115
|
+
updateNodeResult(nodeId, {
|
|
116
|
+
input,
|
|
117
|
+
output,
|
|
118
|
+
duration,
|
|
119
|
+
status: 'completed'
|
|
120
|
+
});
|
|
121
|
+
updateNodeVisualization(nodeId, output);
|
|
122
|
+
|
|
123
|
+
// Or perform async operations if needed
|
|
124
|
+
// await logToServer(nodeId, output);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
onNodeError: async (nodeId, node, error, context) => {
|
|
128
|
+
// Error handling
|
|
129
|
+
showError(nodeId, error);
|
|
130
|
+
updateNodeStatus(nodeId, 'error');
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
await api.executeTool('my_tool', {}, { hooks });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Execution Controller
|
|
138
|
+
|
|
139
|
+
The execution controller provides programmatic control over execution flow. It's available during execution when hooks or breakpoints are enabled.
|
|
140
|
+
|
|
141
|
+
### Getting the Controller
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Start execution with hooks/breakpoints
|
|
145
|
+
const executionPromise = api.executeTool('my_tool', {}, {
|
|
146
|
+
hooks: { /* ... */ },
|
|
147
|
+
breakpoints: ['node_1', 'node_2']
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Get controller (available during execution)
|
|
151
|
+
const controller = api.getController();
|
|
152
|
+
if (controller) {
|
|
153
|
+
// Use controller methods
|
|
154
|
+
controller.pause();
|
|
155
|
+
controller.resume();
|
|
156
|
+
await controller.step();
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Controller Methods
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
interface ExecutionController {
|
|
164
|
+
/**
|
|
165
|
+
* Pause execution at the next node boundary
|
|
166
|
+
* Only valid when status is "running"
|
|
167
|
+
*/
|
|
168
|
+
pause(): void;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Resume execution
|
|
172
|
+
* Only valid when status is "paused"
|
|
173
|
+
*/
|
|
174
|
+
resume(): void;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Step to the next node (step over)
|
|
178
|
+
* Only valid when status is "paused"
|
|
179
|
+
*/
|
|
180
|
+
step(): Promise<void>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get current execution state
|
|
184
|
+
*/
|
|
185
|
+
getState(): ExecutionState;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Set breakpoints
|
|
189
|
+
*/
|
|
190
|
+
setBreakpoints(nodeIds: string[]): void;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Clear breakpoints
|
|
194
|
+
*/
|
|
195
|
+
clearBreakpoints(): void;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Example: Step-through Debugging
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
const hooks: ExecutionHooks = {
|
|
203
|
+
onPause: async (nodeId, context) => {
|
|
204
|
+
console.log(`Paused at node: ${nodeId}`);
|
|
205
|
+
// Show debugger UI
|
|
206
|
+
showDebuggerUI();
|
|
207
|
+
},
|
|
208
|
+
onResume: async () => {
|
|
209
|
+
console.log('Resuming execution');
|
|
210
|
+
hideDebuggerUI();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// Start execution
|
|
215
|
+
const executionPromise = api.executeTool('my_tool', {}, {
|
|
216
|
+
hooks,
|
|
217
|
+
breakpoints: ['entry_node'] // Start paused
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// In your UI event handlers:
|
|
221
|
+
function handleStep() {
|
|
222
|
+
const controller = api.getController();
|
|
223
|
+
if (controller) {
|
|
224
|
+
await controller.step();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function handlePause() {
|
|
229
|
+
const controller = api.getController();
|
|
230
|
+
if (controller) {
|
|
231
|
+
controller.pause();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function handleResume() {
|
|
236
|
+
const controller = api.getController();
|
|
237
|
+
if (controller) {
|
|
238
|
+
controller.resume();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Breakpoints
|
|
244
|
+
|
|
245
|
+
Breakpoints allow you to pause execution at specific nodes. You can set breakpoints in two ways:
|
|
246
|
+
|
|
247
|
+
### 1. Via Execution Options
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
await api.executeTool('my_tool', {}, {
|
|
251
|
+
breakpoints: ['node_1', 'node_2', 'node_3']
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 2. Via Execution Controller
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const controller = api.getController();
|
|
259
|
+
if (controller) {
|
|
260
|
+
// Set breakpoints dynamically
|
|
261
|
+
controller.setBreakpoints(['node_1', 'node_2']);
|
|
262
|
+
|
|
263
|
+
// Clear all breakpoints
|
|
264
|
+
controller.clearBreakpoints();
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 3. Via onNodeStart Hook
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
const hooks: ExecutionHooks = {
|
|
272
|
+
onNodeStart: async (nodeId, node, context) => {
|
|
273
|
+
// Conditional breakpoint logic
|
|
274
|
+
if (shouldBreak(nodeId, context)) {
|
|
275
|
+
return false; // Pause execution
|
|
276
|
+
}
|
|
277
|
+
return true; // Continue
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Execution State
|
|
283
|
+
|
|
284
|
+
The execution state provides a snapshot of the current execution status, including:
|
|
285
|
+
|
|
286
|
+
- **Status**: Current execution status (`not_started`, `running`, `paused`, `finished`, `error`)
|
|
287
|
+
- **Current Node**: The node currently executing (or null)
|
|
288
|
+
- **Execution History**: Complete history of all executed nodes
|
|
289
|
+
- **Context**: The current execution context with all data
|
|
290
|
+
|
|
291
|
+
### Getting Execution State
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// During execution
|
|
295
|
+
const state = api.getExecutionState();
|
|
296
|
+
if (state) {
|
|
297
|
+
console.log('Status:', state.status);
|
|
298
|
+
console.log('Current Node:', state.currentNodeId);
|
|
299
|
+
console.log('History:', state.executionHistory);
|
|
300
|
+
console.log('Context:', state.context.getData());
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Or via controller
|
|
304
|
+
const controller = api.getController();
|
|
305
|
+
if (controller) {
|
|
306
|
+
const state = controller.getState();
|
|
307
|
+
// Same state object
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Execution Status
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
type ExecutionStatus =
|
|
315
|
+
| "not_started" // Execution hasn't begun
|
|
316
|
+
| "running" // Execution is actively running
|
|
317
|
+
| "paused" // Execution is paused (can resume/step)
|
|
318
|
+
| "finished" // Execution completed successfully
|
|
319
|
+
| "error"; // Execution failed with an error
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Execution State Interface
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
interface ExecutionState {
|
|
326
|
+
status: ExecutionStatus;
|
|
327
|
+
currentNodeId: string | null;
|
|
328
|
+
executionHistory: NodeExecutionRecord[];
|
|
329
|
+
context: ExecutionContext;
|
|
330
|
+
error?: Error; // Present when status is "error"
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Execution History
|
|
335
|
+
|
|
336
|
+
Execution history provides a complete record of all node executions with detailed timing information.
|
|
337
|
+
|
|
338
|
+
### History Record Structure
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
interface NodeExecutionRecord {
|
|
342
|
+
nodeId: string; // ID of the executed node
|
|
343
|
+
nodeType: string; // Type of node (entry, exit, transform, mcp, switch)
|
|
344
|
+
startTime: number; // Timestamp when node started (milliseconds)
|
|
345
|
+
endTime: number; // Timestamp when node ended (milliseconds)
|
|
346
|
+
duration: number; // Execution duration (milliseconds)
|
|
347
|
+
input: unknown; // Input data for the node
|
|
348
|
+
output: unknown; // Output data from the node
|
|
349
|
+
error?: Error; // Error object if node failed
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Accessing History
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// From execution result
|
|
357
|
+
const result = await api.executeTool('my_tool', {}, {
|
|
358
|
+
enableTelemetry: true
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
for (const record of result.executionHistory || []) {
|
|
362
|
+
console.log(`${record.nodeId}: ${record.duration}ms`);
|
|
363
|
+
if (record.error) {
|
|
364
|
+
console.error(`Error: ${record.error.message}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// From execution state (during execution)
|
|
369
|
+
const state = api.getExecutionState();
|
|
370
|
+
if (state) {
|
|
371
|
+
const history = state.executionHistory;
|
|
372
|
+
// Access history during execution
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Telemetry
|
|
377
|
+
|
|
378
|
+
Telemetry provides aggregated performance metrics and execution statistics.
|
|
379
|
+
|
|
380
|
+
### Telemetry Structure
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
interface ExecutionTelemetry {
|
|
384
|
+
totalDuration: number; // Total execution time (milliseconds)
|
|
385
|
+
nodeDurations: Map<string, number>; // Total duration per node type
|
|
386
|
+
nodeCounts: Map<string, number>; // Execution count per node type
|
|
387
|
+
errorCount: number; // Total number of errors
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Collecting Telemetry
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
const result = await api.executeTool('my_tool', {}, {
|
|
395
|
+
enableTelemetry: true // Enable telemetry collection
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
if (result.telemetry) {
|
|
399
|
+
console.log(`Total duration: ${result.telemetry.totalDuration}ms`);
|
|
400
|
+
console.log(`Errors: ${result.telemetry.errorCount}`);
|
|
401
|
+
|
|
402
|
+
// Node type statistics
|
|
403
|
+
for (const [nodeType, duration] of result.telemetry.nodeDurations) {
|
|
404
|
+
const count = result.telemetry.nodeCounts.get(nodeType) || 0;
|
|
405
|
+
console.log(`${nodeType}: ${count} executions, ${duration}ms total`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Example: Performance Analysis
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
function analyzePerformance(telemetry: ExecutionTelemetry) {
|
|
414
|
+
const avgDurations = new Map<string, number>();
|
|
415
|
+
|
|
416
|
+
for (const [nodeType, totalDuration] of telemetry.nodeDurations) {
|
|
417
|
+
const count = telemetry.nodeCounts.get(nodeType) || 1;
|
|
418
|
+
const avgDuration = totalDuration / count;
|
|
419
|
+
avgDurations.set(nodeType, avgDuration);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Find slowest node types
|
|
423
|
+
const sorted = Array.from(avgDurations.entries())
|
|
424
|
+
.sort((a, b) => b[1] - a[1]);
|
|
425
|
+
|
|
426
|
+
console.log('Slowest node types:');
|
|
427
|
+
for (const [nodeType, avgDuration] of sorted) {
|
|
428
|
+
console.log(` ${nodeType}: ${avgDuration.toFixed(2)}ms average`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Complete Example: Visualizer Application
|
|
434
|
+
|
|
435
|
+
Here's a complete example of how to build a visualizer application:
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { McpGraphApi, type ExecutionHooks, type ExecutionState } from 'mcpgraph';
|
|
439
|
+
|
|
440
|
+
class GraphVisualizer {
|
|
441
|
+
private api: McpGraphApi;
|
|
442
|
+
private executionPromise: Promise<any> | null = null;
|
|
443
|
+
|
|
444
|
+
constructor(configPath: string) {
|
|
445
|
+
this.api = new McpGraphApi(configPath);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async executeWithVisualization(toolName: string, args: Record<string, unknown>) {
|
|
449
|
+
const hooks: ExecutionHooks = {
|
|
450
|
+
onNodeStart: async (nodeId, node, context) => {
|
|
451
|
+
this.updateNodeStatus(nodeId, 'running');
|
|
452
|
+
this.highlightNode(nodeId);
|
|
453
|
+
return true;
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
onNodeComplete: async (nodeId, node, input, output, duration) => {
|
|
457
|
+
this.updateNodeStatus(nodeId, 'completed');
|
|
458
|
+
this.updateNodeData(nodeId, { input, output, duration });
|
|
459
|
+
this.unhighlightNode(nodeId);
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
onNodeError: async (nodeId, node, error, context) => {
|
|
463
|
+
this.updateNodeStatus(nodeId, 'error');
|
|
464
|
+
this.showError(nodeId, error);
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
onPause: async (nodeId, context) => {
|
|
468
|
+
this.showDebuggerControls();
|
|
469
|
+
this.updateExecutionStatus('paused');
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
onResume: async () => {
|
|
473
|
+
this.hideDebuggerControls();
|
|
474
|
+
this.updateExecutionStatus('running');
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
this.executionPromise = this.api.executeTool(toolName, args, {
|
|
479
|
+
hooks,
|
|
480
|
+
enableTelemetry: true
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const result = await this.executionPromise;
|
|
484
|
+
this.executionPromise = null;
|
|
485
|
+
|
|
486
|
+
// Display results
|
|
487
|
+
this.displayHistory(result.executionHistory || []);
|
|
488
|
+
this.displayTelemetry(result.telemetry);
|
|
489
|
+
|
|
490
|
+
return result;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
pause() {
|
|
494
|
+
const controller = this.api.getController();
|
|
495
|
+
if (controller) {
|
|
496
|
+
controller.pause();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
resume() {
|
|
501
|
+
const controller = this.api.getController();
|
|
502
|
+
if (controller) {
|
|
503
|
+
controller.resume();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
async step() {
|
|
508
|
+
const controller = this.api.getController();
|
|
509
|
+
if (controller) {
|
|
510
|
+
await controller.step();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
setBreakpoints(nodeIds: string[]) {
|
|
515
|
+
const controller = this.api.getController();
|
|
516
|
+
if (controller) {
|
|
517
|
+
controller.setBreakpoints(nodeIds);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
getCurrentState(): ExecutionState | null {
|
|
522
|
+
return this.api.getExecutionState();
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// UI update methods (implement based on your UI framework)
|
|
526
|
+
private updateNodeStatus(nodeId: string, status: string) { /* ... */ }
|
|
527
|
+
private highlightNode(nodeId: string) { /* ... */ }
|
|
528
|
+
private unhighlightNode(nodeId: string) { /* ... */ }
|
|
529
|
+
private updateNodeData(nodeId: string, data: any) { /* ... */ }
|
|
530
|
+
private showError(nodeId: string, error: Error) { /* ... */ }
|
|
531
|
+
private showDebuggerControls() { /* ... */ }
|
|
532
|
+
private hideDebuggerControls() { /* ... */ }
|
|
533
|
+
private updateExecutionStatus(status: string) { /* ... */ }
|
|
534
|
+
private displayHistory(history: any[]) { /* ... */ }
|
|
535
|
+
private displayTelemetry(telemetry: any) { /* ... */ }
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## API Reference
|
|
540
|
+
|
|
541
|
+
### McpGraphApi Methods
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
class McpGraphApi {
|
|
545
|
+
/**
|
|
546
|
+
* Execute a tool with optional debugging options
|
|
547
|
+
*/
|
|
548
|
+
async executeTool(
|
|
549
|
+
toolName: string,
|
|
550
|
+
toolArguments: Record<string, unknown>,
|
|
551
|
+
options?: ExecutionOptions
|
|
552
|
+
): Promise<ExecutionResult>;
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Get the execution controller (available during execution)
|
|
556
|
+
*/
|
|
557
|
+
getController(): ExecutionController | null;
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Get the current execution state (if execution is in progress)
|
|
561
|
+
*/
|
|
562
|
+
getExecutionState(): ExecutionState | null;
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Get the graph structure
|
|
566
|
+
*/
|
|
567
|
+
getGraph(): Graph;
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Get the full configuration
|
|
571
|
+
*/
|
|
572
|
+
getConfig(): McpGraphConfig;
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### ExecutionOptions
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
interface ExecutionOptions {
|
|
580
|
+
hooks?: ExecutionHooks; // Execution hooks for observation/control
|
|
581
|
+
breakpoints?: string[]; // Node IDs to pause at
|
|
582
|
+
enableTelemetry?: boolean; // Enable telemetry collection
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### ExecutionResult
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
interface ExecutionResult {
|
|
590
|
+
result: unknown; // The tool's result
|
|
591
|
+
structuredContent?: Record<string, unknown>; // Structured result (for MCP)
|
|
592
|
+
executionHistory?: NodeExecutionRecord[]; // Execution history
|
|
593
|
+
telemetry?: ExecutionTelemetry; // Performance telemetry
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
## Type Exports
|
|
598
|
+
|
|
599
|
+
All types are exported from the main package:
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
import {
|
|
603
|
+
McpGraphApi,
|
|
604
|
+
type ExecutionHooks,
|
|
605
|
+
type ExecutionController,
|
|
606
|
+
type ExecutionState,
|
|
607
|
+
type ExecutionStatus,
|
|
608
|
+
type ExecutionOptions,
|
|
609
|
+
type ExecutionResult,
|
|
610
|
+
type NodeExecutionRecord,
|
|
611
|
+
type ExecutionTelemetry,
|
|
612
|
+
type NodeDefinition,
|
|
613
|
+
type McpGraphConfig
|
|
614
|
+
} from 'mcpgraph';
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
## Best Practices
|
|
618
|
+
|
|
619
|
+
1. **Enable telemetry only when needed**: Telemetry collection adds overhead, so only enable it when you need performance metrics.
|
|
620
|
+
|
|
621
|
+
2. **Use hooks for real-time updates**: Hooks are perfect for updating UI in real-time as execution progresses.
|
|
622
|
+
|
|
623
|
+
3. **All hooks are async**: All hooks are async functions. If you don't need to perform async operations, you can simply not use `await` - the function will still work correctly. This provides consistency and allows you to add async operations later without changing the function signature.
|
|
624
|
+
|
|
625
|
+
4. **Clean up after execution**: The controller is automatically cleaned up after execution completes, but you should check for `null` when accessing it.
|
|
626
|
+
|
|
627
|
+
5. **Check execution state before operations**: Always verify that execution is in the correct state before calling controller methods (e.g., don't call `resume()` when status is `"running"`).
|
|
628
|
+
|
|
629
|
+
6. **Use breakpoints for debugging**: Breakpoints are more efficient than conditional logic in hooks for simple pause-on-node scenarios.
|
|
630
|
+
|
|
631
|
+
## Limitations
|
|
632
|
+
|
|
633
|
+
- **Controller availability**: The controller is only available during execution when hooks or breakpoints are enabled. After execution completes, it's cleaned up.
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
- **State modification**: You cannot modify execution context during paused execution (this may be added in future versions).
|
|
637
|
+
|
|
638
|
+
- **Concurrent executions**: Each `McpGraphApi` instance supports one execution at a time. For concurrent executions, create multiple instances.
|
|
639
|
+
|
|
640
|
+
## Future Enhancements
|
|
641
|
+
|
|
642
|
+
Planned enhancements include:
|
|
643
|
+
|
|
644
|
+
- Conditional breakpoints (break when expression evaluates to true)
|
|
645
|
+
- Watch expressions (monitor specific values during execution)
|
|
646
|
+
- State modification during paused execution
|
|
647
|
+
- Execution replay from history
|
|
648
|
+
- Execution comparison (compare multiple runs)
|
|
649
|
+
- OpenTelemetry integration for distributed tracing
|
|
650
|
+
|
|
651
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpgraph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "MCP server that executes directed graphs of MCP server calls",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
18
|
"examples",
|
|
19
|
+
"docs",
|
|
19
20
|
"README.md",
|
|
20
21
|
"LICENSE"
|
|
21
22
|
],
|