dosbox-x-mcp
dosbox-store-mcp
一个 MCP 服务器,用来在不触碰桌面的前提下驱动一个 DOSBox-X 客户机:不倒绘图、不产生宿主机的合成击键、不移动指针。一个模型可以把 DOS 程序从头到尾跑完,而你还能在它前面继续干你自己的活。
它最初只是某个逆向工程项目的采集工作流,如今已经成为一个通用工具。面对一个正在运行的 DOS 客户机,它可以毫无先验知识地找到那个客户机,告诉你加载了哪些程序和它们的位置,读取并修补任意内存段,随着时间持续采样内存值,从视频内存中直出屏幕画面,驱动模拟器自带的录音器,并紧盯代码的运行——全程不需要调试器,也不会在磁盘上改动一个字节。
它能做什么
找到客户机 | 只靠 BIOS 不变量就能定位 DOS 客户机——不需要配置、不需要标记、事先什么都不用知道。沿 DOS 内存链走一圈,把每个已加载的程序的名称、所在段和来源路径都报出来。 |
寻址任意段 | 启动链中的另一个程序、TSR、覆盖模块、中断向量表、EMS 页面。一切都可以读、改、转储、搜索。 |
驱动它 | 按键直接进 BIOS 键盘环形缓冲区后台。点击直接写进游戏自己的 post-INT-33h 鼠标缓存。这两条路都不碰不下主机的输入队列。 |
观察它 | 直接从模拟器的视频内存里读帧缓冲:字节索引原样、无窗口、无缩放、客户机零消耗——并用参考帧逐字节确认。必要的时候也可以截窗口。 |
测量它 | 阻塞到一个内存条件成立,或者把一张监测列表按最高 200 Hz 采样成 TSV——每一列都出自同一个快照,所以彼此永远不会分离。还能监测视频内存里出现过的每一个不同帧,以及它出现的时刻。 |
录制它 | 用模拟器自带的 OPL、MIDI 和 WAVE 录制,免焦点,完全绕开宿主机的按键映射。 |
给它插桩 | 把一条 实时的 |
Related MCP server: re-winedbg
它如何工作
这里的一切都与宿主机的输入队列或屏幕无关。
客户机发现。每个 DOS 客户机的内存里都有键盘环形缓冲区的范围界字节
0x001E/0x003E,落在0040:0080,里面有因该范围对应的头指针、尾指针,还存在一个活的INT 21h向量。只要在模拟器内存里找到这三个特征,就找到了客户物理零地址;有了这个,每个段都能直接“不确定”。这根本不需要什么已做好的配置——这正是新项目一开始不需要去面对“先有鸡还是先有蛋”的卡点的方式。
Hmm, the last clause: "This needs no profile, which is what breaks a nearby new project starts chicken-and-egg." I wrote a bit awkwardly. Let me phrase: "这一步骤根本不需要 profile——这正好也就是一个新项目在起步阶段最难住的鸡–蛋过程僵局所在的点。" Ahem, keep simple: "这也正是新项目起步时最致命的“鸡生蛋”困局被破解的地方。"
按键 会像真实键盘一样,被追加到客户机的 BIOS 键盘环形缓冲区中。
点击 被写入游戏自己的 INT 33h 处理器会填充的那些字——即游戏真正读取的状态。这些字会被反复不断重写,因为游戏里的那个处理程序一直在覆盖它们,只写一次必然输掉这场竞速。
画面 直接来源于视频内存。DOSBox 按真实硬件的做法布局 chain-4 页面——CPU 偏移量
o位于线性地址4 * (o & ~3) + (o & 3)——所以每隔 16 个字节取一组四个字节,就能把一块区域还原为屏幕。搞清楚哪些字节才是屏幕,需要一张参考帧:模拟器的内存里充满了像图画却并非画面的数据,所以页面要么和参考帧逐字节对上(会被确认),要么就永不确认。见读取屏幕。追踪 把一条
近CALL` 指向一段全零占位区。这个代码洞会去调用被“挤掉”的原目标,保持标志寄存器,再把你所要的数据复制到自己代码之后并返回。模拟器随运行结束而退出,这个补丁也就一并涂去了。不写入磁盘的文件系统上不会留下任何东西。
安装
pip install "dosbox-x-mcp[all] @ git+https://github.com/md0-code/dosbox-x-mcp"其余部分都是可选的,名字直接写到它们买了什么:
可选依赖 | 用途 |
| Pillow,为模拟器的窗口拍快照 |
| numpy,让 chain-4 反交错更快(也可以退回到纯 Python) |
| python-xlib,在 Linux 上列出窗口并把它们拍下来 |
把这个注册到你的 MCP 客户端里。对 Claude Code,在项目根目录放一个 .mcp.json:
{
"mcpServers": {
"dosbox": {
"command": "python",
"args": ["-m", "dosbox_mcp.server"],
"env": {
"DOSBOX_MCP_PROFILE_DIR": "dosbox-x/profiles",
"DOSBOX_MCP_EXECUTABLE": "dosbox-x/dosbox-x.exe"
}
}
}
}变量 | 含义 |
| 配置文件所在目录(默认:包的 |
| 默认配置文件名;为 |
| 要启动的的 |
| 相对输出相对参考路径的基准目录 |
一个工具读写的每条路径都遵守同一规则:绝对路径原样解释;相对路径被解释在 DOSBOX_MCP_OUTPUT_DIR 之内。工具会返回被解析后的路径,所以某文件到底去了哪里永远不会有疑问。
工具
工具 | 作用 |
| 这台机能做什么、不能做什么 |
| 列出所有配置;显示某个配置的命名偏移 |
| 启动 DOSBox-X 并等待客户机变得可驱动 |
| 通过 pid 将已运行的模拟器接入 |
| 已接入的会话,以及其它任何 DOSBox-X 窗口 |
| 结束一个会话 |
| 找到客户机并列出每个已加载的程序——不需要配置文件 |
| 找一个字节模式,报告为客户的 |
| 往 BIOS 键盘环形缓冲区里输入 |
| 用游戏自己的鼠标字完成点击 |
| 按住若干按钮,可选一直按住直到内存测试通过 |
| 读取字节段,或任意段 |
| 修改数据段,或任意段 |
| 把整个 64 KiB 的段存成文件 |
| 阻塞直到指定内存字段满足某个条件 |
| 把某监视列表按时间采样到 TSV |
| 把当前帧作为图返回供查看 |
| 保存一帧准确画面,来自视频内存或窗口 |
| 从视频内存中读出页面 |
| 一段时间内每一个不同的帧,以及时间 |
| 触发一条 DOSBox-X 自己的菜单命令 |
| 把 OPL、MIDI 或 WAVE 录制到文件 |
| 找到足足够大的零字填充区以用于 trace |
| 把一条实时 |
| 读取某次追踪已经记录了的内容 |
| 恢复调用现场并清空洞 |
只要一个参数是偏移量,也可以用配置里的符号名——即 treasury 替代 0x634A。
从一款没有任何人配置过的游戏开始
配置并不为前置条件:下面就是第一次会话的全部:
dosbox_launch(config="game.conf", profile="none") → pid
dosbox_find_guest()
→ 640 KiB, INT 21h live, and:
JP2D load segment 2456 1.1 MB C:\JP\JP2D.EXE
JP load segment 08A1 64 KB C:\JP\JP.EXE
COMMAND load segment 0801 16 KB C:\COMMAND.COM
dosbox_search_memory(text="sprites.dbt") → 2456:027A
dosbox_dump_segment(path="jp2d.bin", segment="0x2456")那一份转储就是配置的弹药:从中挑 50–100 个不会在运行间变化的字节,再配上两条便宜的检查规则,然后每一件“相对 DS”的工具都能按名称起效。
读取屏幕
dosbox_read_framebuffer 在读取那一瞬间返回客户所写入的调色板索引。它是确切的,不会吞掉半帧画面,也不会对客户机产生任何成本——这正是“任何需要测量的东西,都首选它”的理由。
它需要一个参考帧,并且它会直接告诉你这一点,而不是去猜。 定位页面等于在数百兆字节的内存里找出 64,000 个字节;只有“自成一体”这某一件事是完全不够的——对着一个活着的游戏实测,盲扫会送回一页 0.999 相似的页面,但那其实是一个解码出来的精灵图库,根本不是屏幕。于是,请把 reference= 指向一个 64,000 字节的文件,内容正是当前屏幕上的画面。到此,页面才被逐字节最终确认:
dosbox_read_framebuffer(reference="credits_logo.bin", stem="shots/logo")
→ page_offset 16, confirmed true, pages [16, 64016, 128016, 192016]参考帧可以有这些来源:
一个开发中的移植版,它天然就有一份——它本身对同一屏幕的渲染结果。这也是值得做的一次对照:如果两边逐字节一致,说明这个移植的渲染器是对的。
同一屏幕之前任意一张已确认的抓屏,都可以再确认一次。
窗口照片——只要配置里带了一张调色板,这一步是自动做的,不用传任何参数。
一旦确认,页面位置就会缓存下来,此后每一次读取、以及 dosbox_watch_frames 产生的每一帧都不需要再搜索。allow_unconfirmed=true 则是给那些想直接看看“盲扫”结果的人准备的。
页面所在处不一定是你想当然的地方:它随着 CRTC 起始地址起,只落在一个四字节的对齐边界上,更细粒度是没有的。真正实测的那个页面就在偏移量 16 处。
配置文件
一个配置就是这样一个 JSON 文件,描述一个游戏:如何识别它的数据段、它把鼠标状态放在哪、屏幕的尺寸和调色板、命名偏移、监视组、以及已知的空洞。profiles/example.json 是一个带注释的示例模板;真实案例见OpenJP这个仓库,它是针对一款 1993 年发行的真实游戏写的。
{
"name": "example",
"ds_segment": "0x1234",
"marker": { "bytes": "6578616d706c652e64617400", "offset": "0x0100" },
"checks": [ { "kind": "cstring_via_pointer", "pointer": "0x0200", "value": "game" } ],
"mouse": { "buttons": "0x00B2", "position": "0x00B6" },
"screen": { "width": 320, "height": 200 },
"symbols": { "lives": { "offset": "0x1234", "size": 1, "description": "Lives left." } },
"watch_sets": { "player": ["lives", "score", "level"] }
}标记可以直接内嵌成 bytes 十六进制,也可以从一片参考转储里切出来(source_dump + offset + length)。可用的检查式包含:cstring_via_pointer、max、max_range、equals——这就足以让误报变得几乎不可能,而这很重要,因为误报的结果就是对一块莫名其妙的野生内存打补丁。
平台支持矩阵
Windows | Linux | macOS | |
客户机内存、段、搜索、键鼠 | 是 | 是 | 没有后端 |
帧缓冲、采样、追踪 | 是 | 是 | 没有后端 |
窗口列表、截屏、调整大小 | 是 | 需配合 X11 | — |
模拟器菜单命令 | 是 | 不支持——用隔离的显示环境 | — |
离屏显示缓存 | — | 使用 | — |
dosbox_capabilities 会针对当前正在运行的主机报告所有相关能力,因此请直接查询,而不是猜测。
在 Linux 上,kernel.yama.ptrace_scope 对另一个进程内存的访问控制方式,与 Windows 上的完整性级别(integrity level)完全一致:
值 | 效果 |
| 任意同一 UID 进程 — |
| 仅限后代进程 — |
| 仅限 |
| 完全无法 attach |
在这种常见的默认配置下,应选择 launch 而不是 attach。服务器会读取该 sysctl,并明确说明这一点,而不是抛出一个裸露的 EPERM。
Linux 上如果没有合成管理器(compositing manager),就无法拍摄被遮挡的窗口;而 Wayland 完全没有跨客户端捕获能力。解决之道不是模拟 PrintWindow,而是移除了它所要满足的那个约束:dosbox_launch(isolated=true) 会把模拟器放到自己的 Xvfb 显示环境中,那里没有需要保护的桌面,模拟器自己的键盘快捷键也可以正常使用,而不会从任何人那里抢走按键。
macOS 需要 task_for_pid,因此要么以 root 运行,要么使用一个已签名、带有相应 entitlement 的二进制文件。目前没有针对 macOS 的后端。
注意事项
模拟器必须是可访问的:在 Windows 上处于同一完整性级别,在 Linux 上
ptrace_scope设置合理。每个 profile 同一时间只能运行一个模拟器。两个运行同一游戏的客户机会让段扫描产生歧义,服务器会直接拒绝,而不是猜测。
dosbox_capture_screen使用source="window"时会调整模拟器窗口大小,以获得精确的整数倍缩放。这是本服务器对桌面唯一可见的影响;也正因如此,应优先使用source="vram",它同样更快,而且不会捕捉到绘制到一半的帧。对窗口进行拍摄会让客户机付出真实时间代价:循环拍摄会把客户机可见阶段拉长约 1.6 倍。凡是需要定量分析的内容,都应使用帧缓冲。
在某些游戏中,一次点击可能会推进两个“点击继续”画面;在有列表翻页时,请发送按键。
对运行中的游戏进行写入是无法撤销的,而游戏可能在你设置字段后立刻重新计算它——请在该字段被读取、且尚未被重新计算的时机进行写入。
跟踪内存捕获在代码洞(cave)运行时通过
DS当前持有的段来读取。对于只有一个数据段的游戏来说,这恰好是正确的;对于会切换DS的例程,请同时捕获ds并检查。只有 chain-4 线性模式 13h 会从显存中读取;其他情况都需要
source="window"。对帧缓冲的盲目扫描只是一条线索,不是答案,且会被标记为未确认。请提供一帧参考帧。
开发
pip install -e ".[dev,all]"
pytest该测试套件完全离线:一个 DOS 客户机、一个内存链、一个 chain-4 帧缓冲和一个可追踪的代码段,全部构建在一个 bytearray 中,因此它能在任何平台上运行,不需要模拟器,也不需要游戏。未覆盖的部分是最底层的两个系统调用——读取和写入另一个进程——以及窗口。
许可证
MIT。
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables programmatic control of the mGBA emulator for Game Boy, Game Boy Color, and Game Boy Advance games, including screenshot capture, memory reading, sprite data dumping, and custom Lua script execution for automated testing and game analysis.63
- AlicenseNot gradedqualityCmaintenanceEnables headless debugging of Windows executables from Linux/macOS hosts by orchestrating winedbg's gdbserver and a GDB client, exposing 19 tools for launch, attach, breakpoints, stepping, register/memory access, and session lifecycle.MIT
- AlicenseNot gradedqualityCmaintenanceBridges AI agents to a DOSBox emulator, enabling control of DOS programs via MCP tools for typing, screen reading, video capture, Lua scripting, and memory access.1GPL 2.0
- FlicenseAqualityBmaintenanceEnables an MCP client to observe and control a text-mode DOS system via a Python bridge, supporting keyboard input and screen capture.8
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/md0-code/dosbox-x-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server