u/unnghabunga

▲ 0 r/obs

Hey everyone,

I wanted to share something I've been working on that might be useful if you use OBS with AI tools.

I had built an OBS control server in Dart (using the obs-websocket protocol), and recently compiled it to JavaScript so it can run as an npm package. The idea is to let AI assistants control OBS through the Model Context Protocol (MCP).

What does it do?

Basically, you can configure an MCP-compatible AI agent (Claude Desktop, VS Code with MCP, Cursor, etc.) to talk to this server, and the agent can then:

  • Switch between scenes
  • Start/stop recording and streaming
  • Mute or adjust volume on inputs
  • Move, rotate, or scale sources on the canvas
  • Manage filters and transitions
  • Control virtual camera and replay buffer
  • Check OBS stats (CPU, FPS, etc.)

There are about 60 operations available, but they're exposed through just two tools: search (to find what you need) and execute (to run JavaScript that calls the operations).

How it works

The server uses a pattern called "Code Mode" (similar to what Cloudflare does with their MCP servers). Instead of exposing all 60 operations as separate tools, there are just two:

  1. search - Ask it what operations are available, with different detail levels
  2. execute - Run JavaScript code that can call any of the OBS operations

Here's what that looks like in practice:

// Discover available scene tools
const tools = await call_tool('search', { query: 'scene', detail_level: 'detailed' });

// Switch scenes and start recording
await call_tool('obs_scenes_set_current_program', { sceneName: 'Live Scene' });
await call_tool('obs_record_start', {});

// Animate a source (client-paced with easing)
await call_tool('obs_scene_items_set_transform', {
  sceneName: 'Live Scene',
  sceneItemId: 3,
  sceneItemTransform: { positionX: 960, positionY: 540 }
});

Getting started

The server connects to OBS and exposes the tools over MCP's stdio transport.

To use it with an AI agent, you'd add it to your MCP configuration. For Claude Desktop, that's claude_desktop_config.json:

{
  "mcpServers": {
    "obs": {
      "command": "npx",
      "args": ["@unngh/obs-mcp"],
      "env": {
        "OBS_WEBSOCKET_URL": "ws://localhost:4455",
        "OBS_WEBSOCKET_PASSWORD": "your_password"
      }
    }
  }
}

For VS Code, you'd add it to .vscode/mcp.json in your workspace:

{
  "servers": {
    "obs": {
      "command": "npx",
      "args": ["@unngh/obs-mcp"],
      "env": {
        "OBS_WEBSOCKET_URL": "ws://localhost:4455",
        "OBS_WEBSOCKET_PASSWORD": "your_password"
      }
    }
  }
}

What I use it for

I set this up to automate some of my streaming workflows:

  • Automatically switch scenes when I switch between coding and presenting
  • Animate sources (like having a logo do a little intro animation before going live)
  • Start recording a second before I begin talking, stop a second after I finish
  • Mute/unmute my mic based on which scene is active

It's been working well for basic automation, though there's definitely room for more creative use cases.

A bit about the implementation

The original package was written in Dart because I was already working on an OBS WebSocket SDK in Dart. I compiled it to JavaScript using dart2js so people who don't have Dart installed can still use it.

What you get:

  • Runs on Node.js 18+
  • Uses the standard ws WebSocket library
  • Compiled from strongly-typed Dart code (helps catch bugs)
  • Works on macOS, Windows, and Linux

The Dart version is also still available on pub.dev if you prefer that route. Both have the same functionality.

Available operations

All the tools are prefixed with obs_ and grouped by category:

Category Examples
Connection Connect, disconnect, check status, send raw requests
Scenes List, switch, create scenes; manage program/preview
Scene Items Position, scale, rotation, visibility, z-order
Inputs Audio/video inputs, mute, volume, settings
Audio Balance, sync offset, monitor type, tracks
Media Play/pause/stop media, seek to position
Stream Start/stop streaming, send captions
Record Start/stop recording, pause/resume
Outputs Virtual camera, replay buffer
Transitions List, configure, trigger with T-Bar control
Filters Create, remove, configure source filters
UI Studio Mode, open dialogs, list monitors
Canvases List configured canvases (OBS v5.7.0+)

Technical details

A few things about how it's built:

  • Uses MCP's stdio transport with newline-delimited JSON
  • OBS WebSocket connection happens in the background (doesn't block MCP setup)
  • Has a debug mode (OBS_MCP_DEBUG=1) that logs everything to stderr
  • Handles signals properly for clean shutdown
  • MIT licensed, so you can use it however you want

Links

Give it a try

If you're interested, you'll need:

  • Node.js >= 18
  • OBS Studio with the WebSocket server enabled (OBS 28+ has this built-in)

I'm curious what kinds of workflows people would find useful. I've mostly been using it for basic scene switching and recording automation, but I'm sure there are more creative applications.

Happy to answer questions or take suggestions for improvements. The code's all open source if anyone wants to take a look.

reddit.com
u/unnghabunga — 6 days ago
▲ 13 r/dartlang+2 crossposts

Hey r/dartlang 👋

I just shipped 0.6.0 of two packages that let you expose plain Dart methods as an MCP server, a REST API (with OpenAPI 3.0 spec), or both — from the same annotated class.

What it looks like

    import 'package:easy_api_annotations/easy_api_annotations.dart';
    
    @Server(
      transport: McpTransport.http,
      port: 8080,
      generateRest: true, // also emit .openapi.dart + .openapi.json
    )
    class UserApi {
      @Tool(description: 'Create a new user')
      Future<User> createUser({
        @Parameter(pattern: r'^[\w\.-]+@[\w\.-]+\.\w+$') // optional
        required String email,
        required String name,
      }) async => /* ... */;
    
      @Tool(description: 'Get user by ID')
      Future<User> getUser({required int id}) async => /* ... */;
    }

Run dart run build_runner build and you get:

  • user_api.mcp.dart — a stdio or HTTP MCP server
  • user_api.openapi.dart — a Shelf REST server (POST /users, GET /users/{id})
  • user_api.openapi.json — an OpenAPI 3.0 spec you can feed to Swagger UI

What's in 0.6.0

  • Renamed @Mcp → @Server (the old name still works as a deprecated typedef)
  • Split generation flags: generateMcp, generateRest, generateJson
  • REST template honors @Server(logErrors:) so 500s stay generic client-side but you get full stack traces on stderr when you want them
  • @Parameter(sensitive: true) now actually propagates — x-sensitive in .mcp.json, writeOnly: true + format: 'password' in .openapi.json
  • Code Mode (optional Node.js sandbox for batch tool orchestration)
  • Canonical package:easy_api_generator/easy_api_generator.dart entry point

Working example

Full runnable example (users + todos, stdio + HTTP + REST): https://github.com/cdavis-code/easy_api_workspace/tree/main/example

Happy to hear feedback, bug reports, or "you should really generate XYZ too."

u/unnghabunga — 9 days ago