uvc-ptz-camera-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| UVC_PTZ_DEVICE | No | Any substring of the camera name printed by --list-devices. Equivalent to the --device argument. A flag wins over the environment, and an empty value means 'not set'. | |
| UVC_PTZ_BACKEND | No | The backend to use: 'auto' (default, prefer a real camera and fall back to the simulator), 'dshow' (Windows DirectShow), or 'simulator' (no hardware). Equivalent to the --backend argument. A flag wins over the environment, and an empty value means 'not set'. | |
| UVC_PTZ_STATE_DIR | No | The directory used to store state. A flag wins over the environment, and an empty value means 'not set'. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| camera_statusA | Report the camera, its axes and ranges, and whether it is a real device. Call this first. It says which camera was found, the range each axis accepts, where the
camera believes it is pointing (a hint, not proof), what has been calibrated, and -- if
no real device was found -- the reason. |
| aimA | Point one axis at an absolute value, and return what the picture confirms.
This moves the camera and waits for it: allow roughly a second for a gimbal axis and
three for a zoom. |
| nudgeB | Move one axis relative to where the device says it is now. Relative moves inherit the device's reported position, which is a hint: after a series of nudges the accumulated position may drift from belief. The picture check still tells you whether this call moved the camera; it cannot tell you it is at an absolute angle. |
| sweepA | Move an axis smoothly to a value over a chosen duration. Use this for any move that should read as deliberate: a slow pan across a scene, a
gradual push in. The axis is driven by streaming absolute targets at 15 Hz rather than
one jump, which is how this hardware was measured moving smoothly. |
| zoomA | Set optical zoom as a multiplier: 1.0 is wide, up to the camera's maximum. Convenience over the raw zoom axis, which counts in hundredths. The requested ratio is clamped to what the camera supports and the clamped value is returned. |
| recentreA | Return every axis to the camera's own default: centre, level, unzoomed. |
| lookA | Capture one frame of what the camera currently sees, as a PNG image. This observes the camera's view. Call it when the user asks to see the picture, not on your own initiative, and be aware that a still only tells you what is in front of the lens -- not where the camera is, and not whether a move happened. |
| aim_learnA | Remember the current direction under a name, for later use. Pan is an absolute axis whose meaning depends on where the camera is standing, so
"point at the door" is unanswerable without recording it once. Call this with the camera
already pointed where you want, and the label becomes usable with |
| aim_listA | List the directions recorded for this camera, and its calibrated default pose. |
| go_toA | Point the camera at a direction recorded earlier with Each axis is moved and confirmed from the picture, the same as |
| plan_shotA | Compile a shot and report what it would do, without moving the camera. Takes exactly the step list Use this to compose a shot. It returns the per-step schedule (where each axis starts, the value it was clamped to, how far it travels, how many ticks it costs), the per-axis envelope, the total duration, and the axes with their ranges so the next attempt can be written against the real limits. Nothing is written to the camera and no frame is captured, so it is safe to call as often as you like while deciding. The |
| run_shotA | Execute a multi-step camera move, verifying after every waypoint. Each step is an object: {"axis": "pan", "to": 60, "seconds": 2.5, "ease": "in_out"}. Steps run in sequence and every axis that moves in a step is written on each tick, so a step naming two axes produces a genuine diagonal rather than a staircase. Add {"hold": 1.0} to pause after a step. The whole plan is validated against the camera's advertised ranges before anything moves, so an impossible shot fails without touching the hardware. Afterwards the report gives the picture difference at each waypoint, which is how you tell a shot that happened from one that did not. A long shot takes its full duration; do not set a host timeout shorter. |
| track_startA | Start following a subject, closing the loop on the picture. While this runs the server keeps capturing frames and moving the camera to hold the subject near the centre of the frame: detect, measure the offset, take a bounded step, look again. It decides only from the picture, because this class of camera's position report cannot be trusted -- and it reports the residual offset every iteration, so a loop that is losing the subject looks like one instead of seeming to work. It looks at whatever the camera sees for as long as it runs, which may be a room with people
in it. Start it when the user wants the camera following something, and stop it when they do
not. It also stops by itself: when the subject is lost for a while, when it settles inside
the dead zone, or after
|
| track_statusA | Report what the follow loop is doing, with the evidence for each iteration. Every iteration appears with the measured offset and the step applied, so a loop that is
driving the wrong way shows up as a residual distance that grows, and one whose moves the
picture never confirms shows up in |
| track_stopA | Stop following, and return the summary: what it saw, what it moved, what failed. |
| mark_viewA | Store the current picture under a label, so it can be compared later. Useful before a move whose result you will judge later, or to establish what "the wide shot" looks like. Marks live in memory for this session only. |
| check_viewA | Compare the current picture with one stored by Answers "is the camera still looking at what it was looking at?", which is the question a scene change can otherwise hide: a person walking through the shot changes the picture as much as a pan does, so treat a small difference as "still there" and a large one as "worth looking at". |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 17 tools
Most tools have distinct roles, but several movement tools overlap in surface: aim, nudge, sweep, go_to, zoom, and run_shot all move axes, and an agent must read descriptions closely to pick the right one. The descriptions do differentiate them effectively (absolute vs relative vs smooth-timed vs labeled-direction vs multi-step), and pairs like plan_shot/run_shot and mark_view/check_view are clearly complementary.
Names are consistently snake_case, with single verbs (aim, nudge, sweep, zoom, look) for atomic actions and verb_noun compounds (run_shot, track_start, mark_view, check_view, aim_learn) for compound operations. Minor deviations like camera_status (noun_noun) and go_to (verb_prep) break the verb pattern slightly but remain readable and predictable.
17 tools is slightly heavy but each earns a place: movement (aim, nudge, sweep, zoom, recentre, run_shot, plan_shot, go_to), tracking (track_start/status/stop), observation (look, mark_view, check_view), and calibration/presets (camera_status, aim_learn, aim_list). The one genuine redundancy is the plan/execute split, which still adds validation value.
The surface covers the full PTZ lifecycle: status/ranges, single- and multi-axis movement, smooth sweeps, tracking with evidence, named presets, image capture and comparison. The main gap is no explicit abort/cancel for an in-flight run_shot or sweep (only track_stop exists for the follow loop), which agents must work around with timeouts.