mcpgraphtoolkit
Build, test, and manage mcpGraph tools using the mcpGraphToolkit MCP server. Discover MCP servers and tools, construct graph nodes with JSONata and JSON Logic, and interact with mcpGraph configurations. IMPORTANT: Always read this file before creating graph tools using mcpGraphToolkit.
$ 安裝
git clone https://github.com/TeamSparkAI/mcpGraph /tmp/mcpGraph && cp -r /tmp/mcpGraph/skills/mcpgraphtoolkit ~/.claude/skills/mcpGraph// tip: Run this command in your terminal to install the skill
name: mcpgraphtoolkit description: "Build, test, and manage mcpGraph tools using the mcpGraphToolkit MCP server. Discover MCP servers and tools, construct graph nodes with JSONata and JSON Logic, and interact with mcpGraph configurations. IMPORTANT: Always read this file before creating graph tools using mcpGraphToolkit." version: 1.0.1
Building mcpGraph Tools with mcpGraphToolkit
This skill teaches you how to use the mcpGraphToolkit MCP server to build, debug, test, run, and manage graph tools in an mcpGraph.
What is an mcpGraph
An mcpGraph is a declarative configuration that defines an MCP (Model Context Protocol) server and its tools, where those tools are implemented as directed graphs. We call those exported tools "graph tools". Each graph tool executes a sequence of nodes that can:
- Call other MCP tools (that are available to the mcpGraph)
- Transform data using JSONata expressions
- Make routing decisions using JSON Logic
When to use mcpGraph:
- You need to orchestrate multiple MCP tool calls in sequence
- You want to transform data between tool calls
- You need conditional routing based on data
- You need to compose complex workflows from simpler MCP tools
Using the mcpGraphToolkit
What you should do:
- ✅ DO use
listMcpServersandlistMcpServerToolsto discover available MCP servers and tools - ✅ DO use
getMcpServerToolto get MCP server tool details and schemas - ✅ DO use
addGraphToolto add graph tools to the mcpGraph (it handles file operations automatically) - ✅ DO use
updateGraphToolanddeleteGraphToolto manage graph tools - ✅ DO use
runGraphToolto run a graph tool or to test a graph tool before adding it - ✅ DO use
listGraphToolsandgetGraphToolto discover and examine existing graph tools, especially when considering creating a new graph tool
⚠️ CRITICAL: Use Only the Provided Tools to interact with an mcpGraph
DO NOT create, edit, or read configuration files directly. mcpGraphToolkit uses configuration files internally (such as graph configuration files and MCP server configuration files), but you should never attempt to create, edit, or read directly from these files. The toolkit tools provide all the functionality you need to understand and manipulate the state of the mcpGraph.
Terminology: MCP Servers/Tools vs Graph Tools
Important: Understanding the distinction between MCP servers/tools and graph tools is critical.
MCP Servers and Tools (Available to the Graph)
- MCP Servers: External MCP servers that are available to the graph (discovered via
listMcpServers) - MCP Tools: Tools provided by those MCP servers (discovered via
listMcpServerToolsandgetMcpServerTool) - These are the building blocks that graph tools can use
- Graph tools can only use MCP servers and tools that are available to the graph (as determined by the toolkit's discovery APIs)
- Use
listMcpServersandlistMcpServerToolsto see what's available before building graph tools
Graph Tools (What You Create and Manage)
- Graph Tools: Tools you create, manage, and run using mcpGraphToolkit
- These are composed from MCP tools, transform nodes, and switch nodes
- Once created, graph tools can be called like MCP tools using
runGraphTool - Graph tools are stored in the graph configuration and can be discovered via
listGraphTools
Key Points:
- Graph tools orchestrate MCP tools - they call MCP tools in sequence, transform data, and make routing decisions
- Graph tools can only use MCP servers/tools that are available to the graph (check with
listMcpServersfirst) - Always check if an existing graph tool already serves your purpose before creating a new one (use
listGraphToolsandgetGraphTool) - Graph tools you create become available as callable tools, via
runGraphTool
Graph Tool Structure
A graph tool is a ToolDefinition with this structure:
{
"name": "tool_name",
"description": "Tool description",
"inputSchema": {
"type": "object",
"properties": { ... },
"required": [ ... ]
},
"outputSchema": {
"type": "object",
"properties": { ... }
},
"nodes": [
{ "id": "entry", "type": "entry", "next": "..." }, // REQUIRED
// ... worker nodes (mcp, transform, switch) ...
{ "id": "exit", "type": "exit" } // REQUIRED
]
}
Required Components:
name: Tool identifier (string)description: Tool description (string)inputSchema: JSON Schema for tool inputs (REQUIRED - must be object type)outputSchema: JSON Schema for tool outputs (REQUIRED - must be object type)nodes: Array of nodes (MUST include exactly one entry node and exactly one exit node)
Node Types and Required Fields:
Node Types
Entry Node
Entry point that receives tool arguments. Required in every graph tool.
id: Node identifier (typically"entry")type:"entry"next: ID of the first worker node
Output: Tool input arguments (passed through as-is)
{
"id": "entry",
"type": "entry",
"next": "list_directory_node"
}
MCP Node
Calls an MCP tool on a server available to the graph. Type is exactly "mcp" (NOT "mcp-tool", "mcp-tool-call", etc).
id: Node identifiertype:"mcp"server: MCP server name (must be available vialistMcpServers)tool: Tool name (must be available vialistMcpServerTools)args: Arguments (values starting with$are evaluated as JSONata)next: ID of the next node
Output: MCP tool's response (parsed from content)
{
"id": "list_directory_node",
"type": "mcp",
"server": "filesystem",
"tool": "list_directory",
"args": {
"path": { "expr": "$.entry.directory" }
},
"next": "count_files_node"
}
Important: Only use servers/tools discovered via listMcpServers and listMcpServerTools.
Transform Node
Applies JSONata expressions to transform data.
id: Node identifiertype:"transform"transform.expr: JSONata expression (string)next: ID of the next node
Output: Result of evaluating the JSONata expression
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
}
Switch Node
Uses JSON Logic to conditionally route to different nodes.
id: Node identifiertype:"switch"conditions: Array of{ rule, next }objectsnext: Default next node (used if no conditions match)
Output: Node ID of the routed-to node (string)
{
"id": "switch_node",
"type": "switch",
"conditions": [
{
"rule": {
">": [{ "var": "entry.value" }, 10]
},
"next": "high_path"
},
{
"rule": {
">": [{ "var": "entry.value" }, 0]
},
"next": "low_path"
}
],
"next": "zero_path"
}
Note: var operations in JSON Logic rules are evaluated using JSONata (see Expressions section).
Exit Node
Exit point that returns the final result. Required in every graph tool.
id: Node identifier (typically"exit")type:"exit"- No
nextfield - execution ends here
Output: Output from the previous node in execution history
{
"id": "exit",
"type": "exit"
}
Critical Rules:
- Every graph tool MUST have exactly one entry node (typically
id: "entry") - Every graph tool MUST have exactly one exit node (typically
id: "exit") - Entry node receives tool arguments and must have a
nextfield pointing to the first worker node - Exit node returns the final result and has NO
nextfield (execution ends here) - MCP node type is
"mcp"(NOT "mcp-tool", "mcp-tool-call", or any other variant) - All tools MUST include both
inputSchemaandoutputSchema(both must be object type) - Exit node returns the output from the previous node in the execution history (no special output mechanism needed)
Example Structure:
{
"name": "count_files",
"description": "Counts files in a directory",
"inputSchema": {
"type": "object",
"properties": {
"directory": { "type": "string" }
},
"required": ["directory"]
},
"outputSchema": {
"type": "object",
"properties": {
"count": { "type": "number" }
}
},
"nodes": [
{
"id": "entry",
"type": "entry",
"next": "list_directory_node"
},
{
"id": "list_directory_node",
"type": "mcp",
"server": "filesystem",
"tool": "list_directory",
"args": {
"path": { "expr": "$.entry.directory" }
},
"next": "count_files_node"
},
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
},
{
"id": "exit",
"type": "exit"
}
]
}
mcpGraphToolkit Tools
mcpGraphToolkit provides 12 tools organized into categories:
Graph Discovery Tools
getGraphServer: Get full details of the mcpGraph server metadata (name, version, title, instructions)listGraphTools: List all graph tools in the mcpGraph (name and description)- Always check this first before creating a new graph tool - an existing graph tool may already serve your purpose
getGraphTool: Get full detail of a graph tool from the mcpGraph (including complete node definitions)- Use this to understand existing graph tools before creating new ones
MCP Server Discovery Tools
listMcpServers: List all MCP servers available to the graph (name, title, instructions, version)- These are the MCP servers that graph tools can use
- Graph tools can only use MCP servers listed here
listMcpServerTools: List tools from MCP servers available to the graph (name/description only), optionally filtered by MCP server name- These are the MCP tools that graph tools can call
getMcpServerTool: Get full MCP server tool details (including input and output schemas)- Use this to understand how to call MCP tools from your graph tools
Graph Tool Management Tools
addGraphTool: Add a new tool to the mcpGraphupdateGraphTool: Update an existing tool in the mcpGraphdeleteGraphTool: Delete a tool from the mcpGraph
Tool Execution Tools
runGraphTool: Run an exported tool from the mcpGraph. Can specify existing tool name or run a tool definition supplied in payload. Supports optional logging collection.
Expression Testing Tools
testJSONata: Test a JSONata expression with contexttestJSONLogic: Test a JSON Logic expression with contexttestMcpTool: Test an MCP tool call directly to understand its output structure and behavior
Graph Structure and Flow
A graph is a directed sequence of nodes that execute in order. Execution flow:
- Starts at the entry node (receives tool arguments)
- Executes nodes sequentially based on
nextfields - switch nodes can conditionally route to different nodes
- Continues until the exit node is reached
- Exit node returns the final result
Node Connections
Nodes are connected using the next field, which specifies the ID of the next node to execute:
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
}
Switch nodes use conditions with next fields (each condition specifies its own next node), plus a top-level next field as the default:
{
"id": "switch_node",
"type": "switch",
"conditions": [
{
"rule": { ">": [{ "var": "entry.value" }, 10] },
"next": "high_path"
}
],
"next": "default_path"
}
Execution Context
During execution, each node's output is stored in the execution context. You can access node outputs using JSONata expressions:
$.node_id- Accesses the latest output of a node with IDnode_id$.entry.paramName- Accesses a parameter from the entry node
The context is a flat structure: { "node_id": output, ... }
Expressions
mcpGraph uses two expression languages: JSONata for data transformation and JSON Logic for conditional routing.
JSONata
JSONata is used in three places:
- Transform node expressions (
transform.expr) - Transform data between nodes - MCP tool node arguments - Any argument value starting with
$is evaluated as JSONata - JSON Logic
varoperations - Access context data in switch node conditions
Basic Syntax:
- Property access:
$.node_id.propertyor$.entry.paramName - Object construction:
{ "key": value } - Functions:
$count(array),$split(string, delimiter), etc. - Conditional:
condition ? trueValue : falseValue
History Functions (for loops):
$executionCount(nodeName)- Count executions of a node$nodeExecution(nodeName, index)- Get specific execution (0 = first, -1 = last)$nodeExecutions(nodeName)- Get all executions as array$previousNode()- Get previous node's output
Examples:
Transform node:
{
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
}
}
MCP node args:
{
"args": {
"path": { "expr": "$.entry.directory" }
}
}
In JSON Logic var:
{
"var": "$.increment_node.counter"
}
Testing: Use testJSONata tool to validate expressions before adding to nodes.
JSON Logic
JSON Logic is used in switch node conditions for conditional routing.
Basic Syntax:
- Comparison:
{ ">": [a, b] },{ "<": [a, b] },{ "==": [a, b] } - Logical:
{ "and": [rule1, rule2] },{ "or": [rule1, rule2] },{ "!": rule } - Variable access:
{ "var": "path" }or{ "var": "$.node_id.property" }
Important: var operations are evaluated using JSONata, so you can use full JSONata expressions including history functions.
Examples:
Simple comparison:
{
"rule": {
">": [{ "var": "entry.value" }, 10]
}
}
Complex condition:
{
"rule": {
"and": [
{ ">": [{ "var": "entry.price" }, 100] },
{ "==": [{ "var": "entry.status" }, "active"] }
]
}
}
With JSONata:
{
"rule": {
"<": [
{ "var": "$.increment_node.counter" },
{ "var": "$.increment_node.target" }
]
}
}
Testing: Use testJSONLogic tool to validate conditions before adding to switch nodes.
Understanding MCP Tool Outputs
When an MCP tool executes in a graph node, its output is stored in the execution context using the node ID. However, the structure of that output varies by tool, which can cause confusion when building graph tools.
Output Structure Patterns
Different MCP tools return data in different formats:
-
Direct/Plain Output - Tool returns data directly (string, number, object, etc.)
// Tool output stored as: { "fetch_url": "Content here..." } // Access in JSONata: $.fetch_url -
Wrapped Output - Tool returns an object with nested properties
// Tool output stored as: { "get_info": {"content": "File info here..."} } // Access in JSONata: $.get_info.content
How to Determine Output Structure
- Use
getMcpServerTool- Check the tool'soutputSchemato understand the expected structure - Use
testMcpTool- Test the tool directly to see its actual output (recommended) - Use
runGraphToolwith logging - Run a minimal graph with just entry → mcp → exit and checkexecutionHistory
Testing MCP Tools with testMcpTool
The testMcpTool tool allows you to test MCP tool calls directly without creating a full graph tool. This is the fastest way to understand how a tool behaves and what output structure it returns.
Basic Usage:
{
"tool": "testMcpTool",
"arguments": {
"server": "fetch",
"tool": "fetch",
"args": {
"url": "https://example.com",
"raw": true
}
}
}
Response:
{
"output": "Content type text/plain cannot be simplified...",
"executionTime": 267
}
With JSONata Expression Evaluation:
{
"tool": "testMcpTool",
"arguments": {
"server": "filesystem",
"tool": "write_file",
"args": {
"path": { "expr": "$.entry.filename" },
"content": { "expr": "$.fetch_result" }
},
"context": {
"entry": {"filename": "test.txt"},
"fetch_result": "Some content here"
}
}
}
Response:
{
"evaluatedArgs": {
"path": "test.txt",
"content": "Some content here"
},
"output": {"content": "Successfully wrote to test.txt"},
"executionTime": 8
}
Key Points:
outputmatches what would be available in a graph node's execution context- The output structure depends on the tool's response format (may be an object, string, or other type)
- Use
getMcpServerToolto understand the tool'soutputSchemaand expected output structure evaluatedArgsis included when JSONata expressions are used inargsandcontextis providedexecutionTimeshows how long the tool call took in milliseconds
Why This Matters:
Understanding the exact output structure is critical when building transform nodes or switch conditions that reference MCP tool outputs. Using testMcpTool before building your graph tool saves significant debugging time.
Building Tools with mcpGraphToolkit
Workflow
IMPORTANT: Follow this workflow exactly. Do not skip steps or try to create files manually.
-
Check for Existing Graph Tools
- ALWAYS START HERE: Use
listGraphToolsto see if a graph tool already exists for your purpose - Use
getGraphToolto examine existing graph tools before creating new ones - Only create a new graph tool if no existing tool serves your purpose
- ALWAYS START HERE: Use
-
Discover Available MCP Servers and Tools
- MUST USE
listMcpServersto see MCP servers available to the graph (graph tools can only use these servers) - MUST USE
listMcpServerToolsto see MCP tools available on a server (graph tools can only call these tools) - MUST USE
getMcpServerToolto get full tool details (input/output schemas) - RECOMMENDED: Use
testMcpToolto understand tool behavior and output structure before using it in a graph - Remember: Graph tools can only use MCP servers and tools that are available to the graph (as shown by these discovery tools)
- DO NOT attempt to read configuration files to discover MCP servers - use the toolkit discovery tools instead
- MUST USE
-
Test Components
- Use
testMcpToolto test MCP tool calls and understand their output structure - Use
testJSONatato test transform expressions (use actual MCP tool outputs fromtestMcpToolas context) - Use
testJSONLogicto test switch conditions - Iterate until all components work correctly
- Use
-
Build Tool Definition
- Construct nodes using MCP servers and tools that are available to the graph (from step 1)
- Only reference MCP servers and tools that were discovered via
listMcpServersandlistMcpServerTools - Use tested expressions in transform and switch nodes
- Define entry and exit nodes
- Specify input and output schemas
-
Test Tool Definition Before Adding
- Use
runGraphToolwithtoolDefinitionto test the tool inline (testing from source) - Optionally enable
logging: trueto see execution details - Verify the tool works correctly
- IMPORTANT: Use the exact same tool definition in Step 5
- Use
-
Add Tool to Graph
- MUST USE
addGraphToolto add the tested tool to the graph - CRITICAL: Use the exact same tool definition from Step 4
- DO NOT create or edit configuration files directly
- The tool is saved automatically by the toolkit (all file operations are handled internally)
- MUST USE
-
Verify Tool in Graph (Recommended)
- Use
runGraphToolwithtoolName(the tool's name) to test it from the graph - This verifies the tool was saved correctly and works when called from the graph
- Compare results with Step 4 to ensure consistency
- Use
-
Update or Delete Tools
- MUST USE
updateGraphToolto modify existing tools (do NOT edit configuration files directly) - MUST USE
deleteGraphToolto remove tools (do NOT edit configuration files directly) - Changes are saved automatically by the toolkit (all file operations are handled internally)
- MUST USE
Debugging Strategy
When building or debugging graph tools, follow this systematic approach:
-
Test MCP Tools Individually
- Use
testMcpToolto call the MCP tool directly and see its output structure - This helps you understand what data will be available in the execution context
- Don't guess at output structure - test it first
- Use
-
Test Expressions with Realistic Context
- Use outputs from
testMcpToolas context fortestJSONataexpressions - Use actual data structures, not guessed structures
- This prevents errors like trying to access
$.fetch_url.contentwhen the tool returns a plain string
- Use outputs from
-
Build Incrementally
- Start with entry → first_mcp → exit
- Add one transform or switch node at a time
- Test after each addition using
runGraphToolwithlogging: true
-
Use Debugging Tools
testMcpTool- Verify MCP tool calls work and understand output structuretestJSONata- Validate transform expressions before using themtestJSONLogic- Validate switch conditions before using themrunGraphToolwithlogging: true- See all execution steps and node outputsexecutionHistory- Inspect actual node outputs when debugging
Example: Debugging a Failed Transform
Error: "content": "expected string, received undefined"
Steps:
- Use
testMcpToolto see what the MCP tool actually returns - Use
testJSONatawith the actual output structure as context:{ "tool": "testJSONata", "arguments": { "expression": "$.fetch_url.content", "context": { "fetch_url": "actual output from testMcpTool" } } } - Adjust the expression based on the actual structure (e.g., use
$.fetch_urlif it's a plain string)
Example: Building a File Counter Tool
Step 0: Check for Existing Tools
{
"tool": "listGraphTools",
"arguments": {}
}
Step 1: Discover Available MCP Servers and Tools
{
"tool": "listMcpServers",
"arguments": {}
}
{
"tool": "listMcpServerTools",
"arguments": {
"serverName": "filesystem"
}
}
{
"tool": "getMcpServerTool",
"arguments": {
"serverName": "filesystem",
"toolName": "list_directory"
}
}
Step 2: Test MCP Tool and Understand Output Structure
{
"tool": "testMcpTool",
"arguments": {
"server": "filesystem",
"tool": "list_directory",
"args": {
"path": "/path/to/test/directory"
}
}
}
This returns the actual output structure. For example, if it returns:
{
"output": {
"content": "[FILE] file1.txt\n[FILE] file2.txt\n[FILE] file3.txt\n"
},
"executionTime": 15
}
Now you know the output structure and can use it in expressions.
Step 3: Test Expressions with Actual Output Structure
{
"tool": "testJSONata",
"arguments": {
"expression": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }",
"context": {
"list_directory_node": {
"content": "[FILE] file1.txt\n[FILE] file2.txt\n[FILE] file3.txt\n"
}
}
}
}
Step 4: Test Complete Tool Definition (from source)
Test your tool definition using runGraphTool with toolDefinition:
{
"tool": "runGraphTool",
"arguments": {
"toolDefinition": {
"name": "count_files",
"description": "Counts files in a directory",
"inputSchema": {
"type": "object",
"properties": { "directory": { "type": "string" } },
"required": ["directory"]
},
"outputSchema": {
"type": "object",
"properties": { "count": { "type": "number" } }
},
"nodes": [
{
"id": "entry",
"type": "entry",
"next": "list_directory_node"
},
{
"id": "list_directory_node",
"type": "mcp",
"server": "filesystem",
"tool": "list_directory",
"args": {
"path": { "expr": "$.entry.directory" }
},
"next": "count_files_node"
},
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
},
{
"id": "exit",
"type": "exit"
}
]
},
"arguments": {
"directory": "/path/to/directory"
},
"logging": true
}
}
Step 5: Add Tool to Graph
Once validated, use addGraphTool with the exact same tool definition from Step 4:
{
"tool": "addGraphTool",
"arguments": {
"tool": {
/* SAME tool definition from Step 4 */
"name": "count_files",
"description": "Counts files in a directory",
"inputSchema": {
"type": "object",
"properties": {
"directory": {
"type": "string"
}
},
"required": ["directory"]
},
"outputSchema": {
"type": "object",
"properties": {
"count": {
"type": "number"
}
}
},
"nodes": [
{
"id": "entry",
"type": "entry",
"next": "list_directory_node"
},
{
"id": "list_directory_node",
"type": "mcp",
"server": "filesystem",
"tool": "list_directory",
"args": {
"path": { "expr": "$.entry.directory" }
},
"next": "count_files_node"
},
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
},
{
"id": "exit",
"type": "exit"
}
]
}
}
}
Step 6: Verify Tool in Graph (Recommended)
Test the tool again, but now using the tool name (running from the graph, not from source):
{
"tool": "runGraphTool",
"arguments": {
"toolName": "count_files",
"arguments": {
"directory": "/path/to/directory"
},
"logging": true
}
}
This verifies:
- The tool was saved correctly to the graph
- The tool works when called from the graph (not just from source)
- Results match Step 4, confirming consistency
Resources
- JSONata Documentation: https://jsonata.org/
- JSON Logic Documentation: https://jsonlogic.com/
- MCP Specification: https://modelcontextprotocol.io/
Repository
