STM32 GDB MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| STM32_GDB_MCP_HIL | No | Set to 1 to enable hardware-in-the-loop validation. | |
| STM32_GDB_MCP_HUB_MODE | No | Controls hub daemon behavior: auto (default) uses the daemon and falls back to in-process when unavailable; daemon never falls back; local uses the old single-process behavior. | auto |
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
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| start_debug_sessionA | Starts the specified GDB Server (openocd, stlink, jlink) and connects the GDB Client to it. openocd REQUIRES server_args naming the probe and target, e.g. ['-f','interface/stlink.cfg','-f','target/stm32l4x.cfg'] — without them OpenOCD cannot find a config or adapter. Omitted values come from the active debug profile. |
| stop_debug_sessionB | Stops the GDB client/server, variable tracking, and all active RTT/SWO/UART readers. |
| self_checkA | Validates the link right after connecting: reads CPUID and DBGMCU IDCODE and checks byte order, that a real Cortex-M is present, and that the device matches the expected family (from the profile MCU or the 'expected_family' arg). Run this first to catch endianness/config faults before debugging. Halts the core first (identity reads are unreliable while running); pass halt=false to skip. |
| detect_probeA | Lists physical ST-Link, J-Link, and CMSIS-DAP probes currently connected over USB. Preserves serial numbers so multiple identical probes are never silently collapsed. |
| suggest_server_argsA | Returns the correct OpenOCD server_args for an MCU family + probe (e.g. STM32L431 + stlink -> ['-f','interface/stlink.cfg','-f','target/stm32l4x.cfg']) and validates the config files exist in OpenOCD's bundled scripts dir. Call this to get start_debug_session args — do NOT search the disk for .cfg files. |
| set_adapter_speedA | Sets the SWD/JTAG adapter clock (kHz) at runtime. The default ST-Link speed is only ~480 kHz; raising it (e.g. 4000) speeds up flashing and memory reads ~8x. Lower it if reads/flash become unreliable. |
| batchA | Runs several tool calls in ONE round trip and returns ALL their full results — the fastest way to do a sequence of operations (e.g. read registers + backtrace + several variables) without per-call latency. ok is false if ANY step failed; data.succeeded/data.failed count the outcomes (count/total only count steps run vs requested). Pass session to run every step against a named debug session. |
| callA | Invoke ANY stm32-gdb-mcp tool by name — including one that is NOT in your current tool list (clients with tool-count limits may hide some). Use this to reach e.g. start_debug_session when it isn't directly listed: call(tool='start_debug_session', args={...}). Returns that tool's result. |
| call_readA | Like call, but restricted to tools that only READ state — so it needs no approval prompt where call, which can reach anything, does. Prefer it for hidden read-only tools: call_read(tool='read_core_registers', args={}). The gate is per-ACTION, not per-tool: a family's reading action goes through even though the family also writes, so call_read(tool='debug_profile', args={'action':'get'}) works while action='set' does not. A refusal names the actions it would accept. Refuses anything that writes; use call for those. |
| tool_helpA | Returns descriptions and complete schemas for full-surface tools, including tools hidden in compact mode. |
| mcp_infoA | Identifies THIS running stm32-gdb-mcp server: release version, git commit, the package directory the code was imported from (plus the install root the git probe used), whether compact mode is hiding tools, and how many tools this build advertises versus how many exist. Needs NO debug session, NO probe and NO target — call it the moment a tool you expect is missing or behaves like an older build, instead of guessing which checkout the client actually launched. |
| recover_sessionA | Recovers a dropped or wedged session: cleanly tears down the GDB client and server, then restarts the server (with retry/backoff for a busy probe) using the last start_debug_session arguments and reconnects. Use after a probe_unavailable or connection_lost error. When a programmable USB hub is configured (debug_profile hub.channel), a retry that cannot fix the probe escalates to toggling its USB data lines and then power-cycling the port -- the only in-band cure for a wedged endpoint. Any hub action taken is reported in recovery_steps. |
| build_firmwareA | Builds firmware with Keil uVision (UV4), CMake, make, or a custom command, so the AI can rebuild after a fix. Keil emits a .axf (ELF/DWARF) that the debug tools load like any .elf. Returns the exit code, success flag, and build log tail. |
| load_symbolsA | Loads symbols from an ELF/AXF into the current GDB session WITHOUT flashing. Symbols are per-session, so after a fresh connect or recover_session you need this (or flash_firmware) before symbol breakpoints resolve. Falls back to the debug profile's elf_path if elf_path is omitted. |
| flash_firmwareA | Flashes a compiled firmware binary to the target. Accepts GCC .elf or Keil .axf. By default it then resets and RUNS the firmware (Keil-style 'Load + Run'). Pass reset_run=false to flash only (e.g. to set breakpoints before the firmware starts). Refuses (elf_layout_unsupported) an image GDB would flash incompletely, such as a Keil ARMCC5 AXF whose RW initializer lies outside its segment; flash its fromelf BIN instead. |
| reset_targetA | Resets the target device. Can optionally halt immediately after reset. strategy="cold" removes target power through a configured programmable USB hub before resetting, which is the only strategy that produces a true power-on reset (RCC_CSR POR flag, cleared .noinit, drained RAM); it fails rather than silently doing a warm reset when no hub channel is mapped. It needs no confirm argument -- asking for a cold reset by name IS the confirmation the hub guard wants -- and it stops the GDB session before the cut, then re-establishes it. |
| continue_executionA | Resumes execution of the target device until the next breakpoint. Safe to call when the target is already running (reports already_running instead of erroring), so 'make sure it is running' is expressible. |
| halt_executionC | Interrupts/halts the target device execution. |
| run_and_waitA | Resumes the target and waits, returning a structured stop event (reason, symbolized frame, breakpoint id, signal) or a timeout. Use this instead of continue_execution + polling to close the debug loop. |
| debug_untilA | One-call repro step: set an optional conditional/temporary breakpoint at a location, run, and return the stop event PLUS the decoded backtrace and innermost-frame locals. Collapses set_breakpoint + run + read frame/vars into a single round-trip. |
| capture_stateA | One-call 'where am I': decoded core registers + a PC/LR/SP summary, the decoded backtrace, and the innermost-frame locals. The fastest way to get full halted context. |
| flash_and_runA | One-call bring-up: flash an ELF (loads symbols), reset-halt, set a temporary breakpoint at an entry point (default 'main'), run to it, and return the decoded stop context. With hub_channel (or usb_location) and no session running, it starts one pinned to that probe first -- so 'flash the firmware on channel 4' is this single call, on a bench with several probes, without disconnecting any of the others. |
| run_for_durationA | Runs the target freely for a wall-clock duration, halts it, and returns one structured report with final frame/context and optional expression captures. Useful for counters, telemetry buffers, polling loops, and timing-sensitive bus diagnostics without breakpoint perturbation. |
| wait_for_stopA | Waits for the next stop event WITHOUT resuming the target, returning a structured stop event or a timeout. |
| stepA | Single-steps the target: kind='over' (over the line), 'into' (into calls), 'out' (run until the function returns), or 'instruction' (one machine instruction; set over=true to step over a call). |
| read_variableA | Reads the value of a C variable currently in scope. |
| read_memoryA | Reads a block of memory from the target. Returns the raw bytes in memory order, plus value_le -- the same bytes as one little-endian value -- for a 1/2/4/8-byte read. Use value_le for a peripheral register: the raw string arrives least-significant-byte first, so reversing it by hand is where bit positions get misread. |
| write_memoryC | Writes a value to a specific memory address. |
| read_call_stackA | Reads the call stack as a decoded list of frames {level, func, file, line, addr} plus a one-line summary. Set include_raw=true to also get the raw GDB output. |
| diagnose_faultB | Reads and decodes Cortex-M fault registers into likely fault causes. |
| configure_debug_freezeA | Freezes peripherals (IWDG, WWDG, RTC, timers) while the core is halted via the DBGMCU freeze registers, so the watchdog cannot reset the target out from under the debugger. Family is taken from the debug profile MCU if omitted. |
| analyze_stackA | Reports stack used/free bytes and a clear overflow verdict for the halted core. stack_top defaults to the initial MSP (first word of the vector table at vector_table_addr). Give stack_size or stack_limit for the overflow check (else only usage is reported). The key tool for diagnosing stack overflows. |
| reconstruct_fault_contextA | Reconstructs the full crash site after a HardFault: decodes fault registers, unwinds the auto-stacked exception frame from MSP/PSP via EXC_RETURN to recover the true faulting PC, and resolves it to source file:line. Run this when halted in a fault handler. |
| inspect_projectB | Discovers firmware project artifacts such as ELF, map, linker script, SVD, and STM32CubeMX .ioc metadata. |
| detect_rtosA | Detects whether FreeRTOS symbols are available in the current GDB session. |
| read_freertosA | Reads FreeRTOS state by 'what': 'current_task' (pxCurrentTCB), 'tasks' (ready list: names/priorities/TCB/stack), 'task_lists' (ready/delayed/suspended/deleted), 'queue' or 'mutex' (needs handle = a Queue_t expression), or 'heap' (heap_4/5 usage). |
| load_svdC | Loads an SVD file for peripheral parsing. |
| read_peripheral_registerA | Reads a peripheral register using its name from the loaded SVD. |
| decode_peripheral_registerB | Reads and decodes a peripheral register with SVD bitfield names and enumerated values. |
| track_variableA | Background variable tracking: action='start' (needs variable + interval_ms), 'stop', or 'get' (returns the sampled data for trend/leak analysis). |
| get_sessionA | Returns this session's record by view: 'journal' (every tool call with args/ok/summary/duration; supports limit), 'timeline' (compact human-readable replay), or 'metrics' (per-tool call counts, success/failure, durations). |
| clear_session_journalB | Clears the session journal (keeps the run-id). |
| list_sessionsA | Lists all debug target sessions (the 'default' one plus any named) with their liveness and port. To debug MULTIPLE boards at once, pass a 'session' argument (any string) to any tool — e.g. start_debug_session(session='rackA', ...) — and each gets fully isolated state. |
| close_sessionB | Closes a named debug session, tearing down its GDB client and server. |
| report_issueA | Files a GitHub issue about an MCP problem from THIS session — auto-bundling the session journal, metrics, and MCP version into a structured report (via the gh CLI). Call this when a tool misbehaves or confuses you. Deduplicated per session so retries don't spam. Defaults to the stm32-gdb-mcp repo. |
| export_debug_reportA | Writes a single self-contained JSON report (journal + metrics + profile, optionally a state snapshot and a coredump) tied to the run-id, so a bug session is fully reproducible and shareable from one artifact. |
| run_scenarioA | Replays a declarative scenario — a list of {tool, args} steps — deterministically and returns a per-step pass/fail report. Provide inline 'steps' or a 'path' to a JSON scenario file. The minimal-step way to re-run a complex bug repro. |
| run_to_lineB | Runs until a given location is reached (function, 'file.c:42', or '*0xADDR'). |
| disassembleC | Disassembles N instructions at a location (default $pc). |
| verify_flashA | Verifies that target flash matches an ELF (GDB compare-sections). Compares read-only sections, which is what lives in flash; writable sections hold the ELF's initial RAM values and always differ once the firmware has run, so including them would fail every healthy target. Pass include_writable=true only right after a load, before the target has executed. |
| flash_eraseA | Erases a flash range on the target (OpenOCD 'flash erase_address pad'), rounding out to the driver's erase-sector boundaries. The recovery tool for a board that will not boot: clearing a corrupt OTA journal, a stale boot descriptor, or a half-written image. Requires an explicit address AND length — there is deliberately no mass-erase default. |
| setup_swoA | One-call SWO/ITM printf setup. Configures the target's TPIU+ITM from the debugger (no firmware ITM-init needed) for the given core clock (hclk_hz) and SWO baud, and returns the OpenOCD capture commands + the firmware printf retarget snippet. Then capture with logging(action=start, channel='swo', file=). Requires the SWO pin (e.g. PB3) wired to the probe. |
| sample_pcA | Statistical PC profiler: enables DWT and samples the program counter while the core RUNS (non-intrusive, over SWD — no SWO pin or firmware change). Returns a symbolized hot-spot histogram (top functions by %), not raw hex — the fast way to find where firmware spends time or what loop it is stuck in. A high 'unsampleable' count means the core is halted/asleep; a high 'zero_samples' count means nothing was profiled at all. Leave enable=true: GDB cannot write the enable bit while the core runs, so this halts briefly to set it and resumes, and only when it is not already set. Note some links cannot serve memory reads while the core runs at all (measured: OpenOCD + ST-Link + STM32L1) — there PC sampling is unavailable and the result says so rather than inventing a hot spot. |
| import_netlistA | Parse a schematic netlist (KiCad .net today) into a machine-readable BoardDescription: the MCU part/family/line, a per-pin map (package pin -> port pin -> net -> inferred peripheral function), and the power/ground nets. This is the input contract for automated framework design. Pass 'path' or 'text'. The result is stored on the session; read views with describe_board. |
| describe_boardA | Read the BoardDescription imported by import_netlist. what=summary (MCU + peripherals + counts), pins (full MCU pin map), nets, power (power/ground nets), or peripherals (distinct peripherals in use). |
| validate_boardA | Validate the imported BoardDescription: detect a package pin wired to multiple nets (short), a peripheral signal routed to multiple pins, a port pin driven by multiple nets, and missing power/ground/debug/reset nets. With a pin-capability DB (db_path or the STM32_GDB_MCP_PIN_DB env) it also checks alternate-function legality; unknown pins degrade to 'unverified', never a false conflict. Run import_netlist first. |
| load_acceptanceA | Load a machine-checked AcceptanceSpec (product-spec → deterministic checks) from an inline 'spec' object or a JSON 'path'. Checks: memory_u32 (any memory-mapped register), variable (C global), core_register, no_fault, stopped_at (PC in a symbol). Stored on the session; evaluate with run_acceptance. |
| run_acceptanceA | Evaluate the loaded AcceptanceSpec against live silicon state and return a deterministic pass/fail/error verdict per check (the closed-loop judge). An unreadable target is reported as 'error', never a silent pass. A failing/errored check derived by synthesize_acceptance carries provenance.source — the init function + line that should satisfy it — so fixes are precision-guided. Run load_acceptance first; halt the target at the state you want to assert. |
| describe_acceptanceA | Read the loaded AcceptanceSpec or the last verdict. what=summary (name + check counts), checks (full check list), or last_result (the most recent run_acceptance report). |
| start_acceptance_loopA | Start a bounded spec-to-silicon acceptance loop (Pillar C) for the loaded AcceptanceSpec. Each run_acceptance_iteration does one build → flash → run-to-state → run_acceptance pass; the loop stops on convergence, on max_iterations, or on a stall (same checks failing repeatedly). Omit build/flash to run evaluate-only iterations (you flash manually). Load a spec first. |
| run_acceptance_iterationA | Run one bounded loop iteration: (optional build) → (optional flash+run-to) → evaluate the AcceptanceSpec against live silicon, then record the verdict and return a decision (converged / should_continue / exhausted / stalled) plus the checks to fix. A build or run-to failure is recorded as a phase_error, not a crash. Refuses to run a terminal loop unless force=true. start_acceptance_loop first. |
| acceptance_loop_statusA | Read the acceptance loop's trajectory (per-iteration pass/fail counts, status) and the current decision without running an iteration. |
| import_specA | Translate a controlled-vocabulary product spec (human/product terms) into the per-peripheral design params design_framework consumes, and cross-check it against the imported netlist. This is the upstream guard the pipeline lacked: instead of hand-writing HAL macros, supply intent -- UART framing '8N1', direction 'txrx', flow_control 'rtscts'; SPI role 'master', spi_mode 0..3, data_size, bit_order; I2C speed 'fast', addressing '7bit'; ADC resolution 12, conversion 'continuous'; a timer update_hz; plus dma / interrupt / priority opt-ins -- and the machine expands it deterministically (8E1 -> UART_WORDLENGTH_9B + UART_PARITY_EVEN, honoring HAL's parity-bit-in-word-length rule). A peripheral named in the spec but absent from the netlist is a conflict; an intent key or value the machine does not model is surfaced as unresolved -- never guessed. Then design_framework(from_spec=true) builds the plan from the translated params. Import a netlist first so the spec is cross-checked. |
| design_frameworkA | Synthesize a deterministic FrameworkPlan (Pillar D) from the session's imported board: which clocks to enable, how each pin must be muxed, and which peripheral init blocks to emit, in dependency order. Supply per-peripheral HAL .Init parameters via design={'USART1': {'baud': 115200, ...}} and optional AF numbers via af_map. Mandatory .Init members are auto-filled with HAL-standard defaults (a complete, valid init struct, not a half-initialized one) and a few are derived from the netlist (UART flow control from RTS/CTS pins, SPI NSS from an NSS pin); each field is tagged explicit/derived/default. Alternate-function numbers are also auto-derived from a pin-capability DB (db_path or the STM32_GDB_MCP_PIN_DB env) when its entries carry an 'af' field; an explicit af_map overrides the DB per pin. Anything that needs a human decision (baud, timer period, I2C timing) is surfaced as unresolved, never guessed. Import a netlist first (import_netlist). |
| describe_frameworkA | Read the synthesized FrameworkPlan. what=summary (mcu + clocks + peripherals), clocks, gpio (per-pin config), peripherals (init blocks), init_order, or unresolved (the TODO holes that need target data or a design decision). Run design_framework first. |
| render_frameworkA | Render the synthesized FrameworkPlan to a HAL C init skeleton (bsp_init.c + bsp_init.h). Every derived fact (clock enables, GPIO modes, mapped .Init fields) is concrete; every unresolved value is a clearly marked TODO — nothing is fabricated. Returns the files, their content, and a todo_count. Run design_framework first. |
| synthesize_acceptanceA | Auto-derive a machine-checked AcceptanceSpec from the synthesized FrameworkPlan (Pillar D Tier 3) and load it as the session's acceptance judge — welding design synthesis to the acceptance loop. Always emits a no_fault check (init must not HardFault); adds a memory_u32 bits_set check per clock the plan enables (RCC enable bit), a memory_u32 bits_set check per interrupt the plan enables (arch-standard NVIC ISER bit, from the resolved IRQ number), and a masked memory_u32 eq check per configured pin (GPIO MODER = AF/analog; F1's CRL/CRH is skipped). Register/IRQ/port placements come from the session's loaded SVD or explicit register_map/irq_map/gpio_map; anything unresolvable is surfaced, never guessed. Each derived check also carries source provenance (the init function + line that should satisfy it), so a later failure points straight at the fix site. Run design_framework first; load an SVD (start_debug_session/set svd) for clock/NVIC/GPIO checks. |
| solve_clock_treeA | Synthesize a concrete SystemClock_Config() for the session's FrameworkPlan (Pillar D Tier 3) - the last hand-written gap in generated init code. Given a clock source (HSE + crystal Hz, or HSI) and a target SYSCLK, it computes the exact PLL dividers (M/N/P or R, Q for 48 MHz USB), AHB/APB bus prescalers, and flash wait-states via pure datasheet math, then stores the result so the next render_framework emits real clock code instead of a TODO stub. Deterministic and honest: an unmodelled device or an infeasible target is surfaced, never guessed. Built-in profiles: STM32F401/F407/F411 and mainstream L4 (<=80 MHz); pass an explicit profile for others. Run design_framework first. |
| solve_timerA | Solve a timer's Prescaler/Period (PSC/ARR) for a target update frequency (Pillar D Tier 3). Turns intent ('TIM3 at 1 kHz') into concrete register values using the timer input clock (TIMxCLK) derived from the solved clock tree. Record a target via design_framework(design={'TIM3': {'update_hz': 1000}}) then run solve_clock_tree first, or pass timer_clock_hz directly for a what-if. Deterministic and honest: an exact target yields zero-error PSC/ARR, an inexact one yields the closest pair plus the achieved frequency and ppm error, and an unrepresentable target or an unknown timer bus is surfaced, never guessed. Injects the result into the plan so render_framework emits concrete values instead of a TODO. |
| load_device_packA | Register a verified device-fact pack (Pillar F) so the deterministic solvers cover a new STM32 family: its DMA request routing, irregular NVIC vectors, clock PLL profile, and timer bus/width. Facts are DATA, never guessed -- STM32F4/L4 ship built-in; add a family by supplying a validated pack (schema 'stm32-device-pack/v1') via path= (a JSON file) or inline pack=. Call with no arguments to report current coverage. Honest by design: a malformed pack is rejected with the list of problems and never half-loaded; shadowing a built-in family needs allow_override=true. |
| run_pipelineA | Spec-to-silicon capstone (Pillar G): run the whole deterministic DESIGN half in one call. Chains the existing, individually verified tools in dependency order -- import_netlist? -> import_spec? -> design_framework -> solve_clock_tree? -> solve_timer? -> render_framework -> synthesize_acceptance -- turning a netlist plus a product spec into a flashable HAL skeleton and a machine-checked acceptance spec, then hands off to the build/verify loop. Optional stages (marked ?) run only when their input is present. Honest by construction: it GUESSES NOTHING -- it sequences verified tools and aggregates every stage's own unresolved/conflict gaps into one 'human decisions / data still needed' list. A required-stage hard error (no board, invalid input) stops with pipeline_status=blocked at that stage; expected gaps (an AF needing a pin DB, an unmodelled clock) surface as complete_with_unresolved; a clean run is complete. Operates on the session's board unless netlist= is supplied. |
| loggingA | Firmware log capture over a channel. action=start(channel[,port,baudrate,command,args,file,timeout]) | stop(channel) | get(channel[,limit,since_index,clear]) | clear(channel). channel=rtt|swo|uart; uart takes port/baudrate, rtt/swo take command/args or file. |
| breakpointB | Breakpoint / watchpoint management. action=set(location[,condition,temporary,ignore_count]) | delete(breakpoint_id) | list | watch(location,access_type). access_type=r|w|a. |
| expressionsA | Evaluate C/GDB expressions. action=assert(assertions) | capture([expressions,table]) | compare(expressions,action). assertions=[{expression,expected[,operator]}]; table={index_range,columns}; compare runs 'action' between the two captures. |
| coredumpC | Core-dump capture / load. action=capture(path) | load(path). |
| timeoutsB | GDB operation timeouts. action=get | set(overrides). overrides={connect,reset,memory,...} in seconds. |
| debug_configB | Debug-config file (.json) management. action=load(path) | save(path,config) | validate(config). |
| debug_profileA | Active debug profile (mcu/elf/svd/probe). action=get | set([mcu,elf_path,svd_path,board,probe,server_type,server_args,project_root,hub,notes,merge]). set merges at the TOP LEVEL ONLY: omitted fields keep their value, but a nested block you pass REPLACES the stored one whole — hub={map:{3:{label:TC}}} drops the rest of hub, including what hub(action=discover) wrote. merge=true deep-merges nested blocks instead; leave it off to DROP a stale entry, since replace is the only way to remove one. Returns the full resulting profile, which is in-memory only: empty again after the MCP server restarts. |
| read_registersB | Read CPU register groups. what=core([include_raw]) | fault | cycle([enable]). fault decodes CFSR/HFSR; cycle reads the DWT cycle counter. |
| inspect_symbolA | Symbol / type introspection. what=size(expr) | type(expr) | address(symbol) | resolve(expr) | functions([regex]) | variables([regex]). resolve maps an address back to source, returning {resolved,symbol,offset,section,file,line}; resolved=false means no symbol there. |
| typed_memoryB | Typed (struct-aware) memory access. action=read(address,width_bits,count) | write(address,value,width_bits). width_bits=8|16|32|64. |
| write_guardC | Memory-write guardrail. action=policy([mode,add_allow,add_protected]) | audit([limit]). mode=enforce|dry_run. |
| snapshotB | One-shot diagnostic snapshot. scope=full([include_project,include_rtos,include_logs,log_limit,project_root]) | rtos. full bundles registers+stack+faults; rtos captures task/queue state. |
| frameA | Stack-frame navigation. action=select(level) | source([location,count]) | variables([level,include_raw]). level 0 is the innermost frame. |
| session_diagnosticsB | Session/transport diagnostics. what=health([reconnect]) | events | server_logs. events returns recent GDB/MI records; server_logs returns the GDB server's stderr. |
| hubA | Programmable USB hub: per-port power, USB2 data lines, cold boot, and V/I sampling. action=describe | power(state[,channel,confirm]) | data(state[,channel,exclusive,confirm]) | cycle([channel,off_ms,settle_ms,confirm]) | measure([channel,duration_sec,interval_sec,all_channels]) | discover([apply,force,settle_sec]) | dashboard([state,port,interval_sec,open_browser]). dashboard serves a read-only live web page on 127.0.0.1 and returns its URL. state=on|off; channel is 1-based and defaults to the session's mapped hub channel. Removing port power cold-boots that board and un-enumerates its probe. |
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 86 tools
Many tools overlap in the run/stop/context-capture space (run_and_wait, wait_for_stop, continue_execution, run_for_duration, run_to_line, capture_state) and multiple meta-call tools (call, call_read, batch, tool_help) create selection ambiguity. Descriptions are detailed enough to mostly disambiguate, but with 86 tools an agent can still easily misselect.
Most names follow a predictable snake_case verb_noun pattern (start_debug_session, read_memory, flash_firmware, solve_clock_tree). A minority are single-noun mega-tools (hub, breakpoint, expressions, logging, frame, snapshot), which is a minor deviation but still readable and internally consistent within that subset.
86 tools is far beyond the well-scoped 3-15 range and is too many even for this broad server. Although it spans debug, build, board design, acceptance loops, and USB hub control, the surface is unwieldy and likely to overwhelm clients and agents; consolidation into more action-parameter mega-tools is needed.
The tool surface covers the embedded debug lifecycle comprehensively: sessions, flashing, symbols, memory/registers, breakpoints, RTOS, SVD, fault/stack recovery, logging, profiling, coredump, acceptance loops, netlist-to-framework design, clock/timer solving, and hub power control. No obvious domain gap remains for the stated STM32 GDB/debug-and-build purpose.