Skip to main content
Glama
README.md
[![M8ven Score](https://m8ven.ai/badge/mcp/kshamaybharadwaj-obs-mcp-1qtv0h)](https://m8ven.ai/mcp/kshamaybharadwaj-obs-mcp-1qtv0h)

# OBS MCP — AI Broadcast Control & Automation for OBS Studio

An MCP (Model Context Protocol) server that turns an AI assistant into an
**AI broadcast operator for OBS Studio**. Describe what you want in natural
language — the server handles scenes, sources, audio, recording, streaming,
transitions, filters, media playback, diagnostics and multi-step workflows
over the OBS WebSocket 5.x protocol.

```
AI Assistant (Claude, opencode, Cursor, ...)
        │  MCP (stdio / sse / streamable-http)
        ▼
    OBS MCP Server
    ┌─────────────────────────────┐
    │ Control / Monitoring        │
    │ Diagnostics / Automation    │
    │ Safety layer (confirmation) │
    └──────────────┬──────────────┘
                   │ OBS WebSocket (default port 4455)
                   ▼
              OBS Studio
           (obs-websocket)
```

**89 tools**, 107 tests, no OBS required to run the test suite.

---

## Table of contents

1. [What you can do](#what-you-can-do)
2. [Requirements](#requirements)
3. [Setup OBS (do this first)](#setup-obs-do-this-first)
4. [Installation](#installation)
5. [Configuration](#configuration)
6. [Connecting an AI assistant (MCP client)](#connecting-an-ai-assistant-mcp-client)
7. [Running the server](#running-the-server)
8. [Safety model](#safety-model)
9. [Example session](#example-session)
10. [Testing](#testing)
11. [Project structure](#project-structure)
12. [Troubleshooting](#troubleshooting)

---

## What you can do

**Connection & status**
`get_obs_status` · `get_obs_stats` · `obs_help`

**Scene management**
`list_scenes` · `get_current_scene` · `switch_scene` · `create_scene` ·
`rename_scene` · `delete_scene` · `duplicate_scene` ·
`get_scene_sources` · `add_source_to_scene` · `remove_source_from_scene`

**Source (input) management**
`list_sources` · `get_source` · `get_source_available_kinds` ·
`create_source` · `update_source` · `delete_source` · `duplicate_source` ·
`show_source` · `hide_source` · `set_source_visibility_in_all_scenes`

**Positioning & layout**
`get_source_transform` · `set_source_transform` (move / scale / rotate /
crop) · `set_source_index` (z-order)

**Transitions & studio mode**
`get_transitions` · `set_scene_transition` · `set_transition_duration` ·
`get_studio_mode_status` · `set_studio_mode` · `set_preview_scene` ·
`trigger_transition`

**Audio**
`list_audio_sources` · `get_audio_status` · `get_volume` · `set_volume` ·
`mute_source` · `unmute_source` · `set_audio_monitor` ·
`set_audio_sync_offset` · `set_audio_track`

**Filters**
`list_filters` · `add_filter` · `remove_filter` · `get_filter_settings` ·
`set_filter_settings` · `reorder_filters` · `toggle_filter`

**Recording & replay buffer**
`get_recording_status` · `start_recording` · `stop_recording` ·
`pause_recording` · `resume_recording` · `get_record_directory` ·
`set_record_directory` · `get_replay_buffer_status` · `start_replay_buffer`
· `stop_replay_buffer` · `save_replay_buffer`

**Streaming**
`get_stream_status` · `start_stream` · `stop_stream` · `get_stream_health` ·
`get_stream_service_settings` · `set_stream_settings` ·
`get_output_settings` · `set_output_settings`

**Media & VLC playback**
`media_control` (play / pause / stop / restart / next / previous) ·
`get_media_time` · `set_media_time`

**Hotkeys & configuration**
`get_hotkey_list` · `trigger_hotkey` · `get_video_settings` ·
`set_video_settings` · `list_profiles` · `set_current_profile` ·
`create_profile` · `list_scene_collections` ·
`set_current_scene_collection` · `create_scene_collection`

**Diagnostics**
`diagnose_obs` (full health check) · `diagnose_stream` ·
`diagnose_recording` · `diagnose_audio`

**Automation workflows**
`prepare_recording` · `prepare_stream` · `start_recording_session` ·
`end_session`

---

## Requirements

* **Python 3.10+**
* **OBS Studio** (any recent version — 28+; tested on 32.x) with the
  built-in WebSocket server enabled
* One of these AI assistants (any MCP client works):
  * [opencode](https://opencode.ai)
  * Claude Desktop
  * Cursor
  * Any MCP-capable client

---

## Setup OBS (do this first)

1. **Install OBS Studio** from [obsproject.com](https://obsproject.com/).
2. **Enable the WebSocket server**:
   * OBS menu: **Tools → WebSocket Server Settings…**
   * Check **Enable WebSocket server**
   * Note the **Server Port** (default `4455`)
   * Check **Require authentication** and set a **password** — the server
     refuses to connect without credentials for security reasons. Save it;
     you will need it in the next step.
3. **Prepare your scenes and sources** (optional but recommended):
   * Create scenes (e.g. `Intro`, `Coding`, `BrB`) via **Scene** dock or
     `+` button in the Sources dock.
   * Add sources (webcam, display capture, audio, media) and arrange them.
   * If you plan to use the automation workflows, decide which scene is the
     "recording scene" and which is the "stream scene".
4. **Leave OBS running** while you use the AI assistant. The server connects
   lazily and reconnects automatically if OBS restarts.
5. (Optional) To verify everything works before wiring the AI assistant,
   run the included demo client — see [Testing](#testing).

---

## Installation

```bash
git clone <this-repo> && cd obs-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```

This installs the `obs-mcp` command into the virtual environment
(`.venv/bin/obs-mcp`). All examples below assume the venv is active or use
the full path `.venv/bin/obs-mcp`.

## Configuration

Copy the example file and fill in your OBS WebSocket password:

```bash
cp .env.example .env
# edit .env, set OBS_PASSWORD to the password you configured in OBS
```

The server reads the `.env` file in the project directory, plus any
`OBS_*` environment variables you export (environment variables win).

| Variable | Default | Description |
| -------- | ------- | ----------- |
| `OBS_HOST` | `localhost` | OBS WebSocket host |
| `OBS_PORT` | `4455` | OBS WebSocket port (must match **Tools → WebSocket Server Settings**) |
| `OBS_PASSWORD` | *(empty)* | WebSocket auth password — required when OBS requires authentication |
| `OBS_REQUIRE_CONFIRMATION_HIGH` | `true` | Gate high-risk ops (stream start/stop, deletes) behind `confirm=True` |
| `OBS_REQUIRE_CONFIRMATION_MEDIUM` | `false` | Gate medium-risk ops (audio, recording) behind `confirm=True` |
| `OBS_CONNECT_TIMEOUT` | `5` | Seconds to wait for a connection attempt |
| `OBS_RECORDING_SCENE` | *(empty)* | Scene used by `prepare_recording` / `start_recording_session` (empty = current scene) |
| `OBS_STREAM_SCENE` | *(empty)* | Scene used by `prepare_stream` (empty = current scene) |
| `OBS_LOG_LEVEL` | `INFO` | Logging verbosity: `DEBUG`, `INFO`, `WARNING`, `ERROR` |

### Security note

`OBS_PASSWORD` is the same credential that grants full control of your OBS
instance (start streams, delete scenes). Never commit it to version control
(`.env` is git-ignored), and use a strong password if your machine is
network-exposed.

---

## Connecting an AI assistant (MCP client)

### opencode

Add a `mcp` entry to `opencode.json` (usually `~/.config/opencode/opencode.json`):

```json
{
  "mcp": {
    "obs-mcp": {
      "type": "local",
      "command": [
        "/path/to/obs-mcp/.venv/bin/obs-mcp"
      ],
      "enabled": true,
      "environment": {
        "OBS_HOST": "localhost",
        "OBS_PORT": "4455",
        "OBS_PASSWORD": "your-obs-websocket-password"
      }
    }
  }
}
```

Restart opencode, then ask it things like *"check OBS status"*.

### Claude Desktop

Add to `claude_desktop_config.json` (Claude → Settings → Developer):

```json
{
  "mcpServers": {
    "obs-mcp": {
      "command": "/path/to/obs-mcp/.venv/bin/obs-mcp",
      "args": [],
      "env": {
        "OBS_HOST": "localhost",
        "OBS_PORT": "4455",
        "OBS_PASSWORD": "your-obs-websocket-password"
      }
    }
  }
}
```

### Other clients (Cursor, VS Code, generic)

Point the client at the stdio binary. If your client only supports HTTP
servers, run the server with `--transport sse` or `--transport streamable-http`
and give it the URL of the running server.

---

## Running the server

The server is normally launched by your MCP client, but you can also run it
standalone to check it starts cleanly:

```bash
obs-mcp                          # stdio transport (default, what MCP clients use)
obs-mcp --transport sse          # SSE HTTP transport
obs-mcp --transport streamable-http
python -m server.mcp_server      # equivalent to obs-mcp
```

A successful stdio start prints nothing but the MCP handshake — clients
usually show the server as connected. You can verify OBS connectivity by
calling `get_obs_status` from your assistant, or by running the demo client
(needs OBS running):

```bash
python examples/demo_client.py
```

---

## Safety model

Operations are classified by risk in `server/safety/permissions.py`:

| Level   | Examples | Default policy |
| ------- | -------- | -------------- |
| Low     | status, lists, `get_*`, switch scene, show/hide source | runs automatically |
| Medium  | volume/mute, create/rename scene, source settings, recording | runs automatically (can be gated via `OBS_REQUIRE_CONFIRMATION_MEDIUM=true`) |
| High    | start/stop stream, delete scene/source, `end_session` | **requires `confirm=true`** |

High-risk tools return `confirmation_required` unless the caller passes
`confirm=True` — i.e. the AI asks the human first, then proceeds only with
explicit confirmation.

---

## Example session

> **User:** Check OBS.
>
> **AI:** OBS is connected. Current scene: Coding. Microphone: Active.
> Webcam: Active. Recording: OFF. Streaming: OFF.
>
> **User:** Add a camera in the bottom-right corner of Scene 2 with a
> full-screen background.
>
> **AI:** creates a `Background` color source (1920×1080) and the webcam
> source, then positions the camera at the bottom-right using
> `set_source_transform`.
>
> **User:** Prepare my coding recording.
>
> **AI:** calls `prepare_recording`, reports the setup summary.
>
> **User:** Everything looks good. Start recording.
>
> **AI:** calls `start_recording_session` with `confirm=True` after asking,
> confirms, and reports the recording is live.
>
> **User:** Stop recording and give me a summary.
>
> **AI:** calls `end_session`, returns duration and the saved file path.

---

## Testing

```bash
pip install -e ".[dev]"
pytest
```

Run the tests from the project root. The suite (107 tests) runs against an
in-memory fake OBS — **no OBS needed** — plus one end-to-end test over the
real stdio MCP transport.

---

## Project structure

```
obs-mcp/
├── server/
│   ├── mcp_server.py        # MCP wiring, tool registration, entry point
│   ├── obs_client.py        # OBS WebSocket connection, auth, reconnect, helpers
│   ├── config.py            # OBS_* environment configuration
│   ├── tools/               # one module per feature area
│   │   ├── scenes.py  sources.py  audio.py
│   │   ├── recording.py  streaming.py  transitions helpers
│   │   ├── media.py  filters.py  config.py
│   │   ├── diagnostics.py  automation.py
│   ├── safety/permissions.py  # risk classification + confirmation policy
│   └── models/responses.py    # structured tool responses
├── tests/                   # pytest suite with an in-memory fake OBS
├── examples/demo_client.py  # stdio demo client
├── pyproject.toml
├── features.txt             # full feature checklist
└── .env.example
```

---

## Troubleshooting

| Problem | Fix |
| ------- | --- |
| `get_obs_status` reports "Could not reach OBS" | OBS not running, or WebSocket server disabled (**Tools → WebSocket Server Settings → Enable WebSocket server**) |
| Authentication failed | `OBS_PASSWORD` does not match the password in OBS WebSocket settings — check both, restart OBS after changing it |
| Connection refused on a remote machine | Check `OBS_HOST`/`OBS_PORT`; make sure the port is reachable and OBS is listening on it |
| Tools return `confirmation_required` | The operation is high-risk — pass `confirm=true` to execute it |
| `set_source_transform` does nothing | Keys are snake_case (`position_x`, `scale_y`, `bounds_width`, …); the server converts them for the OBS protocol |
| Media source won't play | `media_control` uses `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_*` actions on media-capable sources (ffmpeg_source / VLC); `set_media_time` needs the source playing or paused |
| Assistant can't find the tools after adding the server | Restart the MCP client so it re-reads the config |
| Tests fail when run from another directory | Always run `pytest` from the project root |

TDQS

B3.2/5.0

Scored across 89 tools

Disambiguation4/5

Tools are generally well-separated by resource and action, but some overlap exists (e.g., get_obs_stats vs get_obs_status vs diagnose_obs; start_recording vs start_recording_session). Descriptions help clarify these boundaries, making accidental misselection unlikely.

Naming Consistency4/5

Most tools follow a consistent verb_noun snake_case pattern (get_, set_, create_, delete_, start_, stop_, etc.). Minor exceptions like 'media_control' and 'obs_help' invert the pattern, but the overall style is uniform.

Tool Count2/5

With 89 tools, the server is extremely large. While OBS has many features, the sheer number of tools is excessive, and some could be consolidated (e.g., diagnostic tools could use a single parameterized endpoint). This is well beyond the 25+ threshold for 'too many'.

Completeness5/5

The tool surface covers virtually every major OBS domain: scenes, sources, audio, video, media, filters, transitions, studio mode, profiles, collections, recording, streaming, replay buffer, hotkeys, and diagnostics. It even includes higher-level session workflows, leaving no obvious gaps for typical automation.