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.
This skill teaches you how to use the mcpGraphToolkit MCP server to build, debug, test, run, and manage graph tools in 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:
When to use mcpGraph:
What you should do:
listMcpServers and listMcpServerTools to discover available MCP servers and toolsgetMcpServerTool to get MCP server tool details and schemasaddGraphTool to add graph tools to the mcpGraph (it handles file operations automatically)updateGraphTool and deleteGraphTool to manage graph toolsrunGraphTool to run a graph tool or to test a graph tool before adding itlistGraphTools and getGraphTool to discover and examine existing graph tools, especially when considering creating a new graph toolDO 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.
Important: Understanding the distinction between MCP servers/tools and graph tools is critical.
listMcpServers)listMcpServerTools and getMcpServerTool)listMcpServers and listMcpServerTools to see what's available before building graph toolsrunGraphToollistGraphToolsKey Points:
listMcpServers first)listGraphTools and getGraphTool)runGraphToolA 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:
Entry point that receives tool arguments. Required in every graph tool.
id: Node identifier (typically "entry")type: "entry"next: ID of the first worker nodeOutput: Tool input arguments (passed through as-is)
{
"id": "entry",
"type": "entry",
"next": "list_directory_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 via listMcpServers)tool: Tool name (must be available via listMcpServerTools)args: Arguments (values starting with $ are evaluated as JSONata)next: ID of the next nodeOutput: 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.
Applies JSONata expressions to transform data.
id: Node identifiertype: "transform"transform.expr: JSONata expression (string)next: ID of the next nodeOutput: Result of evaluating the JSONata expression
{
"id": "count_files_node",
"type": "transform",
"transform": {
"expr": "{ \"count\": $count($split($.list_directory_node.content, \"\\n\")) }"
},
"next": "exit"
}
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 point that returns the final result. Required in every graph tool.
id: Node identifier (typically "exit")type: "exit"next field - execution ends hereOutput: Output from the previous node in execution history
{
"id": "exit",
"type": "exit"
}
Critical Rules:
id: "entry")id: "exit")next field pointing to the first worker nodenext field (execution ends here)"mcp" (NOT "mcp-tool", "mcp-tool-call", or any other variant)inputSchema and outputSchema (both must be object type)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 provides 12 tools organized into categories:
getGraphServer: Get full details of the mcpGraph server metadata (name, version, title, instructions)listGraphTools: List all graph tools in the mcpGraph (name and description)
getGraphTool: Get full detail of a graph tool from the mcpGraph (including complete node definitions)
listMcpServers: List all MCP servers available to the graph (name, title, instructions, version)
listMcpServerTools: List tools from MCP servers available to the graph (name/description only), optionally filtered by MCP server name
getMcpServerTool: Get full MCP server tool details (including input and output schemas)
addGraphTool: Add a new tool to the mcpGraphupdateGraphTool: Update an existing tool in the mcpGraphdeleteGraphTool: Delete a tool from the mcpGraphrunGraphTool: Run an exported tool from the mcpGraph. Can specify existing tool name or run a tool definition supplied in payload. Supports optional logging collection.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 behaviorA graph is a directed sequence of nodes that execute in order. Execution flow:
next fieldsNodes 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"
}
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 ID node_id$.entry.paramName - Accesses a parameter from the entry nodeThe context is a flat structure: { "node_id": output, ... }
mcpGraph uses two expression languages: JSONata for data transformation and JSON Logic for conditional routing.
JSONata is used in three places:
transform.expr) - Transform data between nodes$ is evaluated as JSONatavar operations - Access context data in switch node conditionsBasic Syntax:
$.node_id.property or $.entry.paramName{ "key": value }$count(array), $split(string, delimiter), etc.condition ? trueValue : falseValueHistory 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 outputExamples:
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 is used in switch node conditions for conditional routing.
Basic Syntax:
{ ">": [a, b] }, { "<": [a, b] }, { "==": [a, b] }{ "and": [rule1, rule2] }, { "or": [rule1, rule2] }, { "!": rule }{ "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.
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.
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
getMcpServerTool - Check the tool's outputSchema to understand the expected structuretestMcpTool - Test the tool directly to see its actual output (recommended)runGraphTool with logging - Run a minimal graph with just entry → mcp → exit and check executionHistorytestMcpToolThe 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:
output matches what would be available in a graph node's execution contextgetMcpServerTool to understand the tool's outputSchema and expected output structureevaluatedArgs is included when JSONata expressions are used in args and context is providedexecutionTime shows how long the tool call took in millisecondsWhy 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.
IMPORTANT: Follow this workflow exactly. Do not skip steps or try to create files manually.
Check for Existing Graph Tools
listGraphTools to see if a graph tool already exists for your purposegetGraphTool to examine existing graph tools before creating new onesDiscover Available MCP Servers and Tools
listMcpServers to see MCP servers available to the graph (graph tools can only use these servers)listMcpServerTools to see MCP tools available on a server (graph tools can only call these tools)getMcpServerTool to get full tool details (input/output schemas)testMcpTool to understand tool behavior and output structure before using it in a graphTest Components
testMcpTool to test MCP tool calls and understand their output structuretestJSONata to test transform expressions (use actual MCP tool outputs from testMcpTool as context)testJSONLogic to test switch conditionsBuild Tool Definition
listMcpServers and listMcpServerToolsTest Tool Definition Before Adding
runGraphTool with toolDefinition to test the tool inline (testing from source)logging: true to see execution detailsAdd Tool to Graph
addGraphTool to add the tested tool to the graphVerify Tool in Graph (Recommended)
runGraphTool with toolName (the tool's name) to test it from the graphUpdate or Delete Tools
updateGraphTool to modify existing tools (do NOT edit configuration files directly)deleteGraphTool to remove tools (do NOT edit configuration files directly)When building or debugging graph tools, follow this systematic approach:
Test MCP Tools Individually
testMcpTool to call the MCP tool directly and see its output structureTest Expressions with Realistic Context
testMcpTool as context for testJSONata expressions$.fetch_url.content when the tool returns a plain stringBuild Incrementally
runGraphTool with logging: trueUse Debugging Tools
testMcpTool - Verify MCP tool calls work and understand output structuretestJSONata - Validate transform expressions before using themtestJSONLogic - Validate switch conditions before using themrunGraphTool with logging: true - See all execution steps and node outputsexecutionHistory - Inspect actual node outputs when debuggingExample: Debugging a Failed Transform
Error: "content": "expected string, received undefined"
Steps:
testMcpTool to see what the MCP tool actually returnstestJSONata with the actual output structure as context:
{
"tool": "testJSONata",
"arguments": {
"expression": "$.fetch_url.content",
"context": {
"fetch_url": "actual output from testMcpTool"
}
}
}
$.fetch_url if it's a plain string)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
<!-- Content truncated for initial SEO render. Open the source file tab for the full file. -->
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer