MCP server that executes directed graphs of MCP server calls.
mcpGraph is an MCP (Model Context Protocol) server that exposes tools defined by declarative YAML configurations. Each tool executes a directed graph of nodes that can call other MCP tools, transform data, and make routing decisions, all without embedding a full programming language.
Key Features:
- Declarative Configuration: Define tools and their execution graphs in YAML
- Data Transformation: Use JSONata expressions to transform data between nodes
- Conditional Routing: Use JSON Logic for conditional branching
- Observable: Every transformation and decision is traceable
- No Embedded Code: All logic expressed using standard expression languages (JSONata, JSON Logic)
Here's a simple example that counts files in a directory:
version: "1.0"
# MCP Server Metadata
server:
name: "fileUtils"
version: "1.0.0"
title: "File utilities"
instructions: "This server provides file utility tools for counting files in directories."
# Optional: Execution limits to prevent infinite loops
executionLimits:
maxNodeExecutions: 1000 # Maximum total node executions (default: 1000)
maxExecutionTimeMs: 300000 # Maximum execution time in milliseconds (default: 300000 = 5 minutes)
# Tool Definitions
tools:
- name: "count_files"
description: "Counts the number of files in a directory"
inputSchema:
type: "object"
properties:
directory:
type: "string"
description: "The directory path to count files in"
required:
- directory
outputSchema:
type: "object"
properties:
count:
type: "number"
description: "The number of files in the directory"
# MCP Servers used by the graph
mcpServers:
filesystem:
command: "npx"
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "./tests/files"
# Graph Nodes
nodes:
# Entry node: Receives tool arguments
- id: "entry_count_files"
type: "entry"
tool: "count_files"
next: "list_directory_node"
# List directory contents
- id: "list_directory_node"
type: "mcp"
server: "filesystem"
tool: "list_directory"
args:
path: "$.entry_count_files.directory"
next: "count_files_node"
# Transform and count files
- id: "count_files_node"
type: "transform"
transform:
expr: |
{ "count": $count($split($.list_directory_node, "\n")) }
next: "exit_count_files"
# Exit node: Returns the count
- id: "exit_count_files"
type: "exit"
tool: "count_files"This graph:
- Receives a directory path as input
- Calls the filesystem MCP server's
list_directorytool - Transforms the result to count files using JSONata
- Returns the count
entry: Entry point for a tool's graph execution. Receives tool arguments.- Output: The tool input arguments (passed through as-is)
mcp: Calls an MCP tool on an internal or external MCP server.- Output: The MCP tool's response (parsed from the tool's content)
transform: Applies JSONata expressions to transform data between nodes.- Output: The result of evaluating the JSONata expression
switch: Uses JSON Logic to conditionally route to different nodes. Note:varoperations in JSON Logic rules are evaluated using JSONata, allowing full JSONata expression support.- Output: The node ID of the target node that was routed to (string)
exit: Exit point that returns the final result to the MCP tool caller.- Output: The output from the previous node in the execution history
mcpGraph maintains a complete execution history for each tool execution, enabling powerful debugging and introspection capabilities:
- Execution History: Every node execution is recorded with timing, outputs, and a unique
executionIndex(sequential: 0, 1, 2, ...) - Context Structure: Context for expressions is built from history - a flat structure where each node ID maps to its latest output
- Simple notation:
$.node_idaccesses the latest output of a node - When nodes execute multiple times (loops), context shows the most recent execution
- History functions provide access to all executions, not just the latest
- Simple notation:
- Time-Travel Debugging: Get the context that was available to any specific execution using
getContextForExecution(executionIndex) - History Functions: Use JSONata functions to access execution history:
$previousNode()- Get the previous node's output$previousNode(index)- Get the node that executed N steps before current$executionCount(nodeName)- Count how many times a node executed$nodeExecution(nodeName, index)- Get a specific execution of a node (0 = first, -1 = last)$nodeExecutions(nodeName)- Get all executions of a node as an array
- Loop Support: Nodes can execute multiple times in loops, with each execution tracked separately in history
See docs/introspection-debugging.md for detailed documentation on debugging features.
Context Access:
- All node outputs are accessible by node ID (e.g.,
$.entry_count_files.directory,$.list_directory_node) - Latest execution wins:
$.increment_nodereturns the most recent output when a node executes multiple times - History functions are available in all JSONata expressions (including those used in JSON Logic
varoperations)
If you're interested in contributing to mcpGraph or working with the source code, see CONTRIBUTING.md for setup instructions, development guidelines, and project structure.
Install mcpGraph from npm:
npm install -g mcpgraphOr install locally in your project:
npm install mcpgraphmcpGraph supports cyclical graphs, which requires guardrails to prevent infinite loops. Execution limits can be configured at the graph level:
version: "1.0"
server:
name: "myServer" # Required: unique identifier
version: "1.0.0" # Required: server version
title: "My MCP server" # Optional: display name (defaults to name if not provided)
instructions: "Instructions for using this server" # Optional: server usage instructions
# Optional: Execution limits to prevent infinite loops
executionLimits:
maxNodeExecutions: 1000 # Maximum total node executions (default: 1000)
maxExecutionTimeMs: 300000 # Maximum execution time in milliseconds (default: 300000 = 5 minutes)
tools:
# ... tool definitions ...Execution Limits:
maxNodeExecutions(optional): Maximum number of node executions across the entire graph. Default:1000. If execution reaches this limit, an error is thrown.maxExecutionTimeMs(optional): Maximum wall-clock time for graph execution in milliseconds. Default:300000(5 minutes). If execution exceeds this time, an error is thrown.
Both limits are checked before each node execution. If either limit is exceeded, execution stops immediately with a clear error message indicating which limit was hit.
Note: These limits are optional. If not specified, the defaults apply. They can be set to higher values for long-running batch jobs or lower values for quick operations.
To use mcpgraph as an MCP server in an MCP client (such as Claude Desktop), add it to your MCP client's configuration file.
Add mcpgraph to your Claude Desktop MCP configuration (typically located at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"mcpgraph": {
"command": "mcpgraph",
"args": [
"-c",
"/path/to/your/config.yaml"
]
}
}
}Or if not installed (run from npm):
{
"mcpServers": {
"mcpgraph": {
"command": "npx",
"args": [
"-y",
"mcpgraph",
"-c",
"/path/to/your/config.yaml"
]
}
}
}Note: Replace /path/to/your/config.yaml with the actual path to your YAML configuration file. The -c flag specifies the configuration file to use.
The mcpgraph package exports a programmatic API that can be used in your own applications (e.g., for building a UX server or other interfaces):
import { McpGraphApi } from 'mcpgraph';
// Create an API instance (loads and validates config)
const api = new McpGraphApi('path/to/config.yaml');
// List all available tools
const tools = api.listTools();
// Execute a tool
const result = await api.executeTool('count_files', {
directory: './tests/files',
});
// Clean up resources
await api.close();See examples/api-usage.ts for a complete example.
- Contributing Guide - Setup, development, and contribution guidelines
- Design Document - Complete design and architecture
- Implementation - Implementation details and architecture
- Introspection & Debugging - Guide for building visualizer applications and debuggers