# How to Integrate the CAD Viewer with Claude for JSON Output

> Integrate CAD Viewer with Claude for JSON output. Launch the viewer with the --json flag to enable Claude to construct preview links without manual port detection.

- Repository: [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad)
- Tags: how-to-guide
- Published: 2026-07-28

---

**You can integrate the CAD Viewer with Claude Code by launching the viewer with the `--json` flag, which emits a machine-readable JSON line containing the viewer URL, port, and action status, enabling Claude to construct preview links without manual port detection.**

The `earthtojake/text-to-cad` repository provides a CAD Viewer skill designed for seamless integration with Claude Code's Preview tool. By leveraging the JSON output mode, Claude can programmatically manage the viewer lifecycle, detect server readiness, and generate direct links to CAD artifacts. This approach eliminates manual port polling and allows automated workflows to render 3D models directly within Claude's interface.

## Understanding the JSON Output Schema

According to [`skills/cad-viewer/SKILL.md`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad-viewer/SKILL.md) (lines 69-86), the viewer supports a `--json` flag that modifies the launcher's output behavior. When enabled, the launcher prints a JSON object as the final line of stdout containing three critical fields:

- `url`: The complete viewer URL including the dynamically assigned port and directory parameter
- `port`: The integer port number the server is listening on  
- `action`: A string indicating whether the server was `"start"` (newly launched) or `"reuse"` (existing instance)

The schema structure is:

```json
{
  "url": "http://127.0.0.1:<port>/?dir=<absolute-model-root>",
  "port": <port>,
  "action": "reuse|start"
}

```

## Step-by-Step Integration Workflow

### Launching the Viewer with JSON Output

Execute the viewer launcher via npm with the `--json` flag to enable machine-readable output. The launcher is invoked through [`scripts/viewer/run-agent-start.sh`](https://github.com/earthtojake/text-to-cad/blob/main/scripts/viewer/run-agent-start.sh) (triggered by `npm run agent:start`):

```bash
npm --prefix scripts/viewer run agent:start \
  -- --host 127.0.0.1 \
     --dir /absolute/path/to/models \
     --json

```

Typical stdout output ends with:

```json
{"url":"http://127.0.0.1:54321/?dir=/absolute/path/to/models","port":54321,"action":"reuse"}

```

### Capturing and Parsing the JSON Response

The launcher outputs the JSON object as the last line of stdout. Your integration script must extract this line—identified by its leading `{` character—and parse it to extract the connection parameters.

### Handling Server Startup vs. Reuse

When the `action` field equals `"start"`, the server requires a brief initialization period before accepting connections. Probe the `GET /__cad/server` endpoint on the base URL until it returns HTTP 200. If `action` is `"reuse"`, the server is already ready to serve requests.

### Constructing the Final Preview URL

Append a `file=` query parameter (relative to the `--dir` path) to the base URL to specify which CAD artifact to display:

```

{url}&file=example.step

```

## Implementation Example

The following Python script demonstrates the complete integration pattern, including JSON parsing, server readiness probing, and URL construction:

```python
import json
import sys
import time
import urllib.request

# Read all lines from the process output and pick the last JSON line

output = sys.stdin.read().splitlines()
json_line = next(line for line in reversed(output) if line.lstrip().startswith('{'))
info = json.loads(json_line)

# If the viewer was just started, wait for it to be ready

if info["action"] == "start":
    base = info["url"]
    while True:
        try:
            urllib.request.urlopen(f"{base}/__cad/server")
            break
        except Exception:
            time.sleep(0.2)

# Construct the final preview link for a specific file

file_path = "example.step"          # relative to --dir

preview_url = f"{info['url']}&file={file_path}"
print("Claude preview URL:", preview_url)

```

## Key Files in the Integration Architecture

Understanding the following source files is essential for implementing a robust integration:

- **[`skills/cad-viewer/SKILL.md`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad-viewer/SKILL.md)** (lines 69-86): Documents the `--json` flag specification and the exact JSON schema returned by the launcher.

- **[`scripts/viewer/run-agent-start.sh`](https://github.com/earthtojake/text-to-cad/blob/main/scripts/viewer/run-agent-start.sh)**: The shell script executed by `npm run agent:start` that handles the actual server lifecycle management and JSON output formatting.

- **[`plugins/cad/.claude-plugin/plugin.json`](https://github.com/earthtojake/text-to-cad/blob/main/plugins/cad/.claude-plugin/plugin.json)**: Registers the CAD Viewer as a Claude Code plugin, enabling the Preview tool integration and URL handling within Claude's interface.

- **[`viewer/src/client/components/ViewerLoadingOverlay.js`](https://github.com/earthtojake/text-to-cad/blob/main/viewer/src/client/components/ViewerLoadingOverlay.js)**: Implements the client-side status reporting that the JSON `action` field reflects, indicating when the viewer has finished initializing.

## Summary

- Invoke the viewer launcher with `--json` to receive structured connection data instead of human-readable logs.
- Parse the final stdout line starting with `{` to extract the `url`, `port`, and `action` fields.
- Probe `GET /__cad/server` when `action` equals `"start"` to ensure the server is ready before constructing preview links.
- Append the `file` query parameter relative to the `--dir` argument to target specific CAD models.
- Reference [`skills/cad-viewer/SKILL.md`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad-viewer/SKILL.md) for the authoritative schema definition and [`scripts/viewer/run-agent-start.sh`](https://github.com/earthtojake/text-to-cad/blob/main/scripts/viewer/run-agent-start.sh) for the launcher implementation.

## Frequently Asked Questions

### What is the exact JSON schema returned by the CAD Viewer?

The JSON schema consists of three required fields: `url` (string containing the full viewer URL with port and directory), `port` (integer representing the dynamically chosen port), and `action` (string enum of either `"start"` or `"reuse"` indicating whether a new server instance was launched or an existing one was utilized).

### How does Claude Code know when the CAD Viewer server is ready to accept connections?

When the `action` field is `"start"`, indicating a fresh server launch, you must poll the `GET /__cad/server` endpoint on the base URL until it returns HTTP 200. If `action` is `"reuse"`, the server is already running and immediately ready to serve requests.

### Can I specify which CAD file to display in the viewer URL?

Yes. After parsing the base URL from the JSON output, append a `file=` query parameter containing the path relative to the `--dir` argument specified during launch. For example, if `--dir` points to `/models` and your file is at `/models/part.step`, use `&file=part.step`.

### Where is the `--json` flag documented in the source code?

The `--json` flag behavior and its output schema are documented in [`skills/cad-viewer/SKILL.md`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad-viewer/SKILL.md) at lines 69-86, while the actual implementation resides in [`scripts/viewer/run-agent-start.sh`](https://github.com/earthtojake/text-to-cad/blob/main/scripts/viewer/run-agent-start.sh) which is executed via the `npm run agent:start` command.