TrimbleX9-mcp
Summary: This is a read-only direct-mode Trimble X9 MCP server: it inspects scanner state and data, downloads files locally, and computes area-scan angles from a preview; it cannot move the scanner or modify/delete scanner data.
Read scanner status: battery, AC, levelling, storage, IMU, laser pointer, masked Wi-Fi config, and errors.
List projects, scans, scan modes, errors, and running/queued tasks with progress.
Wait for scans/tasks to finish with configurable polling and timeout.
Get metadata for one point-cloud file.
Download scan
.tzffiles and preview JPEGs intoSCANNER_DOWNLOAD_DIRwith filename/overwrite safeguards.Convert a box on a downloaded preview into area-scan angles (start/delta HA/VA).
Provides tools for interacting with a Trimble X9 terrestrial laser scanner over its local HTTP/REST API, enabling agents to query scanner status, list projects and scans, read scan-mode menus and errors, retrieve scan-file metadata, download point clouds and preview images, and optionally create projects, launch scans, and delete scans or projects.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@TrimbleX9-mcpWhat's the scanner status, and are there any errors?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
TrimbleX9-mcp
An MCP server for the Trimble X9 terrestrial laser scanner. It gives an AI agent tools to read the scanner's status, list projects and scans, read the scan-mode menu, download point-cloud files and previews, and, behind an explicit opt-in, create projects and start full-dome or area scans.
It runs in one of two modes:
Direct mode talks to the scanner's own local HTTP/REST API (
/api/v1) over its USB or Wi-Fi link. The safety checks run in this server.Bridge mode talks to a separate x9 bridge service that sits next to the scanner and enforces the rules (approvals, battery, busy scanner, echo checks) for every client. The tools are thin calls to the bridge's API.
What the agent gets back is something it can look at. The minimap of a
19-station colour scan of an administration building, redrawn by
scanner_minimap after every station:
And where to set up next: scanner_plan_station picks the spot from the
station's points, and scanner_propose_station shows the person the spot,
the landmark beside it and a tripod drawn its real size there, with its
shadow on the ground:
Tested with Claude Opus 5.5 and Grok 4.6 as the model in the chat: given the same plan, both put the tripod on the same spot of pavement.
Interoperability project: written from scratch against the instrument's network API, with behavior verified on a live instrument. No vendor code, firmware or vendor documentation is included or redistributed. How the API knowledge was obtained is recorded in PROVENANCE.md. Independent project, not affiliated with or endorsed by Trimble Inc.; "Trimble" and "X9" are trademarks of their respective owners.
Contents: Install · Modes · Configuration · Tools · Safety · Errors · Client configuration · Compatibility · Tests · full tool reference in docs/tools.md.
Install
Python 3.10 or later. Install from the GitHub release tag; this provides the
console script trimblex9-mcp, which speaks MCP over stdio.
pip install "git+https://github.com/northidaholabs/TrimbleX9-mcp@v0.15.0"
# or, isolated:
pipx install "git+https://github.com/northidaholabs/TrimbleX9-mcp@v0.15.0"
# or run without installing:
uvx --from "git+https://github.com/northidaholabs/TrimbleX9-mcp@v0.15.0" trimblex9-mcp
# no git on the host (e.g. a minimal Raspberry Pi image):
pip install https://github.com/northidaholabs/TrimbleX9-mcp/archive/refs/tags/v0.15.0.tar.gzDependencies: mcp and httpx (see Compatibility).
On a Raspberry Pi without internet
A field Pi is often on the scanner's Wi-Fi, with no internet. Build a wheelhouse on a machine that has internet, for the Pi's Python (Raspberry Pi OS trixie: CPython 3.13, aarch64), copy it over and install from it:
# on a machine with internet
tag=v0.15.0
pip wheel --no-deps -w wheelhouse "git+https://github.com/northidaholabs/TrimbleX9-mcp@$tag"
pip download -d wheelhouse --only-binary=:all: --platform manylinux2014_aarch64 \
--python-version 3.13 --implementation cp "mcp>=1.7,<3" "httpx>=0.27"
curl -L -o wheelhouse/trimblex9-mcp-auto \
https://raw.githubusercontent.com/northidaholabs/TrimbleX9-mcp/$tag/extras/trimblex9-mcp-auto
scp -r wheelhouse <pi>:
# on the Pi
python3 -m venv ~/x9-bridge/.venv
~/x9-bridge/.venv/bin/pip install --no-index --find-links ~/wheelhouse trimblex9-mcp
install -D -m 0755 ~/wheelhouse/trimblex9-mcp-auto ~/x9-bridge/bin/trimblex9-mcp-autoThe launcher (extras/trimblex9-mcp-auto, from v0.12.1) starts the server for
a field kit; see
On a field Pi, through the bridge.
trimblex9-mcp is meant to be started by an MCP client, not run by hand; on a
terminal it just waits for MCP messages on stdin.
Related MCP server: Bambuddy MCP Server
Modes
The mode is chosen once, at start-up, from the environment:
|
| Result |
unset or empty | (ignored) | Direct mode: talks to the scanner at |
set | set | Bridge mode: talks to the bridge at |
set | unset or empty | Exits at start-up with |
The two modes expose different tool sets (see Tools). In bridge mode
SCANNER_BASE and SCANNER_ALLOW_ACTUATION are ignored: the bridge decides
what a token may do.
Direct mode
Run the server on the host the scanner is connected to (by USB, or on the
scanner's Wi-Fi). Out of the box the server is read-only: tools that move
the instrument, fire its laser or delete data are not registered at all
unless SCANNER_ALLOW_ACTUATION is set. With it set, the server validates
every scan request locally, refuses to start a scan or delete data while the
scanner is busy,
and cancels any scan the instrument did not accept exactly as sent.
Bridge mode
The bridge is the only thing that talks to the scanner. This server sends
each call to the bridge's HTTP API with a bearer token the bridge issued,
usually with role agent. With an agent token, a scan waits in
awaiting_approval until a person approves it in the bridge app, unless the
person granted a set of scans in advance. Approval, grant and delete tools
are deliberately absent from this server. Bridge mode adds exports to
PLY/LAS, previews returned as images, aiming, recipes and a field log.
The bridge itself is a separate service and is not part of this repository.
Configuration
All configuration is through environment variables.
Variable | Mode | Default | Effect |
| direct |
| Base URL of the scanner's HTTP API. The default is the scanner over its USB network link; use its Wi-Fi address (e.g. |
| direct | unset (off) |
|
| both |
| Directory that download tools write into and that |
| bridge | unset | Bridge API base, e.g. |
| bridge | unset | Bearer token issued by the bridge, sent as |
| bridge | unset | An |
| bridge | 8 | How long the permission given in the chat lasts (up to 20 scans) |
Timeouts are fixed in the code, not configurable:
Request | Direct mode | Bridge mode |
Ordinary API calls | 15 s (5 s to connect) | 30 s (5 s to connect) |
File downloads (streamed) | 600 s (5 s to connect) | 600 s (5 s to connect) |
| — | 120 s (5 s to connect) |
The long-running waits (scanner_wait_for_scan, scanner_wait_for_job) poll
and take their own timeout_s argument (1 to 7200 s, default 900).
Tools
A summary; parameters, return values and rules for each tool are in docs/tools.md.
"Read" tools only query. "Local write" tools write files into
SCANNER_DOWNLOAD_DIR but do not change the scanner. "Actuating" tools move
the instrument or fire its laser. "Destructive" tools stop work or delete
data. Each tool carries matching MCP annotations (readOnlyHint,
destructiveHint).
Direct mode, always registered
Tool | Kind | What it does |
| read | Battery, AC, levelling, storage, IMU, laser pointer, Wi-Fi config (secrets masked), errors |
| read | List projects |
| read | List scans as compact records |
| read | The scan-mode menu (range, points, size, time, spacing, rate) |
| read | Current error list |
| read | Running or queued tasks with percent complete; empty means idle |
| read | Wait until no task is running, reporting progress |
| read | Metadata of one point-cloud file |
| local write | Download a scan's |
| local write | Download a scan's preview JPEG |
| read (local only) | Turn a box on a downloaded preview into area-scan angles |
Direct mode, only with SCANNER_ALLOW_ACTUATION
Tool | Kind | What it does |
| write | Create a project |
| actuating | Start a full-dome scan |
| actuating | Start a scan of an angular window |
| destructive | Stop a running task |
| destructive | Delete a scan and its file, by scanUUID; refused while busy |
| destructive | Delete a project and its scans, by projectUUID; refused while busy |
A typical direct-mode scan: scanner_scan_modes → scanner_projects (or
scanner_create_project) → scanner_launch_scan → scanner_wait_for_scan →
scanner_scans → scanner_download_scanfile.
Bridge mode
Tool | Kind | What it does |
| read | Bridge and scanner state: connection, busy, battery, storage, levelling, moved-since-last-scan, queue length |
| read | Scan modes with range, angular step, point count and timings |
| read | Projects with scan counts |
| write | Create a project by name |
| read | Scans, newest first, optionally for one project |
| read | One scan's record |
| actuating (queued; usually needs approval) | Queue a full-dome or area scan |
| read | One job's state and progress |
| read | Wait for a job, returning early if it needs approval |
| destructive | Cancel a job; a running scan is stopped |
| read | A scan's preview, returned as an image the agent can see |
| read | Turn a box on a preview into an area-scan window |
| write (on the bridge) | Decode a scan to levelled PLY or LAS |
| read | An export's point count, bounds and checks |
| local write | Download an export file |
| local write | Download a scan's raw |
| read | Installed recipes |
| read | One recipe's inputs and steps |
| write (may lead to scans) | Start running a recipe |
| read | A run's state and steps |
| write | Complete a person step of a run |
| write | Measure a window opening in a scan on the bridge (bridge 0.4.0+) |
| read | A measurement's values, checks and evidence image |
| read | Standing permissions to scan: project, expiry, scans left, who gave them, and the run they cover |
| read | Computes where to set up next from a full dome's points: up to three spots on open ground a person can walk to, a real step out, seeing the most of what this station couldn't (behind and beside a named subject, if given), each with its preview pixel and a landmark beside it (bridge 0.14.0+) |
| write | Marks where to set up next on the station's preview: the tripod, the one landmark the person walks past, and a sentence naming it (no left, right or compass words). The bridge refuses a proposal that breaks that, shows it in its web UI and returns the picture (bridge 0.8.0+) |
| write | Sets what the job is for (the person's goal, kind, done-when criteria) and its first ledger targets (bridge 0.8.0+) |
| read | The mission, its state and its ledger |
| read | The project's stations in one frame (registered by the bridge after each full dome), the walls found, and the plan picture (bridge 0.9.0+) |
| read | Where registration runs: the laptop workers connected, or the Pi; how to start a worker on the laptop. Ask the person once per laptop (bridge 0.10.0+) |
| write | Asks the person, in the chat, to confirm a run's sign-off step (or to correct the numbers); relayed with |
| read | The job so far as a simple line map: walls, numbered stations (amber when not trusted), wall targets; redrawn after every station (bridge 0.11.0+) |
| read | How much of a wall face the registered stations saw: share of its length, spacing, stations, unseen stretches (bridge 0.9.0+) |
| write | Adds or updates ledger targets: open, covered (by stations), measured (with a measurement), declined (with a reason). A wall target can carry a question ( |
| write | Asks a question target of the point cloud now (bridge 0.15.0+): |
| write (asks the person) | Says the job is done (refused while a target is open) and asks the person to sign it off in the chat, or relays their words |
| read | A scan's point spacing and coverage plan (seen, shadows), with the plan image (bridge 0.6.0+) |
| write | Propose a person step's answer (e.g. the box around the window) for a person to confirm (bridge 0.3.0+) |
| destructive | Stop a run and any scan in flight |
| read | The field log |
| write | Add a note to the field log |
Prompt (bridge mode)
Prompt | Arguments | What it does |
|
| Runs a site visit toward one goal: asks once about processing on the laptop, asks which one when the view shows more than one thing the job could mean, sets the mission, scans station by station with the minimap and registration, proposes each next station by the landmark the person walks past, and ends with the one sign-off |
|
| Fetches the recipe from the bridge and returns step-by-step instructions for walking it with the person: which inputs to ask for, then |
Direct mode has no prompts.
The person, in the chat
AI-first: the person says what they want and signs off the result; the agent does the rest. Two moments need the person, and both are asked in the chat itself, through MCP elicitation, where the answer comes from the person and not from the model:
Permission for the visit.
scanner_start_runandscanner_start_scancheck for a grant in the project. Without one it asks once: "Let the agent scan in "" for the next 8 hours (up to 20 scans)?". Yes creates the grant withSCANNER_PERSON_TOKEN; no starts nothing. Later runs in the visit ask nothing.The sign-off.
scanner_sign_off(run_id, summary)asks about the bridge's proposal at the run's sign-off step: confirm it, or change the numbers, which the form shows prefilled with the proposal. The agent shows the evidence image in the chat first. This is the run's one person intervention.
Clients (October 2026): the Claude Code CLI shows elicitation from 2.1.76.
The Claude desktop app's Code tab declares it but closes the question without
showing it (seen 2026-10-21), and the desktop chat and claude.ai don't support
it. A Claude Code Elicitation hook can answer without showing a dialog;
don't configure one for this server.
When the chat can't ask (or closes the question unshown), the tool says so
and tells the agent to ask the person in plain chat, then call again with
person_said = the person's exact words (and, for the sign-off, corrections
for numbers they changed). That is weaker: the model carries the person's
answer. So the bridge records it: the grant's note reads "relayed by the
agent: "…"", the sign-off's input has confirmed_via, and the run counts it in
interventions.relayed. Questions answered in a dialog are noted "asked in
the chat".
Missions: a defined "done"
The person's sentence ("scan the exterior of the house", "measure all the
windows") becomes the project's mission: their goal, a kind, and done-when
criteria the agent writes, concrete enough to check. The agent keeps a ledger
of targets (each facade, each window) as it works: open, covered by named
stations, measured, or declined with a reason. It chooses the next station for
what is still open, and scanner_ready_to_leave is refused while anything is.
Then the person signs the job off once, in the chat (or relayed), and the
mission is done. The survey_mission prompt runs the whole visit.
From bridge 0.9.0 the bridge registers every full dome into one project
frame by itself. Facade targets then name their wall (wall_id from
scanner_registration), and the bridge covers them from the geometry: a
wall seen over 80% of its length is covered, with the stations that saw it,
and covered is refused while less is seen.
Safety
For agents, in short:
Permission: scans run under a grant the person gives once per visit, in the chat. Never use the operator (person) token yourself; the server uses it only after the person said yes.
Secrets: never print, paste or log tokens or the scanner's Wi-Fi passphrase. Keep tokens in files (
~/x9-bridge/*.token), not in client settings: prefer the launcher over--env SCANNER_BRIDGE_TOKEN=…, which stores the token in the client's config.The laser pointer (the scanner's own
laser-pointerAPI, not exposed by these tools): only with the person at the scanner and having said so, and never without explicit angles aimed at the floor.
Read-only by default (direct mode)
Without SCANNER_ALLOW_ACTUATION the actuating and destructive tools are not
registered, so a client sees a read-only server and cannot call them. Starting
a scan moves the instrument and fires its laser; make sure the instrument is
safely set up before enabling them.
Launch checks (direct mode)
The scanner answers HTTP 202 even to a scan request it cannot parse, and then
runs a default full-dome scan. It also ignores projectUUID unless
projectName matches too. So scanner_launch_scan and
scanner_launch_area_scan, in this order:
Validate the angles (area scan):
delta_hain (0, 2π],0 ≤ start_va,0 < delta_va,start_va + delta_va ≤ π.start_hais wrapped into [0, 2π).Refuse while busy: if any task is running or queued, they fail with
instrument is busy: <type> <taskUUID> (<state>)…and send nothing. Another client, or another agent, may be driving the instrument.Check the project:
project_uuidmust parse as a UUID, and a project with that name and that UUID must exist.Check the mode:
scan_modemust be one of the names inscanner_scan_modes.Send, then compare the echo: the instrument echoes the request it accepted. Every field sent (
scanMode,projectName,projectUUID,scanType,fastMode,colorMode, and the four angles for an area scan) must come back unchanged (floats to within 1e-9). On any mismatch the server cancels the task at once and returnsinstrument did not accept the request as sent (sent vs echoed: …); cancelled its task (HTTP <status>).
scanner_delete_scan and scanner_delete_project refuse in the same way
while any task is running or queued: a scan being filed renumbers the scan and
project lists that the delete verification relies on, and deleting the project
a scan is writing into is never wanted. scanner_create_project does not
check, since a new project does not touch the running task. scanner_cancel_task
is meant for a running task, so it does not check either.
Delete by UUID, verified (direct mode)
Scan and project ids on the scanner are list positions and are renumbered
after every delete. The delete tools therefore take the stable scanUUID or
projectUUID, look up its current id immediately before deleting, and read
the list again afterwards. The delete is reported as done only if that UUID is
gone and the list is exactly one shorter; otherwise the tool fails with
delete of <uuid> not confirmed; re-check <kind> before retrying.
Downloads stay in one directory (both modes)
Download tools write only inside SCANNER_DOWNLOAD_DIR:
filenamemust be a plain name: it starts with a letter or digit, then up to 127 more letters, digits,.,_or-. No directories, no.., no leading dot.The resolved path must sit directly in the download directory, so a symlink that points elsewhere is refused.
An existing file is kept unless
overwrite=true.Data streams into
<name>.partand is renamed into place only when complete; the.partfile is removed on failure.
scanner_preview_to_angles reads files only from the same directory, by plain
name.
Secrets masked (direct mode)
The scanner returns its Wi-Fi passphrase in plain text in its status.
scanner_status replaces every non-empty string value whose key ends in
key, psk, passphrase, password, secret or token (any case) with
***, at any depth. Booleans such as isFactoryKey are kept. Only
scanner_status is masked. In bridge mode the bridge decides what its status
contains.
Bridge mode
The bridge enforces approvals, battery limits, a busy scanner, a scanner that
moved since the reference scan, and request echo checks, for every client.
This server adds only input shape checks (for example, all four window angles
or none) and the download-directory rules above. Ids (scan_id, job_id,
export_id, run_id, recipe_id) are sent as single URL path segments with
every reserved character escaped, and an empty id, . or .. is refused, so
an id cannot reach a different bridge endpoint. Whether projects can be
created while the scanner is busy is the bridge's decision; bridge mode has no
delete tools.
Errors
Tool failures are raised as MCP tool errors (ToolError), so the message text
reaches the client on both mcp 1.x and mcp 2.x (mcp 2.x hides the text of
other exceptions). The messages are:
Situation | Message |
Scanner answered with an HTTP error (direct) |
|
Scanner unreachable (direct) |
|
Bridge refused (bridge) |
|
Bridge answered an error without a problem body (not JSON, or JSON without |
|
Scanner or bridge answered success with a body that is not JSON |
|
Truncated or malformed |
|
Any other bad value in a reply or file |
|
Bridge unreachable (bridge) |
|
Validation, busy, echo, delete and file-name checks | A plain sentence saying what was wrong and what to do, e.g. |
Client configuration
On a field Pi, through the bridge (recommended)
The usual setup: the scanner talks to
trimble-x9-bridge on a
Raspberry Pi by the tripod (its ops/README.md builds the Pi), this server runs
on the same Pi, and the agent on the laptop starts it over ssh. The launcher
extras/trimblex9-mcp-auto (installed at ~/x9-bridge/bin/) runs bridge mode
with the bridge's agent token from ~/x9-bridge/agent.token, and passes the
person's token from ~/x9-bridge/operator.token as SCANNER_PERSON_TOKEN, used
only after the person says yes in the chat. With an ssh alias x9-bridge for
the Pi (key login, no prompts):
claude mcp add -s user x9-bridge -- ssh -o BatchMode=yes x9-bridge 'X9_MCP_MODE=bridge ~/x9-bridge/bin/trimblex9-mcp-auto'Quote the remote command, so ~ is the Pi's home, not the laptop's.
Check: the client lists the scanner_* tools, and scanner_status shows the
bridge and the scanner. X9_MCP_MODE=direct starts the same server in direct
mode for diagnostics; it stays read-only while the bridge runs.
Claude Code
Direct mode, read-only:
claude mcp add trimblex9 -- trimblex9-mcpDirect mode with actuation and custom paths:
claude mcp add trimblex9 \
--env SCANNER_ALLOW_ACTUATION=1 \
--env SCANNER_BASE=http://192.168.43.1:34567/api/v1 \
--env SCANNER_DOWNLOAD_DIR=$HOME/scans \
-- trimblex9-mcpWithout installing first:
claude mcp add trimblex9 -- uvx --from "git+https://github.com/northidaholabs/TrimbleX9-mcp@v0.15.0" trimblex9-mcpBridge mode:
claude mcp add trimblex9 \
--env SCANNER_BRIDGE_URL=http://bridge.local:8795/v1 \
--env SCANNER_BRIDGE_TOKEN=<agent token> \
-- trimblex9-mcpGeneric mcpServers JSON
For clients configured with an mcpServers object (Claude Desktop, many
others):
{
"mcpServers": {
"trimblex9": {
"command": "trimblex9-mcp",
"env": {
"SCANNER_BASE": "http://192.168.42.1:34567/api/v1",
"SCANNER_DOWNLOAD_DIR": "/home/user/scanner-downloads"
}
}
}
}Add "SCANNER_ALLOW_ACTUATION": "1" to env to enable actuation. For bridge
mode, set SCANNER_BRIDGE_URL and SCANNER_BRIDGE_TOKEN instead. If
trimblex9-mcp is not on the client's PATH, give its full path (for a
virtualenv, <venv>/bin/trimblex9-mcp).
On a remote host over SSH (e.g. a Raspberry Pi by the scanner)
The scanner is usually reached from a small computer on site, not from the
machine running the agent. Install the server on that host and let the client
start it over SSH; MCP's stdio transport passes through ssh unchanged. With
the bridge on that host, use the launcher as in
On a field Pi, through the bridge.
Without a bridge (direct mode):
# on the agent's machine
claude mcp add trimblex9 -- ssh -T pi@scanner-pi.local \
'SCANNER_DOWNLOAD_DIR=$HOME/scanner-downloads ~/x9-bridge/.venv/bin/trimblex9-mcp'{
"mcpServers": {
"trimblex9": {
"command": "ssh",
"args": ["-T", "pi@scanner-pi.local",
"SCANNER_ALLOW_ACTUATION=1 ~/x9-bridge/.venv/bin/trimblex9-mcp"]
}
}
}Notes:
Set the environment variables in the remote command, as above. A client's
--env/"env"applies to the localsshprocess and is not forwarded to the remote host.Use key-based login with no password prompt (
ssh -Tand no TTY); the client cannot answer prompts.On current Raspberry Pi OS and Debian the system
piprefuses to install into the system Python; usepipxor a virtualenv, and point the command at thattrimblex9-mcp.Downloaded files land on the remote host, in its
SCANNER_DOWNLOAD_DIR.Use the full path to
trimblex9-mcpif the remote non-interactive shell'sPATHdoes not include it.
Compatibility
Item | Supported |
Python | 3.10 and later |
| 1.x ( |
| 0.27 and later |
OS | Linux and macOS (anything that can reach the scanner's network link) |
Transport | stdio |
CI runs the tests on Python 3.10 with mcp 1.7 (the floor; pinned with
pydantic<2.14, because mcp 1.7 imports a pydantic internal that 2.14
removed), on Python 3.10 with the newest mcp 1.x, and on Python 3.13 with
mcp 2.x. If you must stay on mcp 1.7, keep pydantic below 2.14. The tools use tool annotations, which FastMCP accepts from
mcp 1.7, so the requirement is mcp>=1.7,<3.
Tests
python3 -m venv .venv
.venv/bin/pip install -e . pytest
.venv/bin/pytest -qTest file | Needs | Covers |
| nothing (starts in-process stubs of the scanner and bridge APIs) | Direct mode with actuation on: delete by UUID across renumbering, local launch validation, area-scan echo check, cancel on a mismatched echo, |
|
| Bridge mode against a real bridge and scanner simulator: tool list has no approve/grant/delete tools, approval flow and progress, bridge error codes, an escaped id that would otherwise reach another endpoint, recipe prompt and run, field log |
Bridge-mode tests are skipped unless these are set:
Variable | Effect |
| Directory holding the |
| Directory of dome/area |
X9_BRIDGE_BIN=/path/to/bridge/target/release pytest -q tests/test_bridge_mode.pyDevelopment
.venv/bin/trimblex9-mcp # run over stdio
python scanner_mcp.py # same, from a checkoutscanner_mcp.py is direct mode and the entry point; scanner_bridge.py is
bridge mode and reuses the download-path helpers from scanner_mcp.py.
License
MIT (see LICENSE).
Available Tools
11 toolsscanner_download_previewB
Download a scan's panoramic preview JPEG into the server's download directory (default name 'scan--preview.jpg'); same rules as scanner_download_scanfile.
| Name | Required | Description | Default |
|---|---|---|---|
| filename | No | ||
| overwrite | No | ||
| scan_file_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real behavioral context beyond the annotations: the artifact lands in the server's download directory and gets a derived default filename. However, it says nothing about what happens if the file already exists (the overwrite flag exists), whether the download can fail on missing previews, or how the resulting path is reported; the 'same rules as ...' clause pushes the rest onto a sibling description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with the verb and artifact first and the parenthetical default kept tight. Minimal waste, though the trailing cross-reference is a partial substitute for information rather than genuine conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A file-writing tool with no output schema, three parameters at 0% schema coverage, and openWorldHint=true needs more: how overwrite and filename interact, what scan_file_id is, and what the caller gets back (path, bytes, URL). The definition leaves these to an external sibling reference an agent may not have in context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry parameter meaning, and it largely does not. It hints at the filename default ('scan-<id>-preview.jpg', ambiguous whether id is the scan or scan_file_id) but never explains the overwrite parameter or what scan_file_id must reference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (download) and resource (a scan's panoramic preview JPEG) plus the destination (the server's download directory). This distinguishes it from scanner_download_scanfile by artifact type, though the distinction is by resource only and not reinforced with an explicit contrast.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the agent must infer it wants the preview rather than the full scan file. The phrase 'same rules as scanner_download_scanfile' defers to a sibling instead of stating when to pick preview versus scanfile, and gives no exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_download_scanfileA
Download a scan's point-cloud file into the server's download directory
(SCANNER_DOWNLOAD_DIR). filename is a plain name (default
'scan-.tzf'); paths are rejected. Existing files are kept unless
overwrite is true. Streams the full file; returns bytes and path.
| Name | Required | Description | Default |
|---|---|---|---|
| filename | No | ||
| overwrite | No | ||
| scan_file_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations give only a coarse profile (readOnly=false, destructive=false, openWorld=true); the description adds the substantive detail an agent needs: the file lands in a server-side directory rather than the client, the default filename pattern, path rejection, the no-clobber default with an explicit overwrite escape, full-file streaming, and the returned bytes/path. The write-to-disk behavior is consistent with readOnlyHint=false and the non-destructive default is consistent with destructiveHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The destination and core action come first, followed by the two parameter caveats and the return summary. Every sentence conveys a distinct operational fact with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter tool with no output schema, the description is nearly self-sufficient, including where output lands and what is returned. It does not say how failures are surfaced (e.g., unknown scan_file_id, insufficient disk space), which is the one operational gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry parameter meaning and it largely does: filename is described as a plain name with a concrete default ('scan-<id>.tzf') and a hard rejection rule, and overwrite is defined in terms of preserving existing files. scan_file_id is only implicitly characterized as identifying the scan file, which is the remaining gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Download a scan's point-cloud file') and pins the destination ('into the server's download directory (SCANNER_DOWNLOAD_DIR)'). That scope implicitly separates it from scanner_download_preview, but no sibling is named explicitly, so differentiation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Constraints that shape invocation are stated clearly: 'filename is a plain name ... paths are rejected' and 'Existing files are kept unless overwrite is true.' However, there is no explicit guidance on when to pick this over scanner_download_preview or scanner_scanfile_info, so the usage condition is only implied by the word 'point-cloud'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_errorsARead-only
Get the instrument's current error list (type, errorLevel, description).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint=true annotation already establishes this is a safe read, so the description's burden is lower. It usefully adds that the list is 'current' (live/transient rather than historical), but does not say whether errors persist, are cleared on read, or are scoped to the instrument session.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with the resource and the returned fields front-loaded; every clause earns its place and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so naming the three returned fields (type, errorLevel, description) is genuinely valuable compensation. What is missing is small but real: nothing about whether the list can be empty, how errors age out, or how this differs from scanner_status.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to document and the baseline of 4 applies. The description correctly adds no parameter noise.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Get') and resource ('the instrument's current error list') and even enumerates the returned fields (type, errorLevel, description). It is clear what the tool returns, though it never explicitly distinguishes itself from ambiguous siblings like scanner_status, which an agent might reasonably confuse with an error-retrieval tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: 'current error list' suggests troubleshooting/diagnostic use, but there is no explicit 'use this when...' or 'use scanner_status instead for...' guidance. With a sibling set of eleven scanner tools including a status tool, an explicit boundary would have real value.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_preview_to_anglesARead-only
Convert a box drawn on a scan's preview JPEG into instrument angles for
scanner_launch_area_scan. Both files must already be in the download
directory (scanner_download_scanfile + scanner_download_preview of the same
scan, taken from the station the instrument is still standing on).
(x0, y0)-(x1, y1) are preview pixel corners, y down; if x1 < x0 the box
wraps across the panorama seam. margin_deg pads every side.
Returns start_ha/delta_ha/start_va/delta_va in radians (VA from zenith).
| Name | Required | Description | Default |
|---|---|---|---|
| x0 | Yes | ||
| x1 | Yes | ||
| y0 | Yes | ||
| y1 | Yes | ||
| margin_deg | No | ||
| scan_filename | Yes | ||
| preview_filename | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description is consistent with a pure computation. Beyond the annotations it discloses real behavior: y-down pixel coordinates, seam wrapping when x1 < x0, margin padding on every side, and output units (radians, VA measured from zenith). It omits error behavior for malformed boxes or mismatched file pairs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then preconditions, then coordinate semantics, then the return contract. Dense and technical with several parentheticals, but each sentence adds information an agent would otherwise have to guess.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by naming every returned field (start_ha/delta_ha/start_va/delta_va) with units and the VA reference axis. Combined with the prerequisite chain and coordinate conventions, an agent has everything needed to call this correctly in sequence.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the burden and mostly succeeds: it defines (x0,y0)-(x1,y1) as preview pixel corners with y down, explains the seam-wrap edge case, and says margin_deg pads every side. The two filename parameters are covered only implicitly — the agent must infer they are bare filenames in the download directory rather than paths.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: convert a box on a scan's preview JPEG into instrument angles, and names the downstream consumer scanner_launch_area_scan. An agent can distinguish this from every sibling in the list (download, status, scanfile_info) without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit preconditions: both files must already sit in the download directory and must come from scanner_download_scanfile + scanner_download_preview of the same scan, taken from the station the instrument is still standing on. That is a genuinely useful pipeline ordering constraint. It does not state failure behavior or a when-not case, which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_projectsARead-only
List all projects on the instrument (id, projectName, projectUUID, nextProjectScanID).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered; the description contributes the 'on the instrument' scope and the exact field list, which tells the agent what shape of data comes back. It says nothing about ordering, pagination, or behavior when no instrument is connected.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and resource, with the field list tucked into a compact parenthetical. Nothing is wasted and nothing important is buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, listing id/projectName/projectUUID/nextProjectScanID in the description is the only disclosure of return shape and is appropriately included. The remaining gap is only the lack of any note on how downstream tools consume these project identifiers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4 — there is nothing for the description to compensate for. The parenthetical does useful double duty by naming returned fields rather than arguments.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb 'List' plus a precise resource ('projects on the instrument') and an enumeration of the fields returned. It is clearly distinguishable from siblings like scanner_scans or scanner_scan_modes by the word 'projects', though it never explicitly contrasts itself with them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to call this versus scanner_scans or scanner_status, and no stated prerequisites (e.g. needing a connected instrument). The likely use — resolving project IDs/names for other scanner calls — is left entirely to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_scanfile_infoBRead-only
Get metadata for one point-cloud file: file path, size, point count, and whether it has been downloaded.
| Name | Required | Description | Default |
|---|---|---|---|
| scan_file_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already tells the agent this is a safe read, and the description usefully discloses the returned fields (path, size, point count, downloaded flag). It says nothing about behavior on an invalid or missing scan_file_id, nor about permissions beyond openWorldHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with zero filler; the verb and resource lead and the returned fields follow immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only lookup with annotations covering safety and no output schema, listing the return fields gets close, but an agent still lacks guidance on sourcing scan_file_id and on failure behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the single required parameter scan_file_id is never mentioned in the description — no hint as to what an ID looks like or where to obtain one (presumably from scanner_scans). The description only describes outputs, not the input, so it does not compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Get metadata for one point-cloud file') and enumerates exactly which fields come back, making it distinguishable from siblings like scanner_download_scanfile. It does not explicitly name siblings, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The mention of 'whether it has been downloaded' hints at the natural check-before-download workflow, but the description never states when to use this versus scanner_download_scanfile or scanner_status. Usage is implied rather than instructed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_scan_modesARead-only
List the available scan modes (the density/range/time menu): mode name, range (m), point count, file size, scan time (s), spacing, and rate. Use these names when starting a scan.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered; the description adds the useful behavioral detail that the response is a live menu of currently available modes with specific attributes. It does not note that the set of modes is device/browser-dependent (openWorldHint), which is the one piece of context an agent might trip on.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the action and resource, then the payload fields, then the usage note. Every clause carries information and nothing is repeated from annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing returns and does so by enumerating the fields (mode name, range, point count, file size, scan time, spacing, rate). Complete for a lookup tool; only the dynamic/environment-dependent nature of the list is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline is 4. The schema is empty and fully described by its emptiness.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List the available scan modes') and immediately clarifies what a scan mode is with the parenthetical 'density/range/time menu'. No sibling tool (scanner_scans, scanner_status, etc.) returns this menu, so the distinction is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use these names when starting a scan' gives a concrete downstream usage instruction that tells the agent this is a discovery/lookup step feeding a scan-start call. It stops short of naming the specific scan-starting sibling or stating when not to call it, so it is clear context rather than explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_scansARead-only
List all scans as compact records (id, scanUUID, scanMode, points, file path, and the project folder the scan belongs to). Ids are list positions and change when scans are deleted; scanUUID is stable.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, openWorldHint), yet the description still adds real behavioral context: 'compact records' warns output is a summary, and the note that ids are volatile list positions while scanUUID is stable is a concrete caveat an agent must know to avoid caching a bad key. It does not disclose ordering, size limits, or auth requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler. The payload (what is listed, what fields come back) is front-loaded, and the id-versus-scanUUID caveat follows immediately as the single most actionable warning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and largely discharges it by naming the six record fields. What is left unsaid — ordering, whether the list is bounded, whether it spans all projects — is minor for a no-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4; there is nothing in the schema for the description to clarify. The description instead spends its words on the shape of the returned record, which is a reasonable use of the space.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List all scans') and enumerates the exact fields returned (id, scanUUID, scanMode, points, file path, project folder), which distinguishes it implicitly from detail-oriented siblings like scanner_scanfile_info. It never names a sibling explicitly, so it stops short of the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'List all scans' tells an agent this is the overview/listing entry point, and 'compact records' hints that it is not for full detail. There is no explicit when-to-use or when-not statement despite ten siblings (scanner_scanfile_info, scanner_projects, scanner_tasks) that an agent could easily confuse it with.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_statusARead-only
Get the instrument's current status: battery, AC state, leveling, on-board storage, IMU, laser-pointer, WiFi config (passphrase masked), and the active error list.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds one genuinely useful disclosure — the WiFi passphrase is masked — but says nothing about whether the call actively polls hardware, how long it takes, or whether values are cached.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the verb and then lists the returned state categories. No filler, no restating of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing the return value, and it does so by enumerating the status categories. It stops short of explaining shapes or units (e.g. battery as percent vs. voltage), which is a minor but real gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. Nothing about argument semantics needs explaining, and the description correctly implies a parameterless call.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clear verb+resource: 'Get the instrument's current status', then enumerates the exact fields returned (battery, AC, leveling, storage, IMU, laser, WiFi, errors). That enumeration implicitly distinguishes it from narrow siblings like scanner_errors or scanner_scan_modes, but no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (a snapshot of device health) but never says when to call this vs. scanner_errors, scanner_tasks, or scanner_scan_modes. The overlap with scanner_errors — since the active error list is included here — is left for the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_tasksARead-only
List running or queued tasks (e.g. a scan in progress) with their state and percent complete (0-100). An empty list means the instrument is idle.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds real value on top: it names the returned fields (state, percent complete with the 0-100 range) and, most usefully, explains that an empty list means the instrument is idle rather than an error — a non-obvious interpretation rule an agent would otherwise guess at.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The core purpose is front-loaded in the first clause, and the idle-state interpretation follows immediately as the one piece of non-obvious context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters and no output schema, the description carries the burden of describing the response, and it does so adequately by naming state, percent complete, and the empty-list meaning. It falls short only on routing: nothing tells the agent how this differs from scanner_status or when to poll this versus scanner_wait_for_scan.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. The description correctly spends no words on arguments and instead uses the space for return-value semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (list running or queued tasks) and describes the payload: state plus percent complete (0-100). That is concrete enough to distinguish it from write tools like scanner_preview_to_angles or scanner_download_scanfile, but it never differentiates itself from the closely-related scanner_status or scanner_wait_for_scan, which also read scanner state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer 'call this to see if a scan is in progress' from the scan-in-progress example and the idle-when-empty note. There is no explicit statement of when to prefer this over scanner_status or scanner_wait_for_scan, and no exclusions or prerequisites are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanner_wait_for_scanARead-only
Wait until no task is running (use after scanner_launch_scan), polling the
task list every poll_s seconds (0.5-30) for up to timeout_s (1-7200).
Reports progress to the client when supported. Returns
{done, timed_out, elapsed_s, last} where last is the final task snapshot.
| Name | Required | Description | Default |
|---|---|---|---|
| poll_s | No | ||
| timeout_s | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only and open-world nature, and the description adds real behavior: bounded polling interval, bounded timeout, and client progress reporting. It does not state what happens when no tasks are running at call time (immediate return?) or whether the timeout is a hard error, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the blocking behavior and the sequencing hint, then constraints, then return shape. Nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by naming the return fields {done, timed_out, elapsed_s, last} and explaining that `last` is the final task snapshot. For a two-parameter wait tool this is sufficient to invoke and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and carries only defaults and titles, so the description supplies the missing semantics: valid ranges of 0.5-30 for poll_s and 1-7200 for timeout_s. It does not describe unit rounding or what happens if poll_s exceeds timeout_s, but the core meaning is added beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific blocking verb ('wait') on a specific resource state ('until no task is running'), and ties it to the launch tool, which cleanly separates it from sibling reads like scanner_status or scanner_tasks. An agent can tell what this does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'use after scanner_launch_scan', which gives a clear sequencing rule. It does not contrast with scanner_tasks/scanner_status or state when-not to use it (e.g., if you just want a one-shot snapshot), so it stops short of full alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.12.1- First observed
scanner_download_preview - First observed
scanner_download_scanfile - First observed
scanner_errors - First observed
scanner_preview_to_angles - First observed
scanner_projects - First observed
scanner_scan_modes - First observed
scanner_scanfile_info - First observed
scanner_scans - First observed
scanner_status - First observed
scanner_tasks - First observed
scanner_wait_for_scan
TDQS
Scored across 11 tools
Most tools are clearly separable, but several pairs overlap: scanner_status already returns the active error list that scanner_errors returns separately, scanner_scans records already include points and file path that scanner_scanfile_info extends, and scanner_wait_for_scan is a polling wrapper around scanner_tasks. Descriptions mitigate these overlaps, but an agent still has to choose between near-duplicates.
All tools share a uniform snake_case 'scanner_' prefix, which makes the set very readable as a family. The only minor deviation is that some tools are bare noun getters (scanner_status, scanner_projects, scanner_errors) while others use verb phrases (scanner_download_scanfile, scanner_wait_for_scan, scanner_preview_to_angles).
At 11 tools the set is well-scoped for an instrument-control server: inspection (status, projects, scans, modes, errors, tasks), acquisition helpers (wait_for_scan, file info, two downloads), and one geometry converter each earn their place. Nothing feels padded or redundant by count.
Descriptions repeatedly reference scanner_launch_scan and scanner_launch_area_scan, but neither tool is present, so scanner_preview_to_angles and scanner_wait_for_scan point at operations the agent cannot perform — a severe dead end for the core workflow of actually starting a scan. There are also no create/delete operations for projects or scans, only listings.
Maintenance
Related MCP Connectors
Exposes FEDLIN's public security scanners as agent-callable tools over Streamable HTTP.
Scans remote MCP servers for protocol, security, and TLS issues; exposes scan tools via MCP.
Host any HTTP API as a standard MCP server; auto-distribute to 12+ mainstream agent platforms.
Agent-readiness scanner (0-5 score), robots.txt + llms.txt generators, managed agent enablement.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables agents to query LAVA board farms, submit and manage test jobs, and open interactive board sessions via the LAVA REST API.1MIT
- AlicenseAqualityCmaintenanceEnables AI assistants to query Bambuddy-managed 3D printers' status, current prints, diagnostics, camera snapshots, and archived print sources, and to safely start prints via a two-stage confirmation token while keeping sensitive credentials out of MCP output.9AGPL 3.0
- FlicenseNot gradedqualityCmaintenanceEnables local Mac agents to monitor and control Bambu Lab 3D printers via MCP tools, including status checks, camera snapshots, and print job management.-
- AlicenseNot gradedqualityCmaintenanceEnables coding agents to inspect and control BLACS and Runmanager over local Windows or SSH connections, including device-tab and queue state, shot queue editing, application restarts, Runmanager globals and compilation, and leased multi-command operations.MIT