Skip to main content
Glama

dsvlab-mcp — DS-VLAB 电路测试 MCP 服务器

让 AI(MCP 客户端)程序化控制 DS-VLAB v2.0 多思计组原理虚拟实验室中的电路:加载电路、上电、施加输入、单步/连续运行、读取引脚与存储、批量跑真值表,实现自动化测试。

架构

AI 客户端 ─stdio─► dsvlab-mcp(本服务) ─Playwright─► Edge/Chromium(加载 index.html)
                                                    │ page.evaluate()
                                                    ▼
                                          window.mycircuit / cDispatch
                                          / recovercircuit()(原系统全局)
  • 不改动原项目任何源码(18 个 component、dispatch、circuitdiagram、fileoperation 一律不动)。

  • 全部新文件集中在 mcp/dsvlab-mcp/

  • 复用原项目 tools/circuit-validator-core.js(UMD)做加载前校验。

  • 默认用系统自带的 Edge(channel: 'msedge'),无需下载 Chromium

Related MCP server: EDA Tools MCP Server

安装

cd mcp/dsvlab-mcp
npm install
npm run build          # tsc 编译到 dist/
# 可选:跑集成测试(会用 Edge headless 加载 example_bus_demo.txt)
npm test

不需要 npx playwright install —— 默认走系统 Edge。若想用 Playwright 自带 Chromium,设环境变量 DSVLAB_CHANNEL=chromium 后执行 npx playwright install chromium

配置(MCP 客户端)

ZCode / Claude Desktop

files/config.sample.json 的内容并入客户端的 MCP 配置(按本机实际路径调整):

{
  "mcpServers": {
    "dsvlab": {
      "command": "node",
      "args": ["C:/.../dsvlab2.0/mcp/dsvlab-mcp/dist/index.js"],
      "env": {
        "DSVLAB_INDEX": "C:/.../dsvlab2.0/index.html",
        "DSVLAB_CHANNEL": "msedge",
        "DSVLAB_HEADLESS": "0"
      }
    }
  }
}

环境变量

变量

默认

说明

DSVLAB_INDEX

<项目根>/index.html

index.html 绝对路径

DSVLAB_CHANNEL

msedge

浏览器 channel:msedge / chrome / chromium

DSVLAB_HEADLESS

0(可见)

1 = 无头(不弹窗,适合 CI)

浏览器是 lazy 启动:MCP 服务连上后不立即弹窗,第一次调用工具时才启动。

工具清单(共 27 个)

防护补丁:浏览器启动时自动注入,防止组合反馈环导致 runCircuit 死循环卡死主线程(原型 input 加 WeakMap+run token 计数,单拍每元件超 200 次 input 饿死)。卡死时工具调用超时(8s)自动重启浏览器并重放会话(电路 txt 优先从磁盘重读 + memory 写操作去重最终态 + 电源状态)。get_guard_status 返回触发次数/元件/第几次 runCircuit;run_steps 返回 triggeredAt 定位第几步触发。

边界:阈值是 per-component 的,多个独立反馈环各自饿死互不影响;但若两个环共享某元件(如三态门同时被两环驱动),该元件计数会叠加,可能比预期更快触发 guard。课设电路一般不会出现。

电路

工具

说明

load_circuit

加载电路 txt(默认先校验,有 errors 拒绝加载)

clear_circuit

清空画布

画电路(辅助生成,配合 docs/AI画电路手册.md 流程)

工具

说明

list_component_catalog

列出全部 23 种元件:名称/类型/引脚数

get_component_pins

查元件引脚表(画电路必查,引脚号禁止臆测)

build_circuit

由结构化描述生成合法 txt(带校验),可直接 load_circuit 加载

电源

工具

说明

power_on / power_off / reset

开/关/复位电源

仿真

工具

说明

step

单步:跑空一次就绪队列(一次稳定传播)

run

连续运行:启动 ContinuousPulse 跑 N 毫秒后停(有防护,安全)

run_steps

MCP 主动节拍(推荐):每步触发单脉冲/step 后让出主线程,跑 N 拍,响应最好

stop

停止所有连续脉冲(清 timer)

press_switch

翻转开关(toggle)

set_switch

设置开关到 0/1(处理初值高阻,自动判断是否需要翻转)

trigger_pulse

触发单脉冲(须先 power_on)

apply_input

给指定引脚施加 0/1 并传播

set_pulse_width

设置时钟周期(ms,默认 800,测试建议 50)

读取

工具

说明

list_components

所有元件概览

get_component

元件全部引脚(pinName/pinFunction/pinValue)

read_pin / read_all_pins

读引脚值(0低 / 1高 / 2高阻)

read_memory / write_memory

读写 RAM6116/EPROM memory;write 标量按芯片位宽自动拆位数组,read 返回 bits+scalar

snapshot

全电路所有引脚快照

get_guard_status

查防护状态(是否启用/阈值/饿死触发次数)

批量测试

工具

说明

run_truth_table

批量跑真值表(自动遍历 2^n 或自定义 cases)

assert_pins

一次性断言多引脚值,返回 pass/fail

使用示例(AI 视角)

1. load_circuit(text=<电路txt全文>)        → 加载并校验
2. power_on()
3. set_switch(id="CP8", value=0)           → 使能 74LS245
4. for each 输入组合: set_switch + step + read_pin
   或直接: run_truth_table(switch_ids=["CP0",...], outputs=[{id,pin}])
5. assert_pins(expected=[{id,pin,value},...])

关键技术点

  1. 桥接层(src/inject.ts):注入到页面的一段 window.__bridge 脚本,把对原系统 cDispatch/mycircuit/recovercircuit 的调用集中封装,Node 侧通过 page.evaluate 一次性调用,返回可序列化 JSON。减少跨进程往返。

  2. 调用对照(均已查源码确认):

    • 加载:recovercircuit('demo', mycircuit, txt)(fileoperation.js:136)

    • 上电/断电:cDispatch.powerOn()/powerOff()(dispatch.js:93/99)

    • 单步:cDispatch.runCircuit()(dispatch.js:75)

    • 触发源器件:cDispatch.sourceTrigger(c|id)(dispatch.js:86)

    • 读引脚:comp.pinValue[pinNo](0低/1高/2高阻)

  3. pinValue 三态:0 低 / 1 高 / 2 高阻未驱动,断言要区分。

  4. Switch 初值坑:原系统 new Array([0]) 产生 [[0]],pinValue[0] 实际是数组 [0],[0]==0 成立但 [0]===0 不成立。故 setSwitch 用宽松比较 !=,与原系统一律 == 的语义一致。

  5. memory 限制:RAM6116/EPROM 的 memory 硬编码在源码(js/component/ram6116.js 等),不随电路 txt 保存;运行时 component.memory 可读写,但刷新页面会重置回源码值。

  6. 异步脉冲:ContinuousPulse/SinglePulsesetTimeout 自驱动(默认 800ms);run(duration) 用真实等待,stop() 清 timer。测试时 set_pulse_width(50) 加速。

  7. MCP 用 stdio:禁用 console.log(破坏协议流),用 console.error

  8. TS + zod + MCP SDK 的 TS2589:zod ZodRawShape 与 SDK 泛型组合会触发 "Type instantiation excessively deep"。本项目统一用 server.registerTool<any, any> + handler (args:any, _extra:any): Promise<any> 规避。

调试

# MCP Inspector:浏览器里查看所有工具、手动调用
npx @modelcontextprotocol/inspector node dist/index.js

# 跑集成测试
npm test

已知限制

  • 不改原项目源码,因此 RAM/EPROM memory 初值仍需改 js/component/*.js(本工具只在运行时改 component.memory,刷新即失)。

  • run(duration) 基于真实时钟等待,大批量时序测试较慢;组合逻辑用 step/run_truth_table 即可。

  • 单步无 GUI 按钮,step = cDispatch.runCircuit()(跑空就绪队列)。

集成测试结果

tests/integration.test.tsfiles/examples/example_bus_demo.txt(8 开关 → 74LS245 → 8 LED)端到端验证:

  • ✅ 加载 18 个元件

  • -E=0 使能时 A→B 透传,8 个 LED 全亮

  • -E=1 禁能时 B 侧高阻,LED 不亮

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects test and measurement instruments (oscilloscope, logic analyzer, multimeter, power supply) to AI via MCP, enabling natural language control and automated analysis.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to perform electronic circuit power tree analysis, including opening projects, solving margins, validating designs, editing elements, managing waivers, and exporting reports.
    MIT