> ## Documentation Index
> Fetch the complete documentation index at: https://comfyui-mcp.artokun.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用工具

> 工具是什么，为什么你从不自己调用，以及它说不的时候该怎么办。写给人看，不是写给工程师看。

[工具参考](/docs/docs/tools/image-generation) 按 AI 阅读的形式列出这个项目能做的一切。本页是
给你看的版本。

<Note>
  这里不要求你写代码、打 JSON，或学一套 API。如果你曾经对人说过「打开我的肖像工作流，
  把步数调到 30」，你已经知道这个界面了。
</Note>

## 工具是智能体可以做的事，不是你要输入的东西

单靠自己，聊天模型只能产出文本。它可以描述一条工作流；它打不开一条。

**工具**是我们交给模型的、具体、有名字的动作，好让它真正够到你的 ComfyUI —— 加载文件、
把渲染入队、安装节点包、看刚出来的那张图。模型不能发明这些。它拿到一份固定菜单，菜单
上每一项都精确说明自己需要什么。

**你从不从那份菜单里挑。** 你用自然冒出来的词说想要什么，智能体来选。

| 你说                | 它悄悄跑的                                                       |
| ----------------- | ----------------------------------------------------------- |
| 「我存了些什么？」         | `get_workflow` with `action: "list"`                        |
| 「打开那个肖像的，告诉我它做什么」 | `get_workflow` with `action: "list"`，然后 `action: "analyze"` |
| 「给我做一只雪地里的红狐狸」    | `generate_image`（`image` 任务）                                |
| 「做好了吗？」           | `queue`（`list` 任务）                                          |
| 「失败了，我不明白为什么」     | `get_history`（`diagnose` 任务）                                |
| 「一半节点都是红的」        | `list_packs`（`install_deps` 任务）                             |
| 「磁盘满了，哪些大？」       | `list_local_models`                                         |

注意第二行：一句话，两个工具，顺序你不必知道。这就是整套安排的要点。你不需要知道找文件
和读文件是两步操作。

<Tip>
  你想多含糊都可以。「有东西坏了」就是很好的开头 —— 智能体会从
  `get_system_stats (action:"health")` 开始往下收。说得具体会更快，但从来不是必须的。
</Tip>

### 参考页里那些 JSON 是什么？

每个工具页都会展示这样一块：

```json theme={null}
{
  "tool": "generate_image",
  "arguments": {
    "prompt": "a red fox in deep snow, golden hour, sharp focus",
    "steps": 30
  }
}
```

那是智能体发出去的记录，不是给你的说明书。你说的是「给我做一只雪地里的红狐狸，细节再
多一点」；从另一头出来的就是这个。

值得能读懂一份，理由有两个：你想核对智能体是不是听懂了，以及出问题时你要跟别人描述。
不值得背下来。

## 工具来自两个地方

有两面，它们存在是因为回答的是不同问题。

<CardGroup cols={2}>
  <Card title="侧边栏面板" icon="window-maximize">
    住在 **ComfyUI 里面**，智能体标签页里。它的工具（`panel_*`）作用在你此刻看着的
    节点图上 —— 那块真实画布，带着你还没保存的改动。
  </Card>

  <Card title="外面的客户端" icon="terminal">
    Claude Desktop、Claude Code、编辑器、你的手机。它的工具作用在**服务器**上：磁盘
    上的文件、任务队列、模型、节点包、ComfyUI 进程本身。
  </Card>
</CardGroup>

分界其实是「这个」这个词。你说「给**这个**加一个 LoRA」时，面板知道「这个」是什么，
因为它看得见你的屏幕。外面的客户端看不见 —— 得告诉它一个文件名。

所以面板处理的是这类事：

* 读你眼前的节点图（`panel_graph_outline`）
* 跑它，就跟你自己按了 Queue Prompt 一模一样（`panel_run`）
* 接进一个节点、改一个控件、告诉你节点为什么变红（`panel_add_node`、`panel_set_widget`、`panel_get_errors`）
* 把整条工作流加载到画布上，或保存画布上现有的（`panel_load_workflow`、`panel_save_workflow`）

而外面的客户端处理的是从零生成一张图、管理模型和节点包、过一遍已保存的文件、重启
ComfyUI。

<Tip>
  **如果你是新手，用面板。** 一次安装，就在节点图旁边，也不需要单独的应用。见
  [面板指南](/docs/docs/zh/panel) 完成设置。等你想让智能体插手不是画布的事情时，再加外面的
  客户端。
</Tip>

它们不是对手 —— 面板在底下跟同一台服务器说话，一个会话可以两边都用。有人在桌面上改
节点图，同时手机驱动同一个会话，这是受支持的事，不是旁门。

## 一个工具，多项工作

你会注意到有些工具带一个 `action`：

```json theme={null}
{ "tool": "workspace", "arguments": { "action": "get" } }
```

这看起来像暗号，其实不是。`workspace` 是一个话题 —— *我们在说哪一份 ComfyUI 安装* ——
而 `action` 说你就这个话题问的是哪一个问题：读它、改默认、列出有什么。

读起来就跟日常说话一样，动词和宾语是分开的词：

| 你说               | 动作            |
| ---------------- | ------------- |
| 「我在用哪份 ComfyUI？」 | `get`         |
| 「以后一直用 D 盘那份」    | `set_default` |
| 「你能看见哪些安装？」      | `list`        |

### 没有删掉任何东西

这种形状还比较新，很容易读成能力被砍了。并没有，而这种误会值得正面先拦住，因为它已经
出现过。

以前是一个问题一个工具 —— 读工作区一个名字，设置另一个，列出再一个。那些名字没了，
如果你盯着工具数量看，会看见它在急剧下降。

实际发生的是相关工具被**合并**了，不是删除：

| The old name                    | The same thing today                        |
| ------------------------------- | ------------------------------------------- |
| `get_workspace`                 | `workspace` with `action: "get"`            |
| `get_queue`                     | `queue` with `action: "list"`               |
| `apps_run_status`               | `apps` with `action: "run_status"`          |
| `install_workflow_dependencies` | `list_packs` with `action: "install_deps"`  |
| `list_workflows`                | `get_workflow` with `action: "list"`        |
| `analyze_workflow`              | `get_workflow` with `action: "analyze"`     |
| `validate_workflow`             | `create_workflow` with `action: "validate"` |

底下的代码一样，行为一样，答案一样。只有前面的标签变了。

原因是菜单长到开始伤人。每个工具的完整描述都得在模型选择之前交给它，过了某个体量，
选择本身就会变差 —— 尤其是较小的模型，会开始挑一个看起来像邻居的，而不是对的那个。
更少、更宽、带着清楚 `action` 的工具，实测能修好这个。这也意味着模型把注意力花在你的
请求上，而不是读一份目录。

这些你都不该察觉。你以前也没打过旧名字；你说的是「我在用哪份 ComfyUI？」，这句话现在
仍然管用。

<Note>
  如果某份更旧的指南，或模型自己的记忆，伸手去够一个已经不存在的名字，你会拿到一条
  点名替代品的具体错误，而不是空白的「未知工具」—— 例如：*removed in 0.49.0. Call
  workspace (action:"get") instead.* 智能体通常能自己纠正并重试，你什么都不用做。
</Note>

## 想要不一样的结果

每个工具页都列出参数 —— `max_chars`、`limit`、`depth`、`fields`。你会合理地问它们该
打在哪，诚实的答案是：哪都不打。没有给 `max_chars` 的设置框，因为它不是一项设置。它是
**智能体**每次调用工具时当场填的参数。

这并不把你排除在外。它改的是控制长什么样：

<Note>
  你不设置参数。你开口要一个 —— 就写在你本来就要写的那句话里。
</Note>

### 两种问法

两种都管用。它们失败的方式不同，这是唯一需要两种都知道的理由。

|        | 听起来像                                                       | 什么时候用                     |
| ------ | ---------------------------------------------------------- | ------------------------- |
| **白话** | 「详细读节点 42 —— 只要那个节点，不要整张图。」                                | 永远从这里开始。这是人们实际会打的，而且通常管用。 |
| **显式** | 「用 `panel_query_graph`，`ids` 为 \[42]，`max_chars` 为 20000。」 | 模型已经错过一次，你想不给它留下余地。       |

点名工具和参数不是*正确*形式 —— 它是*强硬*形式。留给重试。

### 答案被截断时

长读取会封顶，免得一张巨大的节点图吞掉整段对话。两个不同的天花板可以停住同一次读取
—— 列出的节点数（`limit`）和字符预算（`max_chars`）—— 调高那个不是问题的，什么都
不会变，读起来就跟重试失败一模一样。

你不需要自己算是哪一个。在已保存的文件上，说明会**点名触发的那根杠杆，并排除另一根**，
原话就是这么说的：

> … truncated at 40 of 300 by `limit`=40 — raise `limit` up to 200, or narrow with `types`/`where`/`ids`/`depth`. `max_chars` is not the constraint here.

而当那根杠杆已经顶到天花板时，它会这么说，而不是再让你去调高，因为已经没什么可调了。

<Note>
  在实时画布上（`panel_query_graph`），同一次读取由面板自己那份引擎执行，它还没跟上
  那套措辞。如果那里的说明点名了一个参数，调高它却什么都没变，先试试另一根，再下结论
  说工具坏了。
</Note>

智能体本该读自己的说明并自己重试。它没这么做时，你就是后备，而这句话就是：

> 被截断了 —— 读那条说明，重试同一个查询，把它们点名的那个上限调高。

### 上限在哪里

这些是两个按预算读节点图的工具的数字 —— `panel_query_graph`（实时画布）和
`get_workflow` 配合 `action: "query"`（已保存的文件）：

| 参数             | 默认    | 你最多能要到 |
| -------------- | ----- | ------ |
| `max_chars`    | 12000 | 60000  |
| `limit`（列出的节点） | 40    | 200    |

在这两个工具上，要过天花板会被当成无效参数拒绝，而不是悄悄向下取整，所以智能体立刻
知道并能自己纠正。这些数字也不是通用的：另外几个工具也收 `max_chars`，并设自己的
天花板，写在那个工具自己的描述里。

### 范围比预算更管用

调高天花板是第二件该试的事，不是第一件。在一张 600 节点的工作流上，更大的预算多半只是
给你更多错的节点，把答案埋进几百个无关的里面，即使技术上装得下，回复也会变差。

先收窄，用任何自然的词：

| 你说              | 它收到哪       |
| --------------- | ---------- |
| 「只看节点 42 和 43。」 | 只有那些 id    |
| 「采样器吃进了什么？」     | 一个节点的上游一侧  |
| 「……只往回两跳。」      | 从那里算起的有界距离 |
| 「这里每种节点类型有多少？」  | 计数而不是列表    |

然后，如果还是被截断，再放宽。

## 当它说不

工具拒绝通常不是缺陷。大多数拒绝是护栏开火了，因为这次调用会做一件你没要求的事。

### 「它拒绝了，我不知道为什么」

你会看到白话，而不是堆栈跟踪 —— 点名它不肯做什么、改做什么。把它读成智能体在小心，
而不是卡住了。常见的诚实拒绝：

* **它分不清你说的是哪条工作流。** 打开了不止一个标签页，或节点图还没有已保存的身份。
  保存它，或说出是哪一个。
* **它会覆盖某些东西。** 要一个新文件名，它就会继续。
* **那东西确实不在。** 模型文件、节点包、正在跑的服务器。

如果一次拒绝读起来像胡话而不是谨慎，那就值得报告 —— 让智能体去提交，它会替你附上你的
环境细节。

### 「这个面板太旧了」

最常见、而且有真正修复的拒绝。读起来大致像：

> This ComfyUI-MCP panel is too old for *"…"* — update the ComfyUI-MCP panel, then reconnect.

侧边栏面板和这个服务器是分开出货的两块，所以一块可以落后于另一块。服务器要的东西，
已安装的面板没法安全做到时，它会拒绝而不是猜 —— 一块旧面板如果没法确认命令会落到
*哪条*工作流上，就可能把你的编辑打到错误的标签页，所以在更新之前它被限制在只读。

修复是三步，**第三步是人们会跳过的那步**：

<Steps>
  <Step title="更新面板">
    让智能体更新它（`install_comfyui(action:'panel', panel_action:'update')`），或从
    ComfyUI-Manager 做，那里它列名为 `comfyui-agent-panel`。
  </Step>

  <Step title="重启 ComfyUI">
    更新自己不会重启任何东西。让智能体做，或你自己重启。
  </Step>

  <Step title="硬刷新 ComfyUI 浏览器标签页">
    **Ctrl+Shift+R**（Mac 上是 **Cmd+Shift+R**）。浏览器缓存了旧的面板代码，光重启
    甩不掉。跳过这一步，同一条消息会立刻回来，所以看起来像更新失败了，其实没有。
  </Step>
</Steps>

### 「没有面板已连接」

不同的问题，看起来差不多的消息。意思是外面的智能体找不到你的 ComfyUI 浏览器标签页。
几乎总是下面之一：

* ComfyUI 根本没在浏览器里打开 —— 打开它，看侧边栏的智能体标签页。
* ComfyUI 刚重启过，或你重载了标签页。那会丢掉连接。**重载 ComfyUI 标签页**，它马上
  回来。
* 智能体标签页开着，但从未连接过。面板在你选一个服务商并点**连接**时才附着，从不在
  加载时附着，所以刚打开、什么都没显示的标签页是普通状态，不是故障。
* 面板还没装。见 [面板指南](/docs/docs/zh/panel)。

消息会帮你把这些分成两组 —— 它区分「以前连过、后来掉了」和「还什么都没连过」。它不
再往下走，并且会这么说，而不是挑一个它没法观察的原因。以前连过的标签页证明面板已安装
并且当时能用，所以重载 ComfyUI 标签页是第一件该试的，通常也是唯一一件；如果重载没把它
带回来，就当第二组，顺着上面的检查往下走。

## 当它什么都不说

更难的失败是里面完全没有错误的那种。智能体不调用工具，不拒绝，也不抱怨。它只是说话：
描述你的工作流大概包含什么，或提出给你写脚本。听起来很帮忙，而且它什么都没看过。

三种完全不同的情况会产出同一种行为，从你坐的地方看，它们无法区分：

<CardGroup cols={3}>
  <Card title="不在" icon="circle-minus">
    你的客户端从没拿到工具。它们不在它交给模型的列表里，所以没什么可调用。
  </Card>

  <Card title="被挡住" icon="hand">
    你的客户端有工具，但不让模型跑它们。调用停在客户端内部。
  </Card>

  <Card title="没被要过" icon="eye-slash">
    一切都在工作。你想要的东西住在一个从没被提起的名字下面，所以没人伸手去够。
  </Card>
</CardGroup>

补救指向三个不同方向，其中两个如果你猜错会主动伤人：重装已经装好的东西，或放松从来
不是问题的权限。所以第一步不是去修任何东西。是先搞清楚你在哪一种。

### 把它们分开的两个问题

用白话问智能体：

<Steps>
  <Step title="问它能看见什么">
    > 你从 comfyui-mcp 拿到哪些工具？只列名字。

    几十个名字的列表是正常且健康的 —— 那是直接面，从 0.50.0 起就是默认。

    **三个名字** —— `list_tools`、`describe_tool`、`call_tool` —— *也*正常且健康。
    那是[紧凑模式](#如果你跑的是小型本地模型)，通过传入 `--compact` 得到，小型本地
    模型现在仍会自动选择。目录的其余部分离一次 `list_tools` 调用只有一步，所以让它
    跑那个，你就会看到真正的列表。两种答案都不意味着有东西被扣下。

    **一个名字都没有**，或「我没有任何 ComfyUI 工具」，只排除第三种情况，别的都不排除。
    它**不**意味着不在。权限策略可以从展示给模型的列表里扣下工具，所以一台已安装、
    已连接、正在工作的服务器会给出正好这个答案。这一步里，不在和被挡住无法区分，而这
    就是让一个用户花了好几天的那条枝 —— 他确信是接线问题。

    有一项检查能收窄，而这不是智能体能看见的：**打开你客户端自己的 MCP 服务器列表**
    —— 它展示连上了哪些服务器的那个地方，和它交给模型的工具列表不是同一份。

    * **comfyui-mcp 不在，或显示失败** → **不在**。客户端一侧的接线问题，不是面板或
      服务器故障。它再分成两种 —— 从没接上，或一台根本握不住它们的主机 ——
      [下面](#每种答案通常从哪来) 的列表把它们分开。
    * **它在而且已连接，模型仍然列不出任何东西** → 工具已经到了你的客户端。之后停在
      哪仍然开放：它们可能被权限规则从模型那里扣下，或者模型只是没能或拒绝列出它们，
      从这里看完全一样。**不要**单凭这个就开始放松权限。

      如果那份服务器列表还显示**它从 comfyui-mcp 拿走了哪些工具**，事情就定了：那里
      列了而模型没列，说明问题在模型，不在你的权限；那里一个都没有，说明它们在模型
      看见之前就被过滤了。如果你的客户端不显示那个 —— 很多都不显示 —— 这里没有任何
      你能拿到的东西能区分这两种，第二步机会更好，因为拒绝会用文字回来。
  </Step>

  <Step title="让它试一次，并原样回报">
    > 现在调用那个你会用来做这件没在工作的事的工具，并把回来的东西原样贴出来 ——
    > 包括任何错误。不要绕开它。

    那句话里有两个细节在干活。

    **你会用来做这件没在工作的事的那个工具**，特指这个。权限规则通常按工具写，所以
    另一个工具成功证明不了你在乎的那个 —— 挡住就是这样藏起来的。如果没被读的是画布，
    测试就必须是一次画布读取。

    **不要绕开它。** 整套失败模式就是智能体悄悄绕过障碍而不点名它，由着它自己，它会
    再做一次。

    * **真实结果** —— 那个工具能用。你在第三种情况。
    * **「被拒绝了」/「不允许」/「我需要权限」** —— **被挡住**，在你的客户端内部。
      这一条是定论：智能体问了，被拒绝了。
    * **「我没有那个工具」** —— 仍然是不在 *或* 被挡住。被扣下的工具和缺失的工具从
      模型的座位上看一模一样，所以不要单凭这个行动：把它带回第一步的服务器列表，如果
      那份列表也不显示按服务器的工具，那你能碰到的东西就分不开这两种，诚实的下一步是
      去 issue 跟踪器问，而不是开始改设置。
    * **还是散文，仍然没有调用** —— 直问：*「你调用工具了吗？如果没有，为什么没有？」*
      躲两次的智能体，通常是在绕开一件它没提过的事。
  </Step>
</Steps>

### 我们从这里能看到什么，看不到什么

<Warning>
  当你的客户端拒绝一次工具调用时，那次调用从不离开你的客户端。什么都到不了这台服务器，
  所以它的日志里不会出现任何东西，我们能到达的任何地方也不会产出错误。我们检测不到
  挡住，也不会假装能：任何声称能告诉你「你的客户端挡住了这个」的页面或消息都会是在猜。
</Warning>

同一事实反过来切，而这正是误导人的那一半：安静的日志不是什么都没试过的证据。不在、
被挡住、以及从没被要过，从这里看都像沉默。

所以上面两个问题才是真正的诊断。它们管用，是因为它们问的是*当时在场*的那个参与者
—— 你的智能体 —— 让它说出试了什么，并拒绝它绕开答案的选项。

### 每种答案通常从哪来

**被挡住 —— 你客户端自己的权限规则。** 在 Claude Code 里，那是 `settings.json` 的
`permissions` 块（`~/.claude/settings.json`，或项目的 `.claude/settings.json`）；
MCP 工具以带命名空间的名字出现在那里，`mcp__comfyui__<tool>`。一份从没提到它们的
严格 `allow` 列表会在发送之前停住每一次调用。这就是让一个用户花了好几天的那种情况：
工具看起来像在工作，恰恰因为他们在找的错误永远不会出现。

**不在，而且能修 —— 从没接上。** 客户端会说 MCP，但从没被告知这台服务器，或被告知了
但条目是错的。这是常见的那种，改一份配置就行；见 [快速开始](/docs/docs/zh/quickstart)
了解你的客户端期望的条目。

**不在，而且修不了 —— 一台根本没有 MCP 客户端的主机。** 有些智能体不说 MCP，再怎么
配置也改不了这个。`pi` 就是一个：它有自己内置的 shell 和编辑器工具，没有 MCP 客户端，
所以无论还装了什么，都交不上我们的。你选它时面板会直接说 —— *「pi 没有 ComfyUI 工具
（没有 MCP）」*。那一行就是答案，不是要调试的症状；修复是换一个后端。

**两者都有可能 —— 夹在中间的东西。** 承载你 MCP 流量的网关、代理或路由器，可能只把
工具面的一部分传下去。如果目录和实际跑起来的对不上，就怀疑中间那一层。

### 如果原来是第三种情况

那就什么都没坏，也没人配错：一项能力存在，而你无从发现。那是我们的失败而不是你的，
值得告诉我们 —— 让智能体去提交，它会替你附上你的环境。一项谁都找不到的功能，从你坐的
地方看，就是一项我们没发出去的功能。

## 如果你跑的是小型本地模型

把整份菜单交给模型，等于它开口之前先读很多东西。在大型托管模型上这没问题。在你自己
机器上跑的小型模型上，这常常是能用和不能用的差别。

所以默认情况下智能体拿到的是**三个**工具而不是完整集合：一个浏览目录，一个查单个工具
的细节，一个去跑它。它在需要的时候取需要的东西，而不是一开始把所有东西读完。

你不用做任何事就能得到这个 —— 这是默认。想要的话控件在这里：

```bash theme={null}
# force the small three-tool mode
npx -y comfyui-mcp --compact

# or hand the model everything at once
npx -y comfyui-mcp --full
```

也可以用 `COMFYUI_MCP_TOOL_MODE=compact` 或 `COMFYUI_MCP_TOOL_MODE=full` 设置。

代价是第一次真正动作之前多一两轮往返，换来模型还剩思考的空间。大模型通常更喜欢
`--full`。哪些模型扛得住哪种，见 [本地 LLM](/docs/docs/zh/local-llms)。

## 接下来去哪

<CardGroup cols={2}>
  <Card title="快速开始" icon="rocket" href="/docs/docs/zh/quickstart">
    装上它，生成你的第一张图。
  </Card>

  <Card title="侧边栏面板" icon="window-maximize" href="/docs/docs/zh/panel">
    ComfyUI 内的智能体，以及它能对你的画布做什么。
  </Card>

  <Card title="工具参考" icon="book" href="/docs/docs/tools/image-generation">
    每个工具，带真实调用长什么样的例子。
  </Card>

  <Card title="故障排查" icon="wrench" href="/docs/docs/zh/troubleshooting">
    当它不是拒绝，而是真的坏了。
  </Card>
</CardGroup>
