Skip to main content
Glama

Keil uVision (UV4) → MCP — full-surface reconstruction

keil-uv4-mcp is a dependency-free Model Context Protocol server (stdio, JSON-RPC 2.0) that exposes the complete functional surface of Keil µVision 5 (MDK 5.43a, MDK-Lite non-commercial) as reconstructed from the shipped binaries, the shipped help and controlled runtime probing.

Target installation analysed: C:\Users\ERDAN.DESKTOP-MVAKHCO\AppData\Local\Keil_v5\UV4 (UV4.exe sha256 428baf13d15e6760af1618def9c9815c97f0321cc5e459ec7adc4dde41c42f89, x86 MFC, 41 876 functions / 18 794 strings after auto-analysis).

93 MCP tools · 106/106 acceptance · 10/10 adversarial · 48/48 portable · 37/37 licence-free compile · 44/44 beginner diagnostics · 68/68 release gate.

UV4.exe ──CLI/exit codes──▶ uv4cli.mjs      build / rebuild / clean / download / convert / export / symbols
        ──XML model──────▶  project.mjs     .uvprojx / .uvproj / .uvmpw / .uvoptx (byte-faithful)
        ──.dep & .d──────▶  deps.mjs        UV4 dependency database, incremental impact, stamps
        ──device DB──────▶  packs.mjs       CMSIS-Pack .pdsc devices, components, flash algorithms
        ──toolchain──────▶  toolchain.mjs   armcc / armasm / armclang / armlink / fromelf command lines
        ──images─────────▶  image.mjs       .axf ELF, linker .map, Intel-HEX
        ──batch──────────▶  batchgen.mjs    <Target>.BAT + .__i / ._ia / .lnp via files
        ──debugger───────▶  gdbstub.mjs     SVD → register/bitfield description, peripheral map
        ──license────────▶  license.mjs     armlm / armlm-ipc / FlexNet inventory, #601 build gate
        ──remote control─▶  uvscanner.mjs   UVSOCK probe, UV4 process control

Round 2: exhaustive companion coverage

All 21 companion binaries are profiled in reverse/modules.md: UVSC.dll/UVSC64 (103-export UVSOCK client library -> full wire protocol decoded, re-implemented in src/uvsock.mjs, and verified live end-to-end: V2.29 handshake, remote rebuild with event streaming), UVCDB2XML (2831-device legacy .cdb), SfrCC2, SVDConv 3.3.48, uv2csolution 1.6.0 (Go; AC6-only guard verified), PackInstaller/PackUnzip plus a native .pack ZIP reader, Scintilla *.prop / UTF-16 *.SVCS config formats, armlm.exe + armlm-ipc.exe (Go 1.24.5 wrapping FlexNet Embedded; activation via https://api.arm.com/p-software-licensing/v1/activate, store ~/.armlm), KSPAWN console spawner, DCOMUTIL (UV4.dll) OLE/DDE registration strings, UvCC.dll (LLVM AC6 integration layer), UVAC code-completion engine.

New tools: uvsock_connect / uvsock_request / uvsock_disconnect / uvsock_service_table, cdb_devices / cdb_vendors, editor_props, svcs_menus, pack_file_inspect / pack_file_extract, companion_run, license_architecture.

Related MCP server: kicad-forge

Quick start

cd keil-uv4-mcp
node src/server.mjs            # MCP server on stdio
node tests/run_tests.mjs       # 106 acceptance checks (builds real projects with UV4)
node tests/fuzz_test.mjs       # 10 adversarial checks
node tests/pack_test.mjs       # 68 release-gate checks (npm pack -> unpack -> cold start -> real build)
npm run test:all               # all six suites (313 checks)

No Keil installation and no npm install are required: dependencies: {} and the data the server needs ships in data/fixtures/. Copy the directory (or npm pack / npm i -g) onto any machine with Node >= 20 and start it.

npm pack                       # keil-uv4-mcp-<version>.tgz  (source + fixture snapshot)
npm i -g ./keil-uv4-mcp-*.tgz && keil-uv4-mcp

Start here (three commands)

You do not need to know any Keil error code.

{"tool":"doctor"}                                                   // is this machine ready?
{"tool":"pack_diagnose","project":"your.uvprojx"}                    // why won't it build, and how to fix it
{"tool":"compile","project":"your.uvprojx"}                         // build without any licence
{"tool":"flash","project":"your.uvprojx","chip":"STM32F103C8"}      // dry run first, then dryRun:false

pack_diagnose answers in plain language and returns copy-paste fixes:

summary: 构建会被拒绝:工程写死要 STM32F1xx_DFP 2.4.0,这台机器装的是 2.4.1。
actions:
  - 装回工程要求的 STM32F1xx_DFP 2.4.0      -> pack_fetch {...}
  - 把工程的 PackID 改成已装的 ...2.4.1      -> project_set_option {...}

Licence-free build and flash

A µVision project can be compiled and programmed without an MDK licence, without activation and without UV4.exe. Nothing on this path calls armlm or checks Error #601.

capability

tool

backend

licence

compile

compile

clang+lld or arm-none-eabi-gcc

none

flash

flash

pyOCD / OpenOCD / STM32_Programmer_CLI / ST-LINK_CLI / J-Link

none

probe

build_backends

reports what is installed

—

  • The linker script is generated from the project's own Cpu: string (IROM(...) IRAM(...)); when the project omits CMSIS, CMSIS/Core/Include is resolved from the pack roots or the bundled snapshot automatically.

  • Outputs are .elf + .hex + .bin + .map, and the server's own elf_info/hex_info/ map_info re-validate them (tests assert the vector table: initial SP = top of IRAM, Reset vector in flash with the Thumb bit).

  • No byte-parity claim with armcc: every result carries backend and fidelity. Use uv4_build only when armcc/armclang behaviour is required (that needs a real install).

  • Both paths coexist: uv4_build drives UV4 when present, compile never does.

The underlying algorithms (.dep stamps, via files, UVSOCK frames, device-fragment assembly) are documented with function addresses in docs/algorithms.md.

Client registration (any stdio MCP client):

{ "mcpServers": { "keil-uv4": {
    "command": "node",
    "args": ["C:\\path\\to\\keil-uv4-mcp\\src\\server.mjs"]
} } }

environment

default

meaning

KEIL_MDK_ROOT

%LOCALAPPDATA%\Keil_v5, C:\Keil_v5

installation root (TOOLS.INI owner)

KEIL_UVSOCK_PORT

4328

default UVSOCK port for uvsock_probe

UV4_TIMEOUT_MS

900000

default per-invocation timeout; the process tree is killed on expiry

Recovered contract (evidence first)

Command line — UV4.exe [command] [projectfile] [options]

command

effect

verified

-b

build current target (batch-selected targets for .uvmpw)

exit 0/1/2

-r

re-translate current target

exit 0/1/2

-c

clean all targets ("deleting intermediate output files…")

exit 0

-cr

clean + rebuild

exit 0

-z / -q

rebuild all / batch-selected targets of a multi-project

hangs on a single project (documented; refused unless force)

-f

download to Flash

requires a configured adapter

-5

convert .uvproj → .uvprojx (+ .saved_uv4 backup)

exit 0, log "Migration completed"

-et / -ep

export .cprj (target / all)

exit 0

-X / -X1

co-arm_<target>.h symbol files

file produced

Options: -j0 (headless, mandatory for automation), -o log, -t target, -s UVSOCK port, -sg ignore uvguix, -i import XML, -n/-np create device project, -l logfile (with -5), -x/-y DDE (with -d). ERRORLEVEL: 0 none, 1 warnings, 2 errors, 3 fatal, 11 cannot write project, 12 unknown device, 13 write error, 15 import XML error, 20 conversion error.

Multi-project facts discovered by probing: the workspace is <ProjectWorkspace> with <project><PathAndName/> members (UV4\project_mpw.xsd), and Batch Build selection is the per-target <SelectedForBatchBuild> inside each member — UV4 -b reports Batch-Build summary: N succeeded, M failed, K skipped.

Project / dependency formats

  • .uvprojx (project_projx.xsd) and .uvoptx (project_optx.xsd) are read and written byte-faithfully: an untouched file round-trips identically, edits rewrite only the affected subtree (node src/xml.mjs round-trip test in the suite).

  • <Output>\<project>_<target>.dep writer is FUN_00680b10; the (0x%08X) column is the dependency file's clock time written as decimal HHMMSS and printed in hex (main.c 15:52:13 → 0x00155213); F records hold the exact tool command (-IC:\…\Device\Include, -D__UVISION_VERSION="543", defines, -o, --depend), I records the include closure produced by armcc --depend.

  • Per-file depend files (*.d) are literally "<obj>: <dep>\r\n" lines emitted by the compiler; UV4 and this server both parse that format.

  • Batch build artefacts (Create Batch File): <Target>.BAT with SET PATH/ARMCC5_*OPT/ CPU_TYPE/CPU_VENDOR/UV2_TARGET/CPU_CLOCK, per-file ArmAsm --Via .\objects\x._ia / ArmCC --Via .\objects\x.__i, ArmLink --Via .\Objects\out.lnp, then fromelf.

Device data

pack_devices, pack_device_detail, pack_components, pack_conditions and pack_rte_validate parse the installed .pdsc (also UV4\PACK.xsd layout). The generated Cpu: string, FlashDriverDll (UL2CM3(… -FS08000000 -FL020000 …)) and SFDFile/RegisterFile are byte-identical to UV4's own -5 migration output (asserted in the acceptance suite).

Tool catalogue (93)

group

tools

CLI reproduction

uv4_build, uv4_rebuild, uv4_clean, uv4_clean_rebuild, uv4_rebuild_all, uv4_download, uv4_symbols, uv4_export_cprj, uv4_convert, uv4_import, uv4_run, uv4_job_status, uv4_job_list, uv4_job_wait, uv4_build_log, uv4_processes

project model

project_read, project_files, project_multiproject, project_set_option, project_group_add, project_group_remove, project_file_add, project_file_remove, project_target_clone, project_target_remove, project_validate, project_diff, project_create, project_create_legacy, project_create_multi, project_multi_add, project_multi_read, project_batch_flags

dependencies

dep_read, dep_graph, dep_impact, dep_scan, dep_write, test_build

packs

pack_list, pack_devices, pack_device_detail, pack_components, pack_conditions, pack_rte_validate

images

elf_info, map_info, hex_info, memory_usage, symbols_file

session options

options_read, options_set, options_create

scaffolding / batch

batch_file, batch_generate, import_xml_document, import_xml_from_project

debugger

debug_script, debug_command_reference, debug_pack_generate, debug_peripheral_map

installation

keil_install, toolchain_versions, tool_run, license_status, uvsock_probe, cli_reference, cli_table

Generated short table: tool_table.md.

Evidence kept under reverse/

file

content

cli_matrix.json

every command probed, exit codes, -z/-q hang, timings

dep_stamp_evidence.json

F/I records, producer function FUN_00680b10, stamp semantics

rte_injection_evidence.json

implicit RTE include / __UVISION_VERSION / define injection, ordering

batch_via_files_evidence.json

the byte-exact Flash.BAT, main.__i, startup._ia, main.lnp

uv4_profiles.json

binary identity, CLI contract, side effects, UVSOCK / armlm artefacts

acceptance_results.json

latest acceptance run (106/106)

samples/

Minimal (verified build), Gen2 (scaffolded, builds), Legacy (converted by UV4), Multi* (workspaces), Scaffold, Import

hashprobe*.mjs, pdsc_probe*.mjs, stamp_decode*.mjs

the probes used to pin the formats

Behaviour notes and limits

  • UV4 is a GUI-subsystem binary: without -j0 a shell waiting on stdio deadlocks. Every invocation rewrites <project>.uvoptx (current target, debug options).

  • -z/-q only exist for .uvmpw; the wrapper refuses them on single projects and kills the process tree on timeout (uv4_processes {kill:true} recovers stale runs).

  • RTE components are validated structurally (pack presence, class/group/sub match). UV4 additionally applies condition rules; mismatches are reported as #540, missing packs as #544 — the same codes UV4 logs.

  • Scaffolded projects use AC5-safe include sets: CMSIS 6.x ships cmsis_compiler.h whose AC5 section ends in #error Unknown compiler. (verified at Core/Include/cmsis_compiler.h:279), therefore project_create prefers CMSIS ≤ 5 or omits it and writes a self-contained sysinit.c. Passing addSystem:true copies the DFP system_*.c when CMSIS 5 is installed.

  • armlm.exe / armlm-ipc.exe / FlexNet daemons are treated as black boxes: the server reports their files, running instances and the live Error #601 build gate; it never edits license data.

  • The UVSOCK protocol (frames over the -s port) is probed and reported (reachability, greeting bytes, listener inventory). Frame-level command encoding is not published by Arm; the debugger command surface itself is fully exposed through -d scripts (debug_script, debug_command_reference).

  • tool_run never leaves the toolset bin directory (path traversal is rejected).

  • The bundled DFP snapshot contains .pdsc declarations only — no device sources (Device/Include/*.h, startup_*.s, .FLM payloads). Without Keil, project_create still emits the exact <Device>/<Vendor>/<PackID>/Cpu/FlashDriverDll fragments, and project_validate truthfully reports NO_STARTUP / INCLUDE_MISSING: those files really are absent, and the validator is not allowed to pretend otherwise.

Release and open source

Why the release gate exists

A working checkout is not a working package. Two defects only appear after npm pack:

  1. Data read at import time from the development tree. module_catalog.json lived in reverse/, which is not in files:, so a published package died with ENOENT on startup. It now ships at data/fixtures/catalog/module_catalog.json, is loaded lazily on first use, and degrades to a structured error instead of taking the server down.

  2. Main-module detection by string comparison. 8.3 short paths (C:\Users\ERDAN~1.DES\…), symlinks and case differences made isMain false: the process imported cleanly and exited silently. Detection now uses realpathSync.native with Windows case folding.

tests/pack_test.mjs runs npm pack, unpacks the tarball outside the repository, blanks LOCALAPPDATA/KEIL_MDK_ROOT to simulate a machine without Keil, cold-starts the server and asserts the device DB (2831 devices / 33 vendors), the three .pdsc packs, STM32F103C8's 64 KiB flash / 20 KiB RAM / STM32F10X_MD / SVD/STM32F103xx.svd / STM32F10x_128.FLM, module_catalog resolving inside the package, .axf/.map/.hex parsing, uv4_build returning needsKeil, and startup through an 8.3 short path.

Repository layout

directory

contents

shipped

src/

all runtime code (22 modules + 14 tool registrars)

yes

data/fixtures/

runtime snapshot (134 files / 6.44 MB)

yes

tests/

313 assertions + release gate

no

reverse/

decompilation scripts, evidence JSON, controlled-run logs

no

Licence and attribution

MIT (see LICENSE). The .pdsc files and the UV4.cdb dump under data/fixtures/ remain the property of their respective owners and are included for interoperability; review the licence terms inside each .pdsc before commercial redistribution. This project contains no vendor binary code.

Contributing

Read CONTRIBUTING.md first. The governing rule is fidelity to the original, decompilation first: every behaviour must point at a function address in UV4.exe/UVSC.dll or a controlled-run record under reverse/. When the evidence is missing, return a structured diagnostic — never a plausible-looking guess.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    A
    maintenance
    MCP server for AI-assisted MCU and embedded firmware debugging. It connects to real hardware via debug probes, inspects CPU/memory/peripherals, manages Keil builds, and provides structured evidence for fault diagnosis.
    19
    17 PyPI
    8
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Provides schematic/PCB analysis, authoring, and SPICE simulation through MCP, enabling direct KiCad file manipulation and verification without requiring KiCad for reading.
    18
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that drives Keil µVision debug sessions for 8051/C51 targets via the native UVSOCK/UVSC interface: build, run control, breakpoints, and read/write of variables, memory & expressions (22 tools). Works with the Keil Simulator (no hardware needed) or GLink+/ULINK on real targets.
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that lets AI tools drive Keil uVision debugging sessions for ARM Cortex-M targets, enabling expression/variable reads, memory access, run control, breakpoints, and trace capture.
    44
    4
    MIT