Skip to main content
Glama

ComfyUI-AIAssistant

Let a local AI assistant see what is selected on your ComfyUI canvas — and, on explicit request, insert text into it.

Every browser tab publishes a bounded snapshot of the current node selection to the ComfyUI process over a same-origin WebSocket. The snapshot lives in RAM and is served to any local consumer over HTTP or MCP. One narrow write tool, set_widget_text, can insert text into a text-like widget of the selected node, guarded by concurrency checks.

No chat UI, no AI service calls, no workflow nodes, no runtime dependencies.

Highlights

  • Selection context for agents — ask "how should I configure the selected node?" and get an answer grounded in the live widget values, input/output slots and connections.

  • MCP server built in — one URL, no extra process: POST /mcp speaks a stateless subset of MCP Streamable HTTP (verified live with Claude Code and OpenCode).

  • Multi-tab aware — every tab is a page in a bounded registry; the active page follows window focus and carries a label (AI-XXXX) shown at the top of the tab, so you and the agent always name the same tab.

  • Read-only by design, one narrow carve-out — the only mutation the plugin can perform is writing text into one text-like widget of the selected node on the active page, on an explicit MCP request, guarded by revision and page-identity checks. On the canvas the edit behaves exactly like a manual widget edit: undo works, the workflow becomes dirty.

  • Private by construction — RAM-only storage, no persistence, no telemetry, no outbound network requests, no payload logging; secret-like widget names are redacted before the snapshot leaves the page.

Related MCP server: ComfyUI MCP Server

Requirements

  • ComfyUI with the current frontend (developed and verified against ComfyUI 0.33.3, frontend 1.50.6, aiohttp 3.14, Python 3.13).

  • Python ≥ 3.10.

  • No additional Python or Node packages.

Install

cd <ComfyUI>/custom_nodes
git clone https://github.com/alksef/ComfyUI-AIAssistant.git

Restart ComfyUI. Once the frontend loads, each tab shows its page label (for example AI-6DEF) at the top center of the window — that label identifies the tab in the context envelope below.

Connect an MCP client

The endpoint is http://127.0.0.1:8188/mcp — the ComfyUI port, Streamable HTTP transport, stateless. Adjust the host/port if your ComfyUI listens elsewhere.

Claude Code

claude mcp add --transport http comfyui http://127.0.0.1:8188/mcp

Then ask: "what is selected in ComfyUI?" — Claude reads it through get_selection.

OpenCode

In opencode.json:

{
  "mcp": {
    "comfyui": {
      "type": "remote",
      "url": "http://127.0.0.1:8188/mcp"
    }
  }
}

Any MCP client (or plain curl)

curl -s http://127.0.0.1:8188/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"get_selection","arguments":{}}}'

Supported methods: initialize, tools/list, tools/call, ping. Notifications get 202 Accepted; GET/DELETE get 405 Allow: POST; bodies are capped at 64 KiB. No sessions, no SSE — one JSON-RPC message per POST.

Tools

get_selection

Read-only, no arguments. Returns the context envelope (below) as compact JSON in content[0].text. An absent snapshot (available: false) is a normal result: no tab has published yet.

set_widget_text

Inserts text into widget of the currently selected node on the active page. All four parameters are required:

Parameter

Type

Meaning

widget

string

Exact widget name as get_selection reports it

text

string

Text to insert (≤ 8192 chars)

expected_revision

integer

Revision you last saw — forces a read before a write

expected_page

string

active_page.page_id you last saw

The revision and page checks make writes safe against a stale plan: if the user edited something or switched tabs between your read and your write, the call is refused with the current revision so you can re-read and retry.

Results (content[0].text, compact JSON):

  • success — {"status":"applied","revision":<new>,"widget":<name>} when the page confirmed the edit within the bounded wait (≈3 s), or {"status":"queued",...} when the command was dispatched but no confirmation arrived in time;

  • refusal (isError: true) — invalid params …, no selection available, no node selected, multiple nodes selected, unknown widget, widget is not text-like, no active page, active page changed, revision mismatch (the last two carry current_revision for a cheap retry).

Only text-like widgets (type text, customtext or string) of a singly selected node can be written. Nothing else mutates: no queue, no graph structure, no settings, no files.

HTTP API (for scripts and debugging)

All responses carry Cache-Control: no-store. Bodies are capped at 128 KiB.

  • GET /ai-assistant/context — the context envelope. Poll this per question if your consumer is not an MCP client.

  • POST /ai-assistant/context — anonymous snapshot channel: submit a normalized snapshot object (schema_version, captured_at, revision, workflow, selection) exactly as the frontend builds it; useful for testing consumers without a browser. Does not create registry pages.

  • WS /ai-assistant/ws — the frontend channel (below).

Context envelope

{
  "schema_version": "comfyui.ai-assistant.context/1",
  "available": true,
  "received_at": "2026-08-29T12:00:00.123456+00:00",
  "snapshot": {
    "schema_version": "comfyui.ai-assistant.context/1",
    "captured_at": "2026-08-29T12:00:00.120000+00:00",
    "revision": 7,
    "workflow": {
      "id": "9",
      "title": "ace_step remix",
      "selected_count": 1,
      "selection_detail": "full",
      "selected_limit": 1,
      "selection_truncated": false
    },
    "selection": [
      {
        "id": "107",
        "comfyClass": "CLIPTextEncode",
        "title": "Song Tags",
        "type": "CLIPTextEncode",
        "mode": 0,
        "widgets": [
          { "name": "text", "type": "text", "value": "K-Pop Girl Group, …",
            "truncated": false, "redacted": false, "unsupported": false }
        ],
        "inputs": [
          { "name": "clip", "type": "CLIP",
            "link": { "link_id": "42", "origin_id": "11", "origin_slot": 0,
                      "target_id": "107", "target_slot": 0, "type": "CLIP" } }
        ],
        "outputs": [
          { "name": "CONDITIONING", "type": "CONDITIONING", "links": [] }
        ]
      }
    ]
  },
  "pages": [
    { "page_id": "6def0a1b-2c3d-4e5f-8a9b-0c1d2e3f4a5b",
      "page_label": "AI-6DEF", "workflow_name": "ace_step remix",
      "connected": true }
  ],
  "active_page": { "page_id": "6def0a1b-…", "page_label": "AI-6DEF", "connected": true }
}

Notes:

  • selection_detail is full for a single selection, names_only for a multiple selection (bounded node names, no ids/params/widgets/links), none for an empty selection — an empty selection is a valid snapshot.

  • revision grows monotonically per page on every published change; use it with page_id for the set_widget_text checks.

  • Values are bounded and normalized: strings over 512 chars truncate to <truncated>, non-JSON shapes become <unsupported>, and widget names containing terms like password, token, api_key are reported with "<redacted>" values.

  • active_page is the most recently focused connected tab; when it disconnects, the next remaining tab takes over immediately (socket liveness — no timeouts).

WebSocket channel (frontend ↔ server)

JSON text frames, one object per frame. The frontend sends register ({type, page_id}), snapshot ({type, page_id, snapshot} — the normalized snapshot object), activate ({type, page_id}, on focus and visibility change), and receives registered / accepted (with the revision) / activated acks, error frames that never close the socket, and command frames {type: "command", command_id, op: "set_widget_text", widget, text} carrying the write. The registry holds at most 8 pages; disconnected pages are evicted first.

Security and privacy boundary

  • The plugin stores snapshots only in process memory and never writes them to disk, never logs them, never echoes them anywhere except to the asking consumer.

  • The plugin makes no outbound network requests. The WebSocket is same-origin inbound; consumers pull context.

  • Secret-like widget names are redacted in the frontend before the snapshot leaves the page; values never travel for them.

  • The endpoints ride the ComfyUI port and are reachable wherever ComfyUI is reachable — including LAN exposure if you run ComfyUI that way. They expose exactly the bounded selection snapshot and the one guarded write; there is no authentication, so treat the port as trusted (default: localhost).

  • The only mutation surface is the set_widget_text carve-out described above. AGENTS.md records this boundary for contributors.

Limitations

  • Writes target text-like widgets only, a single selection only, the active page only.

  • "queued" means dispatched without confirmation in the bounded wait — check the revision or re-read before retrying; a concurrent manual edit can also advance the revision and be reported as "applied".

  • The MCP subset is stateless by design: no sessions, no SSE streams, no server-initiated notifications, no batching.

Development

python -m unittest discover -s tests -v   # backend (needs aiohttp)
ruff check ai_assistant tests             # lint
ruff format --check ai_assistant tests    # format
npm test                                  # frontend (node:test)

The backend core (pages, commands, mcp_protocol) is stdlib-only and fully testable offline; server.py is covered through aiohttp test utilities. Design decisions and their history live in docs/roadmaps/.

License

MIT — see LICENSE.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alksef/ComfyUI-AIAssistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server