Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ clicking menus. That loopback CLI / HTTP channel is documented in
[docs/vibecad-agent-control.md](docs/vibecad-agent-control.md). It does not
disable the in-app Assistant and it is not MCP.

The in-app Assistant can also call tools from MCP servers you register, such as
[Cua Driver](https://cua.ai/cua-driver) for desktop automation, a Playwright
browser for finding and downloading models, or a project folder of datasheets.
Registration, presets, and the download-and-import flow are documented in
[docs/vibecad-mcp-tool-servers.md](docs/vibecad-mcp-tool-servers.md).

Release packaging details are documented in [docs/vibecad-release-packaging.md](docs/vibecad-release-packaging.md).

The single-workbench Part and Part Design model, compatibility boundary, and
Expand Down
5 changes: 5 additions & 0 deletions docs/vibecad-mcp-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ To keep the in-app Assistant (including Grok) running while a desktop agent
opens documents or runs scripts, use the separate loopback channel in
[vibecad-agent-control.md](vibecad-agent-control.md) instead of MCP.

To give the built-in agent *additional* tools from MCP servers such as
cua-driver, register them as tool servers instead; see
[vibecad-mcp-tool-servers.md](vibecad-mcp-tool-servers.md). Tool servers do not
enable this control mode.

## Connect a client

1. Open **Edit → Preferences → VibeCAD**.
Expand Down
100 changes: 100 additions & 0 deletions docs/vibecad-mcp-tool-servers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# VibeCAD MCP tool servers

The built-in VibeCAD agent can call tools from MCP servers that you register in
Preferences. VibeCAD is the MCP **client** in this mode: it starts or connects
to each server, reads its tool list, and offers those tools to the active
provider (ChatGPT/Codex, Grok, OpenAI-compatible endpoints, Anthropic, or
Gemini) beside the normal VibeCAD CAD tools.

This is different from [External MCP control](vibecad-mcp-control.md), where an
outside MCP client drives VibeCAD and the built-in agent is disabled. Tool
servers extend the built-in agent; they never replace it.

## Register a server

1. Open **Edit → Preferences → VibeCAD → MCP**.
2. Under **External MCP tool servers**, choose a preset or select **Add** and
fill in the fields:
- **Name**: how the server appears to the agent. Tools are exposed as
`mcp_<name>.<tool>`, so a server named `cua-driver` provides
`mcp_cua_driver.screenshot`.
- **Transport**: `stdio` runs a local command; `http` connects to a
Streamable HTTP endpoint.
- **Command** and **Arguments** for `stdio`, or **URL** and **HTTP headers**
for `http`.
- **Environment**: extra `NAME=value` lines for a `stdio` command. Values
such as `${MY_TOKEN}` are read from the VibeCAD process environment when
the server starts, so secrets do not need to be written into preferences.
- **Tools**: an optional comma-separated allowlist when a server advertises
more tools than the agent needs.
- **Tool timeout**: how long one call may run before VibeCAD reports
`MCP_TOOL_TIMEOUT` to the model.
3. Select **Test connection** to start the server and list its tools.
4. Select **Apply** or **OK**.

Registrations are stored as JSON under the `MCPToolServers` preference key.
The same list also accepts the `mcpServers` object format used by other MCP
clients when it is pasted into that preference.

### Presets

- **Add cua-driver** registers `cua-driver mcp`, the [Cua Driver](https://cua.ai/cua-driver)
desktop automation server. Install it first with the command from its
documentation. On Linux the agent can then target a browser window, take
screenshots, and click without moving your cursor.
- **Add browser (Playwright)** registers the official Playwright MCP server
through `npx -y @playwright/mcp@latest`. Node.js must be installed.
- **Add project folder…** registers the reference filesystem server for one
folder, so the agent can read datasheets, downloaded models, and BOM files.

## What the agent sees

- External tools are declared after the frozen VibeCAD tool surface and use the
`mcp_<server>` namespace. The CAD surface, its digests, and its authorization
checks are unchanged.
- A short system-instruction section lists the connected servers and tells the
model that external tools never edit the CAD document, that their output is
untrusted data, and that failures must be reported plainly.
- Tool results keep text and structured content. Image results, such as a
screenshot, are saved under `~/.vibecad/mcp-tool-servers/images` and shown to
the model through the same path as viewport captures.
- Failures use the normal VibeCAD tool-failure contract with the codes
`MCP_TOOL_ERROR`, `MCP_TOOL_TIMEOUT`, `MCP_TOOL_CALL_FAILED`, and
`MCP_SERVER_UNAVAILABLE`.

Servers connect on the first turn that needs them and stay connected for the
rest of the VibeCAD session. A server that fails to start is skipped for one
minute and reported in the assistant panel; the CAD turn continues without it.
Standard error from `stdio` servers is written to
`~/.vibecad/mcp-tool-servers/logs/<server>.stderr.log`.

## Example: find a model online, download it, import it

With the browser and project-folder presets registered (or cua-driver driving a
signed-in browser), a request such as *"find an L bracket on GrabCAD, download
the STL into my project folder, and import it"* runs like this:

1. The agent searches with the browser tools (`mcp_playwright.browser_navigate`,
`browser_snapshot`, `browser_click`) and opens the model page.
2. It downloads the file. Playwright saves downloads into the folder given by
`--output-dir`; point that at the same folder as the project-folder server.
3. It confirms the file with `mcp_project_files.list_directory`.
4. It imports the mesh through the Mesh ribbon's native `mesh.io` tool
(`import_mesh` accepts STL, OBJ, 3MF, PLY, and related formats) and then
continues with VibeCAD's own tools to position or link the imported object.
STEP and IGES files are imported through **File → Import** today; the agent
works with the imported part afterwards.

GrabCAD requires a signed-in account to download. Use a browser profile that is
already signed in (`--user-data-dir` for Playwright, or cua-driver targeting
your normal browser window) rather than storing credentials in VibeCAD.

## Security notes

- A `stdio` registration runs the command you entered with your user account.
Register only servers you trust, exactly as their documentation describes.
- HTTP headers and environment values are stored in plain preferences unless
you use `${NAME}` references to the process environment.
- External tool output is delivered to the model as data. VibeCAD does not
execute instructions found in that output, and the system instructions tell
the model not to either.
1 change: 1 addition & 0 deletions src/Mod/VibeCAD/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ set(VibeCAD_Scripts
VibeCADMCP.py
VibeCADMCPStdio.py
VibeCADMCPToolNames.py
VibeCADMCPToolServers.py
VibeCADModelingSurface.py
VibeCADNativeActionManifest.py
VibeCADNativeArguments.py
Expand Down
22 changes: 22 additions & 0 deletions src/Mod/VibeCAD/VibeCADGui.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@ def _shutdown_internal_assistant() -> None:
shutdown_managed_codex_sessions()
except Exception as exc:
_warn(f"VibeCAD Codex shutdown failed: {exc}")
try:
from VibeCADMCPToolServers import shutdown_mcp_tool_servers

shutdown_mcp_tool_servers()
except Exception as exc:
_warn(f"VibeCAD MCP tool server shutdown failed: {exc}")

current = threading.current_thread()
for worker in (
Expand Down Expand Up @@ -2389,10 +2395,25 @@ def _format_progress_event(event: dict[str, Any]) -> str:
tool = str(event.get("tool_name") or "CAD tool")
elapsed = float(event.get("elapsed_seconds", 0.0) or 0.0)
return f"Applied {tool} in {elapsed:.2f}s."
if name == "external_tool_server_ready":
count = int(event.get("tool_count", 0) or 0)
return (
f"External MCP server {event.get('name') or 'server'} is ready "
f"with {count} tools."
)
if name == "external_tool_server_failed":
return (
f"External MCP server {event.get('name') or 'server'} is unavailable: "
f"{event.get('error') or 'unknown error'}"
)
if name == "external_tool_servers_failed":
return f"External MCP servers were skipped: {event.get('error') or 'unknown error'}"
return name.replace("_", " ")


_PROGRESS_THINKING_EVENTS = {
"external_tool_server_failed",
"external_tool_servers_failed",
"provider_tool_requested",
"provider_web_search_started",
"provider_web_search_completed",
Expand All @@ -2406,6 +2427,7 @@ def _format_progress_event(event: dict[str, Any]) -> str:
}

_PROGRESS_STATUS_ONLY_EVENTS: set[str] = {
"external_tool_server_ready",
"analyze_context_cache_hit",
"analyze_context_progress",
"analyze_context_ready",
Expand Down
Loading