Skip to content

feat(mcp): add OpenClaw MCP bridge plugin#1412

Open
ruthwikdasyam wants to merge 11 commits intodevfrom
ruthwik/openclaw
Open

feat(mcp): add OpenClaw MCP bridge plugin#1412
ruthwikdasyam wants to merge 11 commits intodevfrom
ruthwik/openclaw

Conversation

@ruthwikdasyam
Copy link
Contributor

@ruthwikdasyam ruthwikdasyam commented Mar 4, 2026

Summary

  • Add OpenClaw plugin at dimos/web/plugin_openclaw/ bridging DimOS MCP tools into OpenClaw
  • Add MCP README with setup instructions for OpenClaw
  • Link from main README
  • Scope .gitignore package.json to repo root only, ignore pnpm-lock.yaml

Breaking Changes

None

How to Test

  1. Clone repo, uv sync --extra base --extra unitree
  2. Start MCP blueprint: uv run dimos --simulation run unitree-go2-agentic-mcp
  3. In dimos/web/plugin_openclaw/: pnpm install, install & enable plugin, set API keys in ~/.openclaw/.env
  4. Start gateway: pnpm openclaw gateway run --port 18789 --verbose - verify tools discovered
  5. New terminal: pnpm openclaw tui - send commands like "rotate in place"

Contributor License Agreement

  • I have read and approved the CLA.

Note

More tests needed to verify robustness. This PR covers primary installation instructions and connection setup between DimOS<>OpenClaw

@ruthwikdasyam ruthwikdasyam marked this pull request as ready for review March 4, 2026 03:20
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR introduces the OpenClaw MCP bridge plugin at dimos/web/plugin_openclaw/, enabling users to control DimOS robots through the OpenClaw agent system as an alternative to Claude Code. It also expands the MCP README with side-by-side setup instructions for both integrations and makes minor .gitignore and documentation updates.

Key changes:

  • dimos/web/plugin_openclaw/index.ts: Core plugin that synchronously discovers DimOS MCP tools at startup (via a spawned child Node.js process), converts their JSON Schemas to TypeBox, and registers them with the OpenClaw gateway. Tool calls are proxied to the DimOS MCP server over plain HTTP/JSON-RPC. Two issues were found: unsafe res.result.tools access in the embedded child-process script (will crash with a confusing error if the server returns a JSON-RPC error), and callTool skips the MCP initialize handshake that discoverToolsSync correctly performs.
  • dimos/web/plugin_openclaw/package.json: @sinclair/typebox is imported in index.ts but is absent from all dependency sections — this may cause a module-not-found error at runtime if openclaw does not bundle it.
  • .gitignore: The new pnpm-lock.yaml entry lacks a leading /, so it silently prevents the plugin's lock file from ever being committed, reducing install reproducibility.

Confidence Score: 3/5

  • This PR is mergeable but has a few correctness issues in the plugin code that should be addressed before wide use.
  • The logic is mostly correct and the integration approach is sound. However, the unsafe res.result.tools access in the embedded child-process script can produce opaque failures, callTool inconsistently skips the MCP initialize handshake, and @sinclair/typebox is missing from package.json — any of these could break the plugin in practice. The PR author notes "more tests needed," and the issues are fixable without major rework.
  • dimos/web/plugin_openclaw/index.ts and dimos/web/plugin_openclaw/package.json need attention before the plugin can be considered production-ready.

Important Files Changed

Filename Overview
dimos/web/plugin_openclaw/index.ts Core plugin bridge: discovers MCP tools synchronously via a child Node.js process, converts JSON Schema to TypeBox, and registers tools with OpenClaw. Two issues: unsafe res.result.tools access in the embedded script (crash on error response), and callTool skips the MCP initialize handshake that discoverToolsSync correctly performs.
dimos/web/plugin_openclaw/package.json Package manifest with empty dependencies and devDependencies; @sinclair/typebox (imported in index.ts) is not declared, which may cause a runtime module-not-found error if it isn't bundled by openclaw.
dimos/web/plugin_openclaw/openclaw.plugin.json Plugin metadata with configSchema for optional mcpHost and mcpPort overrides; no issues found.
.gitignore Scopes package.json and package-lock.json ignores to repo root; adds pnpm-lock.yaml without root-scoping, which prevents committing the plugin's lock file for reproducible installs.
dimos/agents/mcp/README.md Documentation update adding OpenClaw and Claude Code setup guides with clear terminal-by-terminal instructions; no code issues.
README.md Adds a single "Control with OpenClaw" link to the Agentive Control table cell; no issues.
pyproject.toml Adds */pnpm-lock.yaml to the large-file ignore list in pyproject.toml; no issues.

Sequence Diagram

sequenceDiagram
    participant User
    participant OpenClaw TUI/Agent
    participant OpenClaw Gateway
    participant Plugin (index.ts)
    participant DimOS MCP Server
    participant Robot

    Note over Plugin (index.ts), DimOS MCP Server: Plugin registration (startup)
    Plugin (index.ts)->>DimOS MCP Server: POST /mcp initialize (child process)
    DimOS MCP Server-->>Plugin (index.ts): initialized
    Plugin (index.ts)->>DimOS MCP Server: POST /mcp tools/list (child process)
    DimOS MCP Server-->>Plugin (index.ts): [{name, description, inputSchema}, ...]
    Plugin (index.ts)->>OpenClaw Gateway: registerTool() × N

    Note over User, Robot: Runtime tool execution
    User->>OpenClaw TUI/Agent: "move forward 1 meter"
    OpenClaw TUI/Agent->>OpenClaw Gateway: resolve tool call
    OpenClaw Gateway->>Plugin (index.ts): execute(toolCallId, params)
    Plugin (index.ts)->>DimOS MCP Server: POST /mcp tools/call {name, arguments}
    DimOS MCP Server->>Robot: execute skill
    Robot-->>DimOS MCP Server: result
    DimOS MCP Server-->>Plugin (index.ts): {content: [{type:"text", text:"..."}]}
    Plugin (index.ts)-->>OpenClaw Gateway: {content, details}
    OpenClaw Gateway-->>OpenClaw TUI/Agent: tool result
    OpenClaw TUI/Agent-->>User: response
Loading

Last reviewed commit: b02e1e3

Comment on lines +155 to +157
): Promise<string> {
const url = mcpUrl(host, port);
const result = (await rpc(url, "tools/call", { name, arguments: args })) as {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callTool skips the MCP initialize handshake

discoverToolsSync correctly sends an initialize request before tools/list (line 137), but callTool calls tools/call directly via rpc() without any prior initialize. While stateless Streamable HTTP transports often tolerate this, the MCP spec requires an initialize/initialized exchange before any other messages. If the DimOS server enforces this (or is updated to do so), every tool execution will fail silently with an HTTP error or a JSON-RPC error, while tool discovery continues to succeed.

Consider either:

  • Sending a lightweight initialize in callTool before tools/call, or
  • Confirming in a code comment that the DimOS MCP server is unconditionally stateless and does not require initialization per request.

@leshy
Copy link
Contributor

leshy commented Mar 4, 2026

Just to understand, openclaw is not able to interact with dimos directly via MCP? Asking since the whole idea of MCP is that other tooling can just use dimos out of the box

@spomichter
Copy link
Contributor

@ruthwikdasyam Reminder to add @Kaweees as a co-author when PR so both of yall are on this PR

Co-authored-by: Miguel Villa Floran <miguel.villafloran@gmail.com>
@ruthwikdasyam
Copy link
Contributor Author

ruthwikdasyam commented Mar 4, 2026

Just to understand, openclaw is not able to interact with dimos directly via MCP? Asking since the whole idea of MCP is that other tooling can just use dimos out of the box

Right. openclaw doesn't have built in MCP servers. it has its own plugin-based tool system. So, this plugin is to bridge the gap - on startup, this discovers robot skills from DimOS MCP server and registers them as openclaw agent tools. then, forwards tool calls back to DimOS over HTTP when the openclaw agent uses them

@Kaweees anything to add?

@leshy
Copy link
Contributor

leshy commented Mar 4, 2026

Just to understand, openclaw is not able to interact with dimos directly via MCP? Asking since the whole idea of MCP is that other tooling can just use dimos out of the box

Right. openclaw doesn't have built in MCP servers. it has its own plugin-based tool system. So, this plugin is to bridge the gap - on startup, this discovers robot skills from DimOS MCP server and registers them as openclaw agent tools. then, forwards tool calls back to DimOS over HTTP when the openclaw agent uses them

@Kaweees anything to add?

Not having an MCP client is such a glaring hole I assume there is a popular plugin for MCP for openclaw, did you investigate this and try it out on default dev branch dimos? If not I think you should

@@ -1,55 +1,142 @@
# DimOS MCP Server
# DimOS MCP Server with OpenClaw
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dimOS MCP Server OR openclaw. we support mcp wihtout openclaw of course need to make clear


```bash
cd dimos/web/plugin_openclaw
pnpm openclaw tui
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt it just openclaw tui?

Copy link
Contributor Author

@ruthwikdasyam ruthwikdasyam Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that works if openclaw is installed globally. we install it locally via pnpm install in plugin dir. so need to pnpm openclaw tui to run it from local node_modules
if we do pnpm add -g openclaw sets global_path, then openclaw tui works

# DimOS MCP Server with OpenClaw

Expose DimOS robot skills to Claude Code via Model Context Protocol.
The OpenClaw plugin lives at `dimos/web/plugin_openclaw/`. It bridges DimOS MCP tools into the OpenClaw agent system.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't have Openclaw take over the MCP readme. Revert all the changes to this file and add "Roboclaw" readme to the botton or put roboclaw readme as a seperate readme.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed MCP readme to bottom and added Openclaw instructions on the top. Nothing is removed.
Readme is 2 parts - MCP with Openclaw, and MCP with ClaudeCode.
Maybe, I can add a section at the top specifying this

@@ -0,0 +1,223 @@
import { execFileSync } from "node:child_process";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nitpick but change the directory to web/roboclaw

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a 'roboclawz' trademark and a motor controller called 'RoboClaw'.

Not sure if it's the best name...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legally speaking, I think we will be fine, since it seems the trademarks are only applicable for physical manipulators

<td align="center" width="50%">
<h3><a href="docs/capabilities/agents/readme.md">Agentive Control, MCP</a></h3>
"hey Robot, go find the kitchen"<br><a href="https://x.com/stash_pomichter/status/2015912688854200322">Watch video</a>
"hey Robot, go find the kitchen"<br><a href="https://x.com/stash_pomichter/status/2015912688854200322">Watch video</a><br><a href="dimos/agents/mcp/README.md">Run with OpenClaw</a>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Roboclaw"

@spomichter
Copy link
Contributor

And then we probably should have unit tests here. Ideally a test that tests end to end whether openclaw sees 100% of the tools and can call them etc @ruthwikdasyam

## Setup
## How It Works

1. DimOS starts a FastAPI MCP server on port 9990, exposing robot skills as JSON-RPC tools
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to mention FastAPI. It would be more useful to mention the transport used.

DimOS starts an MCP server on port 9990 using the SSE transport (HTTP), exposing robot skills as tools.

Comment on lines +43 to +45
## Terminal 2 — OpenClaw gateway

First time only — install and configure the plugin:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Em dashes are signs that the docs were AI generated.

Suggested change
## Terminal 2 OpenClaw gateway
First time only — install and configure the plugin:
## Terminal 2: OpenClaw gateway
Install and configure the plugin:

```

It will open a browser window.
# DimOS MCP Server with Claude Code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# is h1 so you can only have one per page. Maybe you should have # Model Context Protocol at the top of the page and add an extra # to all titles.

function discoverToolsSync(host: string, port: number): McpToolDef[] {
const url = mcpUrl(host, port);
const script = `
const http = require('http');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite ugly. It should be a separate file.

Blocking the thread is also bad, but it looks like it's required as openclaw's API expects all tools to be known at registration time synchronously.

Looks like it might be possible to register tools asynchronously, by using api.registerService (https://docs.openclaw.ai/tools/plugin#register-background-services) and define the tools in async start() {...}, but I haven't tried it and I'm not sure.

): Promise<unknown> {
const body = {
jsonrpc: "2.0",
id: 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ids are supposed to be unique. It technically works if you don't have two concurrent calls, but we should be able to support it.

import { Type } from "@sinclair/typebox";
import type { AnyAgentTool } from "openclaw/agents/tools/common.js";

const DEFAULT_HOST = "127.0.0.1";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works if you run both openclaw and dimos on the same machine, right?

Currently, the MCP server has no auth, but we should probably add auth so we can connect to it from a remote server. Otherwise we will have to run openclaw and dimos on the same machine.

I think most people run openclaw on AWS or on a local minipc. People probably can't run dimos there.

(Personally, I run openclaw in a VM, for security reasons.)

We probably need instructions for how to run them on separate machines. Do you agree?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed for now

const url = mcpUrl(host, port);
const script = `
const http = require('http');
function post(body) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a lot shorter if you used fetch.

Also, we probably need some re-try logic in here because otherwise we always have to start the gateway after the MCP server has started... and I'm sure people will probably start both at the same time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants