obs-action-history
An MCP server for OBS Studio that subscribes to events and maintains a history, enabling queries about audio levels, source states, and past actions rather than only one-shot requests.
README
obs-action-history
An MCP server for OBS Studio that can hear.
There are already several of these. Most of them wrap the obs-websocket request surface one call at a time and stop there. That is a reasonable thing to build, and it produces a tool that can operate OBS competently. It also produces a tool that is, in a specific and consequential way, deaf.
This one subscribes to the event stream, keeps a bounded record of what happened, and answers questions about it.
Zero dependencies. Node builtins only. Windows, macOS and Linux.
The distinction that matters
A request answers exactly one kind of question: what is true at this instant. You ask, OBS replies, you decide. Whatever occurred between one call and the next is gone, and you have no way of knowing it was ever there.
Now, that sounds like an architectural footnote. It is not. Consider what it costs you.
There is no request in the obs-websocket protocol that returns an audio
level. GetInputVolume gives you the fader position. GetInputMute gives
you a boolean. Neither has anything to say about whether sound is actually
coming out of that microphone. Levels exist in one place only, as
InputVolumeMeters, which is an event.
So the question "is my microphone working right now" cannot be answered by a server built purely on requests. Not answered poorly. Not answered slowly. Not answered at all. A server exposing 148 tools has precisely the same blind spot as one exposing twelve, because the answer is not on the surface either of them is drawn from.
This server holds that stream:
obs_who_is_talking -> Mic A peak -36.9 dB 29 samples
Mic B peak -37.8 dB 29 samples
Music peak -54.2 dB 29 samples
InputVolumeMeters arrives roughly fifty times a second per source. Nobody
wants three thousand raw frames back from a tool call. The question a person
actually has is who was loud, so meters never enter the buffer at all. They
are reduced to a peak per source and returned as an answer.
What this buys you, concretely
A microphone that is configured correctly and produces nothing. Fader at unity, not muted, and the wrong device selected or a cable quietly dead. Every setting a request can reach reports perfect health. This is not hypothetical; it is why the rig this came from needed a separate microphone-checking process before this existed.
A camera that follows the voice. You need to know which of two microphones is louder, continuously, and you need to compare them against each other rather than against some fixed threshold, because two microphones in one room have different gains and each of them hears everybody. There is nothing here to poll. The information only arrives as it happens.
Something alive and wedged, which is worse than something dead. During
development this server surveyed five media sources and every one of them
reported PLAYING. One had advanced zero milliseconds while the others moved
about 2,540. By state they were indistinguishable. Only elapsed time separated
a working feed from a corpse, and that exact blindness had already concealed
seventeen hours of silent music behind a dashboard showing green.
What happened two minutes ago. A poller can describe the present and nothing else. Once something has passed, it is simply unavailable, and you are reduced to guessing about the very incident you are trying to explain.
The descriptions are part of the product
A tool description is not a place to restate the parameter list. The model can already read the schema. It is where you put the things that will otherwise be learned the expensive way:
- OBS audio sync offset caps near 960 ms. Larger values apply silently as nothing, so you believe you compensated for a two second delay and you compensated for none of it.
- Scene item index 0 is the bottom, and a full-canvas source sitting above a background conceals it utterly, with no error raised anywhere.
- A source parked off-canvas is still visible and still plays its audio. Hiding it instead does cut the audio, which is why an audio-only overlay is parked rather than hidden.
RemoveInputreports success and does not delete a source that anything still references.- Bounds fields are inert unless
boundsTypeis set first. TriggerHotkeyByNametakes a bare name, andlibobs.muteis registered once per audio source, twenty-four times on the reference machine. Hotkeys therefore cannot address a specific source, whatever you might reasonably assume.
Each of those cost somebody something. They are written down because a model that does not know them will act confidently and be wrong, which is a good deal worse than acting tentatively and being right.
The tool that makes a fresh machine possible
obs_input_property_items enumerates the real choices behind a source
property: every webcam and every audio device, with the identifiers OBS
actually expects.
Microphone (Some USB Mic)
-> {0.0.1.00000000}.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
There is nothing human-readable in that to guess at. Without this call, an assistant can only adjust sources a person already created by hand. With it, it can build them from nothing.
What is covered
67 tools across eleven modules.
| Module | What it reaches |
|---|---|
| scene items | add, remove, duplicate, z-order, lock, blend, the full fifteen-field transform |
| filters | complete CRUD, reordering, renaming, and every filter kind the install can create |
| audio routing | monitor type, sync offset, track assignment, balance, special inputs |
| capture | replay buffer including save, virtual camera, screenshot to disk, record chapters, file splitting |
| studio mode | preview scene, and the transition that puts it to air |
| inputs | device enumeration, properties buttons, remove, rename, kind reference |
| outputs | enumerate, status, settings, start and stop |
| media | transport control, and a status probe that reports cursor movement |
| hotkeys | list and trigger, the only route to plugin features that have no request of their own |
| projectors | monitors, and fullscreen output of a mix or a single source |
| core | scenes, sources, streaming, recording, screenshots, and a raw escape hatch |
Install
You need Node 22 or newer, for the global WebSocket, and OBS 31+ with Tools → WebSocket Server Settings → Enable WebSocket server ticked.
Copy .mcp.example.json into your MCP client's configuration and point args
at server.js. The password is read from OBS_WEBSOCKET_PASSWORD when it is
set, and otherwise from a secrets.json beside the server:
{ "obsPassword": "the value from OBS > Tools > WebSocket Server Settings" }
Be aware that a wrong password does not present as a wrong password. OBS accepts the socket and then closes it with code 4009, which most clients report as a timeout, and you will spend your afternoon investigating your network. This server names it correctly.
The reference machine
Figures quoted throughout, such as the 43 filter kinds, the 411 hotkeys of which only 88 are distinct, the 960 ms ceiling, the five outputs and two replay buffers, were measured on OBS 32.2.1 with obs-websocket 5.7.4 on Windows, while that machine was broadcasting live to three platforms. That is what the reference machine refers to wherever it appears. Your install will differ in places, and every one of those numbers is checkable with the tools here, which is the point of stating them rather than rounding them off into vagueness.
Two errors in the published obs-websocket documentation surfaced this way and
are worked around. GetSourceFilterKindList returns sourceFilterKinds,
where the documentation says filterKinds. And SetSourceFilterSettings.overlay
defaults to true, where a summary claimed false; passing false calls
obs_source_reset_settings and destroys every other tuned value on that
filter, which is the sort of mistake you make once.
Contributing
mcp/tools/index.js holds the contract. A module exports
(obs) => [ { name, description, inputSchema, handler } ] and may use
obs.request(type, data) and nothing else.
Loading is deliberately fail-safe. A module that is missing, that throws while building, that returns a malformed tool or that duplicates a name is logged and skipped, and the server still starts with everything else intact. Your broken module is your problem and should not become somebody else's dead broadcast.
Before you open a pull request:
npm run preflight
It refuses credentials, absolute paths, machine-specific addresses and device identifiers anywhere in the tree, and it verifies that every module still loads.
Status
0.1.0. Tool names may still move before 1.0. Pin an exact version if you
are scripting against them.
Licence
MIT. See LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。