Skip to main content
Glama
mpolinowski

camera-mcp

by mpolinowski

INSTAR MQTT Camera MCP Server

Async MQTT runtime for INSTAR IP cameras with complete reconnect state machine, connection health separation, runtime hardening, and MCP integration.

Built on paho-mqtt>=2.1.0 with Paho sync client + isolated CommandExecutor worker. FastMCP-compatible fastmcp>=0.1.0 async API with Hermes Agent integration support.

Hermes MCP Integration

The runtime includes a production-ready MCP server consumable by Hermes Agent and other aagent harnesses:

user  ❯ Using the INSTAR camera integration, read if the red and yellow alarm area are enabled for camera 224. Use the available camera MCP tools. If the areas are disabled please toggle them on.

hermes-agent  ❯ Checked camera 224.

Red area alarm_areas_red_enable was disabled (0, known_but_stale). Yellow area alarm_areas_yellow_enable was disabled (0, known_but_stale).

Toggled them on:

alarm_areas_red_enable set to 1 → first attempt was clamped (camera stayed 0), second read shows it now observed as 1.
alarm_areas_yellow_enable set to 1 → confirmed observed as 1.
Both red and yellow alarm areas are now enabled on camera 224.

Prerequisites

  • Hermes Agent v0.21.0+ installed

  • INSTAR camera reachable via MQTT broker

  • camera-mcp installed locally

Install the package to make camera-mcp available:

git clone https://github.com/mpolinowski/instar-mqtt-mcp.git
cd instar-mqtt-mcp
pip install -e .
    Successfully built mqtt-runtime
    Installing collected packages: mqtt-runtime
    Attempting uninstall: mqtt-runtime
        Found existing installation: mqtt-runtime 0.1.0
        Uninstalling mqtt-runtime-0.1.0:
        Successfully uninstalled mqtt-runtime-0.1.0
    Successfully installed mqtt-runtime-0.1.0
which camera-mcp
~/.local/bin/camera-mcp

This installs the camera-mcp console script used by Hermes via stdio.

Installation hierarchy

Recommended — Catalog install (production)

Once the server is published to the Hermes catalog:

hermes mcp install instar-camera

The catalog manifest handles git checkout, pinned ref, venv bootstrap, and prompts for MQTT credentials. This is the supported production path.

Local development / testing

Use hermes mcp add when developing locally or testing without a published catalog entry:

echo "INSTAR_MQTT_HOST=<your-broker-host>" >> ~/.hermes/.env
echo "INSTAR_MQTT_PORT=<your-broker-port>" >> ~/.hermes/.env
echo "INSTAR_MQTT_USERNAME=<your-mqtt-user>" >> ~/.hermes/.env
echo "INSTAR_MQTT_PASSWORD=<your-mqtt-password>" >> ~/.hermes/.env
echo "INSTAR_MQTT_CLIENT_PREFIX=<your-topic-prefix>" >> ~/.hermes/.env
echo "INSTAR_MQTT_CAMERA_ID=<your-camera-id>" >> ~/.hermes/.env
source ~/.hermes/.env

NOTE: That these env variables will be available to your Hermes Agent. If you try to run test_application.py manually the code will fall back to .env - make sure you added your MQTT credentials there as well.

❯ hermes mcp add instar_camera \
  --command "$(which camera-mcp)"

  Connecting to 'instar_camera'...
  ✓ Connected! Found 6 tool(s) from 'instar_camera':
    set_camera_value                Set a camera capability value and wait for camera observatio...
    get_camera_state                Get current observed state of a camera capability.
Returns ...
    wait_camera_state               Wait for camera capability to reach expected value.
Blocks ...
    get_camera_health               Check operational health and connectivity of camera integrat...
    get_camera_image                Retrieve the most recently received image from camera.
This...
    list_camera_capabilities        List all capabilities/settings the camera runtime can operat...
  Enable all 6 tools? [Y/n/select]: y
  ✓ Saved 'instar_camera' to ~/.hermes/config.yaml (6/6 tools enabled)
  Start a new session to use these tools.

Hermes will probe the server, list the six tools, and prompt to enable them. After saving, verify:

hermes mcp list
hermes mcp test instar_camera

 MCP Servers:

 Name             Transport                      Tools        Status
 ──────────────── ────────────────────────────── ──────────── ──────────
 instar_camera    ~/.local/bin/...   all          ✓ enabled

 Testing 'instar_camera'...
 Transport: stdio → ~/.local/bin/camera-mcp
 Auth: none
 ✓ Connected (1360ms)
 ✓ Tools discovered: 6
   set_camera_value            Set a camera capability value and wait for camera obser...
   get_camera_state            Get current observed state of a camera capability.
Returns...
   wait_camera_state           Wait for camera capability to reach expected value.
Blocks...
   get_camera_health           Check operational health and connectivity of camera int...
   get_camera_image            Retrieve the most recently received image from camera.
This...
   list_camera_capabilities    List all capabilities/settings the camera runtime can o...

Expected output shows 6 tools discovered and status ✓ enabled.

Environment variables required by the server:

  • INSTAR_MQTT_HOST — MQTT broker hostname

  • INSTAR_MQTT_PORT — MQTT broker port, default 1883

  • INSTAR_MQTT_USERNAME — MQTT username

  • INSTAR_MQTT_PASSWORD — MQTT password

  • INSTAR_MQTT_CLIENT_PREFIX — MQTT topic prefix, default cameras

  • INSTAR_MQTT_CAMERA_ID — Camera ID, default 224

You can also persist these in ~/.hermes/.env and reference them via --env INSTAR_MQTT_HOST=... on add, or edit ~/.hermes/config.yaml under mcp_servers.instar_camera.env.

Skill Integration

A Hermes skill instar-camera ships with the repo at skills/instar-camera/SKILL.md. The skill is independent of MCP installation and teaches the agent when and how to use the camera tools without constructing MQTT topics manually.

For local use, copy the skill to Hermes' skill path:

mkdir -p ~/.hermes/skills/home-automation/instar-camera
cp ~/Projects/instar-mqtt-mcp/skills/instar-camera/SKILL.md ~/.hermes/skills/home-automation/instar-camera/

Hermes will discover it as a local skill and guide the agent to select the correct MCP tools after you restarted the service. Once the catalog entry is upstream, the skill remains a separate user-facing asset.

The catalog manifest optional-mcps/instar-camera/manifest.yaml defines:

  • git install with pinned ref

  • bootstrap venv + pip install

  • stdio transport command: "${INSTALL_DIR}/.venv/bin/camera-mcp"

  • auth.env prompts for the six MQTT variables

  • six tools default-enabled

See docs/hermes.md for complete configuration.

Available MCP Tools

The server exposes six tools:

  • set_camera_value - Change camera setting with confirmation

  • get_camera_state - Get observed state with confidence

  • wait_camera_state - Wait for state change

  • get_camera_health - Check broker/camera connectivity

  • get_camera_image - Retrieve latest periodic snapshot

  • list_camera_capabilities - Discover camera settings

Hermes registers these as mcp_instar_camera_*.

Skill Integration

A Hermes skill instar-camera ships with the repo at skills/instar-camera/SKILL.md. For local use, copy it to Hermes skill path:

mkdir -p ~/.hermes/skills/home-automation/instar-camera
cp skills/instar-camera/SKILL.md ~/.hermes/skills/home-automation/instar-camera/

Hermes will discover it as a local skill and guide the agent to use the MCP tools safely without manual MQTT topic construction.

See skills/instar-camera/SKILL.md for agent usage guidelines.

Related MCP server: MQTT MCP Server

Architecture

  • Paho sync client with loop_start() background network thread

  • Single CommandExecutor worker owns all Paho calls and state mutations

  • Async callers enqueue operations and await futures via loop.call_soon_threadsafe

  • Ownership invariant: Executor is the only component allowed to call Paho APIs or mutate application state. Paho callbacks only enqueue inbound events.

Project Structure

mqtt_runtime/
├── camera.py              # Public async API
├── executor.py            # CommandExecutor worker thread
├── paho_bridge.py         # Paho callbacks only enqueue
├── models.py              # StateEntry, Command, Confidence, Events
├── state_cache.py         # Confidence model, disconnect downgrade
├── subscription_registry.py # No wildcards, explicit topics only
├── command_manager.py     # FIFO, idempotency, superseding
├── topic_registry.py      # Topic metadata from topics.py + API docs
├── topics.py              # 740 topic definitions
├── event_queue.py         # Inbound/operation queues
└── experiments.py         # Paho behavior experiments

tests/
├── run_tests.py
└── unit/                  # 14 test suites
    ├── test_ownership.py
    ├── test_state_cache.py
    ├── test_command_lifecycle.py
    ├── test_async_boundary.py
    ├── test_connection_state_machine.py
    ├── test_subscription_registry.py
    ├── test_shutdown.py
    ├── test_concurrency.py
    ├── test_event_stream.py
    ├── test_payload_parsing.py
    ├── test_phase2_reconnect.py
    ├── test_phase2_health.py
    ├── test_phase2_events.py
    └── test_phase2_images.py

main.py                    # Live demo: toggle red alarm area

Quick Start

Install

pip install -r requirements.txt
pip install python-dotenv

Broker Configuration

The MQTT broker host, port, username, password, client prefix and camera ID must be provided via environment variables. Do not use hardcoded defaults.

Production / Hermes: Configure them in ~/.hermes/.env via the catalog manifest prompts. They are injected into the MCP server at runtime.

Local development: Create a .env file in the repository root with the six variables:

INSTAR_MQTT_HOST=...
INSTAR_MQTT_PORT=...
INSTAR_MQTT_USERNAME=...
INSTAR_MQTT_PASSWORD=...
INSTAR_MQTT_CLIENT_PREFIX=...
INSTAR_MQTT_CAMERA_ID=...

The application automatically loads this file via python-dotenv. Do not commit .env to version control.

Live Demo

python3 main.py

Toggles alarm/areas/red/enable via plain MQTT and TLS (insecure), verifies state with confidence tracking.

Programmatic Usage

from mqtt_runtime.camera import Camera

camera = Camera(client_prefix=os.getenv("INSTAR_MQTT_CLIENT_PREFIX"), camera_id=os.getenv("INSTAR_MQTT_CAMERA_ID"))

await camera.connect(
    host=os.getenv("INSTAR_MQTT_HOST"),
    port=int(os.getenv("INSTAR_MQTT_PORT", "1883")),
    username=os.getenv("INSTAR_MQTT_USERNAME"),
    password=os.getenv("INSTAR_MQTT_PASSWORD"),
    use_tls=False,
)

# Relative path resolves via TopicRegistry
state = await camera.get_state("alarm/areas/red/enable")
print(state)  # {'value': '1', 'confidence': 'observed', ...}

await camera.set_value("alarm/areas/red/enable", "0")
await camera.subscribe("alarm/areas/red/enable")

await camera.close()

Public API

  • await camera.connect(host, port, username, password, client_prefix, camera_id, use_tls, tls_insecure)

  • await camera.close()

  • await camera.set_value(topic, value, timeout=...) — topic resolves via registry

  • await camera.get_state(topic)

  • await camera.wait_for_state(topic, expected, timeout=...)

  • await camera.subscribe(topic)

  • await camera.unsubscribe(topic)

  • await camera.check_health() — returns HealthResult with broker_connected and camera_online

  • await camera.get_image(topic) — decode image outside callback path

  • camera.events() — async iterator for CameraEvent (STATE_CHANGED, CONNECTION_CHANGED, COMMAND_COMPLETED, ERROR)

Topic Metadata

Catalogue of 663 stateful topics from:

  • mqtt_runtime/topics.py — authoritative topic list + type/flags

  • topics/api/_extracted.json — descriptions + value hints

Topic naming:

  • Read (status): {prefix}/{id}/status/<path> — retained

  • Write (command): {prefix}/{id}/<path> — publishes {"val": "..."}

Phase 2 Features

Phase 0 (Complete)

  • ✅ Executor ownership model

  • ✅ Async bridge with loop.call_soon_threadsafe

  • ✅ Worker supervision

  • ✅ Connection state machine

  • ✅ Subscription registry (no wildcards)

  • ✅ State confidence model (UNKNOWN / KNOWN_BUT_STALE / OBSERVED)

  • ✅ Disconnect downgrade: OBSERVED → KNOWN_BUT_STALE

  • ✅ Retained messages never confirm commands

  • ✅ Command lifecycle with FIFO per topic

  • ✅ Idempotency and superseding

  • ✅ Event stream

  • ✅ Shutdown resolves all futures

Phase 1 (Complete)

  • ✅ Command confirmation requires OBSERVED confidence tier and non-retained message

  • ✅ Same-topic commands produce last-wins final camera state

  • ✅ UNCHANGED decided before publish from fresh OBSERVED state

  • ✅ CLAMPED as valid observed different value

  • ✅ Worker failures resolve pending futures

  • ✅ Queued commands may resume after reconnect

Phase 2 (Complete)

  • ✅ Complete reconnect state machine with exponential backoff

  • ✅ Subscription restoration hardening with pending additions/removals

  • ✅ Connection health separation: broker_connected vs camera_online

  • ✅ StateCache production hardening with immutable snapshots and bounded LRU

  • ✅ Public event stream API with bounded queue and diagnostics

  • ✅ Public async API stabilization

  • ✅ Image/content support with LRU cache and base64 validation

  • ✅ MCP adapter boundary with Result model

Testing

python3 tests/run_tests.py

14 test suites, all passing. Tests verify ownership boundaries, async isolation, state transitions, command lifecycle, reconnect behavior, health separation, event ordering, image handling.

Phase 2 Verification Report

  • Test Suites: 14 / 14 passing

  • Phase 0 Guarantees: Preserved

  • Phase 1 Guarantees: Preserved

  • Phase 2 Guarantees: Reconnect deterministic, state confidence enforced, MCP adapter ready

  • Remaining: Empirical Paho runtime verification against live broker

Migration from mcp_server.py

mcp_server.py deleted. Functionality migrated to:

  • mqtt_runtime/topic_registry.py — TopicRegistry + CameraTopic

  • mqtt_runtime/camera.py — Async API

  • mqtt_runtime/topics.py — Moved from topics/topics.py

Old synchronous API replaced with async ownership model.

Security

  • Credentials via parameters, never source

  • TLS opt-in, cert verification default

  • No wildcards allowed in subscriptions

  • Worker failure isolates per-operation errors

Available Tools

6 tools
get_camera_healthGet Camera HealthA

Check operational health and connectivity of camera integration.

Distinguishes between MCP server availability and camera/broker connectivity.

Returns operational state:

  • MCP server alive: process is running

  • MQTT broker connected: broker reachable

  • Camera online: camera publishing state messages

  • Camera offline: broker connected but no camera messages

MCP server starts successfully even if camera is offline. Use this tool to diagnose connectivity issues rather than assuming MCP failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
cameraYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and handles it well. It defines exactly what each operational state means, explains that the MCP server can start successfully even when the camera is offline, and distinguishes server availability from broker and camera connectivity. This gives the agent useful diagnostic context beyond the tool name.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, front-loaded with the core purpose, and uses a well-organized bullet list for the operational states. Every sentence adds meaningful information, and there is no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter diagnostic tool with an output schema, the description is complete. It explains the possible operational states, the relationship between server/broker/camera, and the right situation in which to use the tool. An agent can reasonably select and invoke this tool without needing additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema only shows one required 'camera' string parameter with 0% description coverage, so the description should compensate. It does imply that 'camera' refers to the camera being health-checked and clarifies what 'online' and 'offline' mean for that camera. However, it never explicitly describes the expected value format or how to identify the camera, so the parameter semantics are only partially covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Check operational health and connectivity of camera integration.' It clearly distinguishes this tool from siblings like get_camera_state, get_camera_image, and set_camera_value by focusing on health/diagnostics rather than state retrieval, imaging, or control.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to 'Use this tool to diagnose connectivity issues rather than assuming MCP failure,' which is clear when-to-use guidance. It also clarifies that MCP server health and camera/broker connectivity are separate concerns. It does not explicitly name alternative sibling tools, so it stops short of a full when-to-use versus alternative comparison.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_camera_imageGet Camera ImageA

Retrieve the most recently received image from camera.

This retrieves a cached periodic snapshot published by the camera. It does NOT trigger a new photograph or snapshot.

INSTAR cameras publish snapshots periodically via MQTT. This tool returns the latest received image if available.

max_age parameter enforces freshness: image rejected if older than max_age seconds. Returns confidence metadata:

  • OBSERVED: live image received after connection

  • KNOWN_BUT_STALE: retained image or downgraded after disconnect

Do not treat stale images as current live images.

Use list_camera_capabilities to find image sources (type=image).

ParametersJSON Schema
NameRequiredDescriptionDefault
cameraYes
sourceYes
max_ageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden, and it does so thoroughly. It explains MQTT periodic publishing, cached/non-triggering behavior, max_age freshness rejection, confidence metadata states (OBSERVED and KNOWN_BUT_STALE), and warns against treating stale images as live. This is model transparency beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although longer than a one-liner, every sentence earns its place: the core action, the cached/no-trigger caveat, MQTT context, max_age semantics, confidence metadata, the stale-image warning, and source discovery. The structure is front-loaded and uses a clear bullet list, making it easy for an agent to parse the essential behavior quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a camera image retrieval tool with no annotations and zero parameter description in the schema, this definition is highly complete. It covers purpose, behavioral caveats, freshness rules, confidence interpretation, and prerequisite source discovery. An output schema exists, so detailed return field documentation is not required from the description. No significant call-blocking gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It thoroughly explains the max_age parameter including its freshness enforcement, and it tells the agent to use list_camera_capabilities to identify valid image sources. It does not elaborate on the camera identifier or the exact format of source values, which are otherwise undocumented, but the highest-risk parameter is well covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Retrieve the most recently received image from camera.' It immediately clarifies that this is a cached periodic snapshot and does NOT trigger a new photograph, clearly distinguishing it from other camera tools. The scope is precise and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: it returns the latest cached MQTT-published image, and max_age enforces freshness. It also explicitly warns that it does NOT trigger a new capture and points to list_camera_capabilities for finding image sources. However, it does not name a concrete alternative for intentionally triggering a fresh photograph, so it stops slightly short of complete alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_camera_stateGet Camera StateA

Get current observed state of a camera capability.

Returns the most recently observed value with confidence metadata.

Confidence levels:

  • OBSERVED: freshly observed from camera via non-retained MQTT message

  • KNOWN_BUT_STALE: value known but not freshly observed (retained or downgraded after disconnect)

  • UNKNOWN: no state available

Do not treat KNOWN_BUT_STALE as current. For fresh state, wait for observation.

Use list_camera_capabilities to discover valid settings.

ParametersJSON Schema
NameRequiredDescriptionDefault
cameraYes
settingYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are absent, so the description carries the full burden. It discloses the confidence levels (OBSERVED, KNOWN_BUT_STALE, UNKNOWN) and their meanings, which is critical behavioral information about data freshness and reliability. It also warns about stale data. However, it doesn't specify the exact return structure beyond 'most recently observed value with confidence metadata', which might be partially covered by the output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is reasonably concise, with a clear first sentence stating purpose, followed by confidence level explanations and usage guidance. The structure is logical, front-loading the core purpose and then detailing the confidence semantics. Could be slightly shorter by merging some sentences, but it's well-organized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (confidence levels) and the presence of an output schema (which may define return format), the description covers the critical aspects: what it returns, the confidence semantics, and how to handle stale data. It also points to the sibling for discovering valid settings. The only minor gap is lack of explicit mention of parameter values or examples, but the pointer to list_camera_capabilities mitigates that.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, meaning the schema only provides types (string) without any descriptions. The description adds semantics by referencing 'camera capability' and 'setting', but doesn't elaborate on what values are valid beyond pointing to list_camera_capabilities. It partially compensates for the lack of schema descriptions but doesn't fully define parameter meanings.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves the current observed state of a camera capability, with 'camera' and 'setting' parameters. It distinguishes itself from siblings like list_camera_capabilities and set_camera_value by focusing on state retrieval. However, it doesn't explicitly state it's a read-only operation compared to set_camera_value, though the context implies it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises when to use this tool versus others: 'Use list_camera_capabilities to discover valid settings' and warns not to treat KNOWN_BUT_STALE as current, suggesting wait_camera_state for fresh state. This provides clear routing and usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_camera_capabilitiesList Camera CapabilitiesA

List all capabilities/settings the camera runtime can operate.

Primary discovery primitive. Returns authoritative capability names, types, writable flags, descriptions, and value constraints.

Always use this before attempting unfamiliar camera settings.

Never construct MQTT topics manually. The server maps capability names to topics via the registry. Hermes must not infer topic names from capability names.

Returns structured list of capabilities with metadata for agent decision making.

ParametersJSON Schema
NameRequiredDescriptionDefault
cameraYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses that results are authoritative and include writable flags/value constraints, and exposes the server-side topic-mapping constraint ('Never construct MQTT topics manually'), which is important non-obvious behavior. It does not discuss side effects or auth, but as a discovery/list action the read-only nature is reasonably implied.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is scannable and front-loaded: the core purpose appears first, followed by return semantics, usage rule, and the critical MQTT warning. The final sentence mildly repeats the earlier return-value statement, so it is not perfectly lean, but it remains appropriately compact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool with an output schema, the description covers the primary usage, return metadata, and a critical integration constraint. However, it leaves the camera parameter underspecified and does not explicitly route to siblings for state/health/value operations, so there is a clear completeness gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single required parameter 'camera' has no schema description (0% coverage), and the description does not explain what identifier to pass, its format, or how to discover valid camera IDs. With such low schema coverage the description needed to compensate, but it does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('List all capabilities/settings') against a clear resource ('camera runtime') and names the exact content returned (authoritative names, types, writable flags, descriptions, value constraints). Calling it the 'Primary discovery primitive' clearly separates it from sibling state/health/image tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit invocation guidance: use this tool before attempting unfamiliar camera settings, and never infer MQTT topics. It does not name alternative tools or exclusion cases, but the context is strong enough for an agent to know when to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_camera_valueSet Camera ValueA

Set a camera capability value and wait for camera observation confirmation.

Requests a camera setting change via MQTT and waits for the camera's observed state. The operation does not succeed simply by sending the command; it requires fresh observation.

Use list_camera_capabilities to discover valid settings and value types.

Returns result status:

  • confirmed: requested value was observed by camera with confidence OBSERVED

  • clamped: camera applied a different valid value (clamped to allowed range)

  • unchanged: requested value was already freshly observed, no publish necessary

  • timeout: fresh confirmation not obtained within timeout

Result is authoritative based on observed state, not requested value.

ParametersJSON Schema
NameRequiredDescriptionDefault
valueYes
cameraYes
settingYes
timeoutNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully carries the behavioral disclosure burden. It transparently states that the operation requires fresh observation, may return clamped/unchanged/timeout outcomes, and is authoritative based on observed state rather than the requested value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core behavior and uses a compact bulleted status list with no filler. Its length is justified by the non-obvious observation-confirmation workflow and the need to explain non-trivial result semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and a sparse schema, the description covers the async MQTT nature, the need for fresh observation, required discovery steps, and all meaningful result states. It leaves parameter-level type details to list_camera_capabilities, which is a reasonable division of labor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no descriptions and the 'value' parameter is untyped, so the description must compensate. It clarifies 'setting' and 'value' by pointing to list_camera_capabilities, and 'timeout' is referenced via the timeout result status, but individual parameter meaning remains under-specified.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Set') with a clear resource ('camera capability value') and adds the distinctive waiting-for-observation-confirmation behavior. It clearly separates this tool from sibling list/get/wait tools by emphasizing the set-and-verify action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs agents to use list_camera_capabilities to discover valid settings and value types before invoking this tool. It establishes a clear set-and-verify workflow, though it does not explicitly contrast it with wait_camera_state or other sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_camera_stateWait Camera StateA

Wait for camera capability to reach expected value.

Blocks until the camera observes the expected value or timeout occurs. Requires fresh OBSERVED confidence, not stale state.

Use this to confirm state changes after set_camera_value.

Returns success when expected value is observed with OBSERVED confidence. Timeout if value not observed within timeout period.

ParametersJSON Schema
NameRequiredDescriptionDefault
cameraYes
settingYes
timeoutNo
expected_valueYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well: it discloses blocking behavior, timeout behavior, the requirement for fresh OBSERVED confidence rather than stale state, and the success/failure conditions. This is strong behavioral transparency for a waiting/observation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, followed by behavior, usage, and return semantics. It is slightly repetitive ('Blocks until...' and later 'Timeout if value not observed within timeout period'), but overall it remains efficient and readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description adequately covers the tool's blocking and timeout behavior, usage context, and success/failure conditions, especially since an output schema exists. However, parameter semantics are mostly unexplained, and the expected_value type and timeout units are omitted, leaving a meaningful gap for a tool with no annotations and 0% schema coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for the undocumented parameters. It references 'expected value' and 'timeout period' but never defines the meaning or format of `camera`, `setting`, `expected_value`, or the units for `timeout`. The mapping from parameters to 'camera capability' is implied but not explicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Wait for') and a specific resource ('camera capability to reach expected value'), and clearly differentiates this tool from its siblings: it blocks and observes rather than listing, setting, or getting state. The phrase 'confirm state changes after set_camera_value' further anchors its distinct role.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this to confirm state changes after set_camera_value,' giving clear context for when the tool is appropriate. It does not explicitly state when not to use it or name alternatives, but the intended usage is unambiguous.

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.

  1. 6 tool updatesv0.1.0
    • First observedget_camera_health
    • First observedget_camera_image
    • First observedget_camera_state
    • First observedlist_camera_capabilities
    • First observedset_camera_value
    • First observedwait_camera_state

TDQS

A4.3/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing capabilities, setting values, getting state, waiting for state, checking health, and retrieving images. No overlap exists, making tool selection unambiguous.

Naming Consistency5/5

All tool names follow a consistent verb_camera_noun pattern using snake_case (list_camera_capabilities, set_camera_value, get_camera_state, wait_camera_state, get_camera_health, get_camera_image). The naming is predictable and uniform.

Tool Count5/5

With 6 tools, the server is well-scoped for camera control and monitoring. Each tool serves a necessary function without redundancy, fitting the expected range for this domain.

Completeness4/5

The tool set covers core lifecycle operations: capability discovery, setting values, reading state, waiting for confirmation, health monitoring, and image retrieval. A minor gap is the lack of a tool to trigger a new snapshot, but since cameras publish periodically, this is acceptable.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers