Skip to main content
Glama
fancy-flow-mcp-js

fancy-flow-mcp-js

@particle-academy/fancy-flow-mcp-js

Fancified

MCP server that lets an agent author fancy-flow workflows headlessly on a TypeScript host — the Node twin of fancy-flow-mcp (Laravel).

Same 15 tools, same names, same arguments. An agent that learned to build graphs against the PHP server drives this one without relearning anything — and that claim is asserted by a test that reads the PHP source, not maintained by hand.

npx @particle-academy/fancy-flow-mcp-js

The split it is built around

We own whether a graph is well-formed; the host owns whether it is allowed to run.

Every issue crosses the wire tagged with which of those refused it:

{ "source": "schema", "level": "error",   "message": "message: Message is required", "nodeId": "log-1" }
{ "source": "host",   "level": "error",   "message": "This host cannot resume a paused run.", "nodeId": "ask-1" }

Those have different remedies — one is fixed by editing the graph, the other by granting a capability or picking another kind. Collapsing them costs an author real time chasing the wrong fix, so they are never merged.

Related MCP server: Orchestration MCP

Two entry points

Import

What it costs

Use it when

@particle-academy/fancy-flow-mcp-js/authoring

nothing beyond fancy-flow

You want graph authoring and validation, no server

@particle-academy/fancy-flow-mcp-js

+ @particle-academy/agent-integrations

You want an MCP server

The core was written first and deliberately depends on nothing, so a host that only wants to build and validate graphs never pays for a server it will not use.

No third-party runtime code, and no React. The server is agent-integrations' first-party MicroMcpServer, imported from its headless /mcp subpath, which imports no package at all. (Until 0.2.0 it was @modelcontextprotocol/sdk — see the changelog for what changed and what did not.)

Use it from a host

import { createFlowServer, MemoryDraftStore } from "@particle-academy/fancy-flow-mcp-js";
import { attachStdio } from "@particle-academy/agent-integrations/mcp/stdio";

const server = createFlowServer({
  store: new MemoryDraftStore(),

  // Your answer to "may I run this kind here?". Return a string to REFUSE —
  // and name the missing capability, because a refusal an author can act on is
  // worth more than a correct one they cannot.
  admits: (kind) =>
    kind.name.includes("terminal") ? "This host has no terminal sessions." : null,
});

attachStdio(server); // stdin/stdout; log to stderr, never stdout

Importing @particle-academy/agent-integrations yourself? Declare it in your own dependencies (>=0.45 <2.0) rather than relying on this package to bring it.

There is no need to call registerBuiltinKinds(): the kind registry fills itself on first read. It is also the wrong import for a headless host — @particle-academy/fancy-flow/registry pulls in React.

createFlowServer returns a transport-agnostic server. For anything other than stdio, attach any agent-integrations transport, or implement its two-member Transport (send, optional close) and hand each incoming frame to server.receive(transport, frame).

MemoryDraftStore is a convenience. Implement DraftStore (list / get / save / remove, sync or async) against your own storage and drafts survive a restart — this package never persists anything itself.

The tools

create_workflow list_workflows get_workflow delete_workflow

Drafts

add_node remove_node configure_node

Nodes

connect_nodes remove_edge

Edges

list_node_kinds describe_node_kind

The vocabulary

validate_workflow export_workflow import_workflow

Checking and portability

run_workflow

A smoke test of wiring — see below

list_node_kinds reads the live registry, so kinds a host registered itself and kinds vendored from the marketplace are included. It is not a fixed list.

configure_node writes a config that fails validation and reports warnings rather than refusing. A half-configured node is a normal intermediate state when an agent builds a graph one step at a time; validate_workflow is the place that says "not finished".

run_workflow — read this before relying on it

It is a smoke test of wiring and routing, not a production run.

It takes no executor argument, and the executor registry is bound as a literal at the call site — the same shape the PHP twin uses. An agent-reachable run is structurally incapable of being pointed at your real infrastructure. Unrepresentable beats forbidden: a policy can be relaxed by a later edit; an absent parameter cannot be passed.

Two honest limits:

  1. 9 of 31 builtin kinds have a TypeScript executor. The PHP twin's Builtin::executors() covers every kind; the TS runtime has no equivalent yet. The other 22 return ok: false with "No executor registered" — a true answer about this runtime, delivered as a result rather than an error. A test pins the count so the day it improves, this paragraph is forced to change.

  2. Kind-level executors still apply. A host process that has called registerTerminalHost or registerLlmClient makes those reachable from here. That is your doing, not this package's, and it is said plainly rather than papered over.

Protocol revision

Speaks 2025-11-25, negotiating back to 2024-11-05 — the same family laravel/mcp speaks, which is what the PHP twin is built on, and what Claude Code and Codex speak. initialize echoes any of those a client asks for and answers 2025-11-25 otherwise.

It does not speak 2026-07-28, the revision that removed initialize and made the protocol stateless. Neither does the PHP twin. If you need to be reached by a 2026-07-28-only client, that gap is open and belongs to both twins together — a Node server that jumped ahead alone would stop being a twin.

Licence

MIT

Available Tools

15 tools
add_nodeAdd NodeA

Add a node of a given kind to a workflow. The kind is checked against the live registry (call list_node_kinds first — a host may have registered its own). Omitting config applies the kind's schema defaults. Pass parent_id to place the node inside a lane. Returns the created node.

NameRequiredDescriptionDefault
kindYesNode kind, e.g. "manual_trigger", "llm_call", "branch".
configNoOptional config. See describe_node_kind for the fields.
node_idNoOptional explicit node id. Omit to auto-generate.
parent_idNoOptional lane node id — puts this node inside that lane.
workflow_idYesThe workflow id from create_workflow.
configure_nodeConfigure NodeA

Merge config into a node, keeping the kind's other defaults. A config that does not satisfy the kind's schema is WRITTEN ANYWAY and reported as warnings — a half-configured node is a normal intermediate state when building a graph one step at a time, and refusing the write makes it impossible to get there. validate_workflow is where 'not finished' is said.

NameRequiredDescriptionDefault
configYesFields to merge into the node's config.
node_idYesThe node to configure.
workflow_idYesThe workflow id.
connect_nodesConnect NodesA

Draw an edge from one node's output port to another's input port. Omit the port names to use each kind's defaults. Both nodes must already exist — connecting to a node that is not there is an error rather than a promise to create it.

NameRequiredDescriptionDefault
sourceYesSource node id.
targetYesTarget node id.
source_portNoOptional output port on the source, e.g. "true" on a branch.
target_portNoOptional input port on the target.
workflow_idYesThe workflow id.
create_workflowCreate WorkflowA

Start a new, empty workflow draft and return its workflow_id. Every other tool takes that id. Nothing is persisted beyond the host's store, and creating a workflow never runs anything.

NameRequiredDescriptionDefault
nameYesHuman-readable name for the workflow, e.g. "Nightly digest".
workflow_idNoOptional explicit id. Omit to have one minted.
delete_workflowDelete WorkflowA

Remove a workflow draft from this host's store. Irreversible on a store that does not version, and it deletes only the draft — nothing that was already exported or run.

NameRequiredDescriptionDefault
workflow_idYesThe workflow id to delete.
describe_node_kindDescribe Node KindA

One kind in full — its config schema, its default config, and its input and output ports. Call this before configure_node rather than guessing field names; the fields are deliberately not on list_node_kinds, which would turn a vocabulary query into a payload nobody reads.

NameRequiredDescriptionDefault
kindYesThe kind name, e.g. "llm_call" or the fully-qualified form.
export_workflowExport WorkflowA

Emit the portable WorkflowSchema document — the same JSON the TypeScript, PHP and Python runtimes all read. This is what you hand to another runtime, commit to a repo, or pass to import_workflow.

NameRequiredDescriptionDefault
workflow_idYesThe workflow id.
get_workflowGet WorkflowA

Return one workflow's full graph — every node with its kind, config and parentId, and every edge. This is the authoring view; use export_workflow for the portable WorkflowSchema document.

NameRequiredDescriptionDefault
workflow_idYesThe workflow id from create_workflow.
import_workflowImport WorkflowA

Read a WorkflowSchema document into a NEW draft and return its workflow_id, plus any issues found. Import is lenient on purpose: a document referencing a kind this host has not registered still imports, with the problem reported — refusing would lose the other forty nodes to fix one.

NameRequiredDescriptionDefault
nameNoOptional name for the imported draft.
workflowYesA WorkflowSchema document, as export_workflow emits.
workflow_idNoOptional explicit id for the new draft.
list_node_kindsList Node KindsA

Every node kind this host has registered, read from the LIVE registry rather than a fixed list — so kinds the host added itself, and kinds vendored in from the marketplace, are included. Each says whether this host ADMITS it, and a refusal names the missing capability.

NameRequiredDescriptionDefault
categoryNoOptional filter, e.g. "logic", "ai", "io", "trigger".
list_workflowsList WorkflowsA

List every workflow draft this host is holding, with node and edge counts. Use it to recover a workflow_id you did not keep, before creating a duplicate.

NameRequiredDescriptionDefault

No parameters

remove_edgeRemove EdgeA

Remove one edge, named either by its edge id or by the source/target pair it connects. Removing an edge never removes the nodes it joined.

NameRequiredDescriptionDefault
sourceNoSource node id, if naming the edge by its endpoints.
targetNoTarget node id, if naming the edge by its endpoints.
edge_idNoThe edge id, if you have it.
workflow_idYesThe workflow id.
remove_nodeRemove NodeA

Remove a node and every edge touching it. The edges go WITH the node deliberately — leaving them would produce edges pointing at nothing, reported as a second error the author did not cause.

NameRequiredDescriptionDefault
node_idYesThe node to remove.
workflow_idYesThe workflow id.
run_workflowRun WorkflowA

Execute the graph and return per-node outputs plus ok/error. This is a SMOKE TEST of wiring and routing, not a production run: it takes no executors, so nodes fall back to their kind's own behaviour and anything needing a host capability (a terminal session, an LLM client) refuses rather than acting. Refuses outright to run a graph with validation errors, because a malformed graph produces failures that look like engine bugs and are not. Seed entry nodes with initial_inputs, keyed by node id then port.

NameRequiredDescriptionDefault
workflow_idYesThe workflow id.
initial_inputsNoInputs seeded to entry nodes: { "<node_id>": { "<port>": <value> } }.
validate_workflowValidate WorkflowA

Check a workflow and return every issue TAGGED by who refused it: source "schema" means the graph is malformed and editing it is the fix; source "host" means this host will not run that kind and the fix is a capability or a different kind. Collapsing the two costs you the wrong fix.

NameRequiredDescriptionDefault
workflow_idYesThe workflow id.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 15 tool updatesv0.1.0
    • First observedadd_node
    • First observedconfigure_node
    • First observedconnect_nodes
    • First observedcreate_workflow
    • First observeddelete_workflow
    • First observeddescribe_node_kind
    • First observedexport_workflow
    • First observedget_workflow
    • First observedimport_workflow
    • First observedlist_node_kinds
    • First observedlist_workflows
    • First observedremove_edge
    • First observedremove_node
    • First observedrun_workflow
    • First observedvalidate_workflow

TDQS

A4.3/5.0

Scored across 15 tools

Disambiguation5/5

Every tool maps to one distinct operation: workflow-level CRUD, node editing, edge editing, node-kind introspection, validation, import/export, and smoke-test running. The close pairs like get_workflow/export_workflow and list_node_kinds/describe_node_kind are explicitly differentiated. No two tools appear to do the same job.

Naming Consistency5/5

All tools follow a consistent snake_case verb_noun pattern: list_, create_, get_, delete_, add_, remove_, configure_, connect_, describe_, validate_, export_, import_, and run_. The object nouns are predictable and consistent. There is no mixed casing or vague verb usage.

Tool Count5/5

Fifteen tools sits at the upper boundary of ideal, but each tool earns its place in the workflow-authoring lifecycle. There are no duplicate or filler tools, and the count matches the apparent domain richness. It feels intentionally scoped rather than bloated.

Completeness5/5

The server covers workflow CRUD, node editing, edge editing, node-kind introspection, validation, portable import/export, and a run smoke test. Every editing operation has a corresponding read or delete path, and get_workflow/export_workflow provide both authoring and portable views. The declared out-of-scope production execution is a deliberate boundary, not a gap.

Maintenance

ActivityActive
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    A TypeScript MCP server for launching, tracking, and managing external coding-agent runs across local and remote backends like Codex and Claude Code. It allows top-level agents to orchestrate subagents through tools for spawning tasks, polling events, and handling interactive sessions.
    7
    2
    -
  • A
    license
    D
    quality
    D
    maintenance
    A TypeScript MCP server demo supporting local Stdio and remote Streamable HTTP, demonstrating tool invocation for AI agents.
    2
    1
    MIT