{"ok":true,"site":{"host":"web-mcp-flow.vercel.app","url":"https://web-mcp-flow.vercel.app/","type":"live","desc":"EasyFloww","tools":[{"name":"get_flow_state","kind":"answer","impl":"imperative","description":"Return the currently active/visible flow as { flow, nodes, edges } — this is one tab only, not every flow. `flow` is { id, name }. Each node has id, type, label, config (type-specific fields like description / condition / variant), and position {x,y}. A node the user has selected on the canvas also has `selected: true` — use it as the anchor when the user refers to \"the selected node\" (there may be none, or more than one). Each edge has id, source, target, and sourceHandle/targetHandle (sourceHandle is \"yes\" or \"no\" for edges leaving a decision node, otherwise null). Call this first and after any change to see current state. Valid node types: \"start_end\" (rounded pill; data.variant is \"start\" or \"end\"), \"process\" (rectangle; optional data.description), \"decision\" (diamond; optional data.condition; has two source handles \"yes\" and \"no\"), \"io\" (parallelogram; optional data.description), \"note\" (dashed box, annotation only — cannot be connected).","inputSchema":{"type":"object","properties":{},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"add_node","kind":"act","impl":"imperative","description":"Add a new node to the active flow. Valid node types: \"start_end\" (rounded pill; data.variant is \"start\" or \"end\"), \"process\" (rectangle; optional data.description), \"decision\" (diamond; optional data.condition; has two source handles \"yes\" and \"no\"), \"io\" (parallelogram; optional data.description), \"note\" (dashed box, annotation only — cannot be connected). `label` is the visible title. Placement, in priority order: (1) explicit `position` {x,y} in canvas coords; (2) `near` (a node id) with optional `direction` (\"below\" default | \"above\" | \"left\" | \"right\") — placed one step from that node and nudged clear of overlaps; (3) if neither is given and exactly one node is selected, placed below the selected node; (4) otherwise the canvas origin. Returns { success, nodeId }, or { success: false, error } if `near` refers to a missing node. All canvas tools act on the currently active/visible flow tab only, never other tabs.","inputSchema":{"type":"object","properties":{"type":{"type":"string","enum":["start_end","process","decision","io","note"]},"label":{"type":"string"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"near":{"type":"string"},"direction":{"type":"string","enum":["below","above","left","right"]}},"required":["type","label"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"connect_nodes","kind":"act","impl":"imperative","description":"Draw a directed edge from one node to another (source → target) in the active flow. For a decision node source, pass sourceHandle \"yes\" or \"no\" to pick the branch; leave it out for any other node type. Note nodes cannot be connected. If either node id no longer exists the call returns { success: false, error } rather than throwing. Returns { success: true } on success.","inputSchema":{"type":"object","properties":{"sourceId":{"type":"string"},"targetId":{"type":"string"},"sourceHandle":{"type":"string","enum":["yes","no"]}},"required":["sourceId","targetId"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"move_node","kind":"act","impl":"imperative","description":"Reposition a node in the active flow. `position` is absolute canvas coordinates {x,y} (same space as get_flow_state positions and node width/height ~160–200px). Returns { success: false, error } if the node id does not exist, otherwise { success: true }.","inputSchema":{"type":"object","properties":{"nodeId":{"type":"string"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]}},"required":["nodeId","position"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"update_node_config","kind":"act","impl":"imperative","description":"Merge fields into a node's data in the active flow. Use \"label\" to rename; \"description\" for process/io; \"condition\" for decision (the text shown under the diamond, e.g. \"latency > 2s\"); \"variant\" (\"start\" or \"end\") for start_end; \"borderColor\" to tint a node's border as a persistent marker — a CSS colour string, or one of \"red\" / \"amber\" / \"green\" / \"blue\" / \"purple\" (pass null to clear; a malformed colour is ignored). e.g. after evaluating a rule, set { borderColor: \"red\" } on the decision node. Only the keys you pass are changed. Returns { success: false, error } if the node id does not exist, otherwise { success: true }.","inputSchema":{"type":"object","properties":{"nodeId":{"type":"string"},"config":{"type":"object","additionalProperties":true}},"required":["nodeId","config"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"delete_node","kind":"transact","impl":"imperative","description":"Remove a node and every edge attached to it, in the active flow. Returns { success: false, error } if the node id does not exist, otherwise { success: true }.","inputSchema":{"type":"object","properties":{"nodeId":{"type":"string"}},"required":["nodeId"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"insert_node_between","kind":"act","impl":"imperative","description":"Insert a new node onto an existing edge, splitting it. `sourceId` and `targetId` MUST already be joined by a direct edge in that direction (source → target) — this tool removes that edge and reconnects source → newNode → target. The original edge's decision handle (\"yes\"/\"no\"), if any, is preserved on the source → newNode edge. The new node is placed at the midpoint of the two. Takes node IDs, not labels: call get_flow_state first to resolve a label like \"check auth\" to its id, and to read edge directions. Valid node types: \"start_end\" (rounded pill; data.variant is \"start\" or \"end\"), \"process\" (rectangle; optional data.description), \"decision\" (diamond; optional data.condition; has two source handles \"yes\" and \"no\"), \"io\" (parallelogram; optional data.description), \"note\" (dashed box, annotation only — cannot be connected). Returns { success: true, newNodeId }, or { success: false, error } with a specific reason (\"... does not exist\" vs \"no direct edge from sourceId to targetId\").","inputSchema":{"type":"object","properties":{"sourceId":{"type":"string"},"targetId":{"type":"string"},"newNodeType":{"type":"string","enum":["start_end","process","decision","io","note"]},"newNodeLabel":{"type":"string"}},"required":["sourceId","targetId","newNodeType","newNodeLabel"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"remove_edge","kind":"act","impl":"imperative","description":"Delete one edge by its id, disconnecting the two nodes it joined (both nodes stay). Edge ids come from get_flow_state. Returns { success: true }, or { success: false, error } if no edge has that id.","inputSchema":{"type":"object","properties":{"edgeId":{"type":"string"}},"required":["edgeId"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"export_flow_as_png","kind":"act","impl":"imperative","description":"Export the currently active/visible flow as a PNG image and trigger a browser download of it. The filename is derived from the tab name (e.g. \"onboarding-flow.png\"). The image contains only the diagram — no sidebar, tabs, or other app chrome — on a solid background, framed to fit the whole flow. Returns { success: true, filename }, or { success: false, error } if the flow is empty, an export is already running, or the browser blocks the download.","inputSchema":{"type":"object","properties":{},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"clone_flow","kind":"act","impl":"imperative","description":"Duplicate a flow into a new tab and switch to it. `flowId` is OPTIONAL — omit it to clone the currently active/visible flow (the common case). Optional `newFlowName` sets the new tab name; the default is \"Copy of <original name>\". The clone is a fully independent copy: every node, edge, label, condition, description, position and handle is duplicated with fresh IDs, so later edits to the clone (by you or the user) never affect the original and vice versa. Use this for \"try an alternative version of this flow\" style requests. Returns { success: true, newFlowId, newFlowName }, or { success: false, error } if an explicitly given flowId does not exist.","inputSchema":{"type":"object","properties":{"flowId":{"type":"string"},"newFlowName":{"type":"string"}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"}],"category":"Productivity & Business","favicon":"/favicons/web-mcp-flow.vercel.app.svg","apiSurface":"spec","toolCount":10}}