From cb36560526484ce77133f0f9c9c462d540ec57ca Mon Sep 17 00:00:00 2001 From: Thomas Marchand Date: Sat, 17 Jan 2026 08:56:09 +0000 Subject: [PATCH] Rename host MCP to workspace MCP for clarity - Rename binary from host-mcp to workspace-mcp - Rename src/bin/host_mcp.rs to src/bin/workspace_mcp.rs - Update tool prefix from host_* to workspace_* - Update MCP registration name from "host" to "workspace" - Add "Builtin" tag to UI for workspace and desktop MCPs - Update documentation (CLAUDE.md, INSTALL.md, docs-site) The "workspace MCP" name better reflects that it runs in the workspace's execution context - inside containers for container workspaces, on host for host workspaces. --- .claude/CLAUDE.md | 15 ++++++ Cargo.toml | 4 +- INSTALL.md | 12 ++--- dashboard/src/app/extensions/mcps/page.tsx | 6 +++ docs-site/app/[[...mdxPath]]/docs.css | 58 ++++++++++++++++++++++ docs-site/content/setup.mdx | 4 +- src/api/system.rs | 4 +- src/bin/{host_mcp.rs => workspace_mcp.rs} | 8 +-- src/mcp/registry.rs | 22 ++++---- src/opencode_config.rs | 2 +- src/workspace.rs | 21 ++++---- 11 files changed, 119 insertions(+), 37 deletions(-) rename src/bin/{host_mcp.rs => workspace_mcp.rs} (99%) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 1d48160..b738991 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -22,6 +22,21 @@ Open Agent is a managed control plane for OpenCode-based agents. The backend **d MCPs can be global because and run as child processes on the host or workspace (run inside the container). It depends on the kind of MCP. +## Container Execution Model (Important!) + +When a **mission runs in a container workspace**, bash commands execute **inside the container**, not on the host. Here's why: + +1. OpenCode's built-in Bash tool is **disabled** for container workspaces +2. Agents use `workspace_bash` from the "workspace MCP" instead +3. The "workspace MCP" command is **wrapped in systemd-nspawn** at startup +4. Therefore all `workspace_bash` commands run inside the container with container networking + +The "workspace MCP" is named this way because it runs in the **workspace's execution context** - for container workspaces, that means inside the container. + +See `src/workspace.rs` lines 590-640 (nspawn wrapping) and 714-720 (tool configuration). + +**Contrast with workspace exec API**: The `/api/workspaces/:id/exec` endpoint also runs commands inside containers (via nspawn), but is subject to HTTP timeouts. The mission system uses SSE streaming with no timeout. + ## Design Guardrails - Do **not** reintroduce autonomous agent logic (budgeting, task splitting, verification, model selection). OpenCode handles execution. diff --git a/Cargo.toml b/Cargo.toml index d2e40d9..40c8385 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,8 +79,8 @@ name = "desktop-mcp" path = "src/bin/desktop_mcp.rs" [[bin]] -name = "host-mcp" -path = "src/bin/host_mcp.rs" +name = "workspace-mcp" +path = "src/bin/workspace_mcp.rs" [dev-dependencies] tokio-test = "0.4" diff --git a/INSTALL.md b/INSTALL.md index 364a705..385558f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -349,15 +349,15 @@ cd /opt/open_agent/vaduz-v1 source /root/.cargo/env # Debug build (fast) - recommended for rapid iteration -cargo build --bin open_agent --bin host-mcp --bin desktop-mcp +cargo build --bin open_agent --bin workspace-mcp --bin desktop-mcp install -m 0755 target/debug/open_agent /usr/local/bin/open_agent -install -m 0755 target/debug/host-mcp /usr/local/bin/host-mcp +install -m 0755 target/debug/workspace-mcp /usr/local/bin/workspace-mcp install -m 0755 target/debug/desktop-mcp /usr/local/bin/desktop-mcp # Or: Release build (slower compile, faster runtime) -# cargo build --release --bin open_agent --bin host-mcp --bin desktop-mcp +# cargo build --release --bin open_agent --bin workspace-mcp --bin desktop-mcp # install -m 0755 target/release/open_agent /usr/local/bin/open_agent -# install -m 0755 target/release/host-mcp /usr/local/bin/host-mcp +# install -m 0755 target/release/workspace-mcp /usr/local/bin/workspace-mcp # install -m 0755 target/release/desktop-mcp /usr/local/bin/desktop-mcp ``` @@ -611,9 +611,9 @@ cd /opt/open_agent/vaduz-v1 git fetch --tags origin git checkout # e.g., v0.2.1 source /root/.cargo/env -cargo build --bin open_agent --bin host-mcp --bin desktop-mcp +cargo build --bin open_agent --bin workspace-mcp --bin desktop-mcp install -m 0755 target/debug/open_agent /usr/local/bin/open_agent -install -m 0755 target/debug/host-mcp /usr/local/bin/host-mcp +install -m 0755 target/debug/workspace-mcp /usr/local/bin/workspace-mcp install -m 0755 target/debug/desktop-mcp /usr/local/bin/desktop-mcp systemctl restart open_agent.service ``` diff --git a/dashboard/src/app/extensions/mcps/page.tsx b/dashboard/src/app/extensions/mcps/page.tsx index 7c02946..26ab004 100644 --- a/dashboard/src/app/extensions/mcps/page.tsx +++ b/dashboard/src/app/extensions/mcps/page.tsx @@ -301,6 +301,9 @@ function RuntimeMcpCard({

{mcp.name}

Runtime + {(mcp.name === 'workspace' || mcp.name === 'desktop') && ( + Builtin + )}

{mcp.name}

Runtime + {(mcp.name === 'workspace' || mcp.name === 'desktop') && ( + Builtin + )} div:last-child, +aside > div:last-child, +aside > div:last-of-type { + border-radius: 0 !important; +} + +/* Ensure the sidebar footer area has no rounded corners */ +[class*="sidebar"] [class*="footer"], +[class*="sidebar"] > :last-child, +aside [class*="theme"], +aside [class*="toggle"] { + border-radius: 0 !important; +} + +/* Target any nested containers that might have rounded corners */ +.nextra-sidebar-container *, +aside.nextra-sidebar-container * { + border-bottom-left-radius: 0 !important; +} + +/* Specifically remove the bottom-left radius from the sidebar wrapper */ +.nextra-sidebar-container > div, +aside > div { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +/* Fix any pseudo-elements that might create the corner effect */ +.nextra-sidebar-container::after, +.nextra-sidebar-container::before, +aside::after, +aside::before { + border-radius: 0 !important; +} + /* ============================================ MOBILE SIDEBAR FIXES ============================================ */ diff --git a/docs-site/content/setup.mdx b/docs-site/content/setup.mdx index df26c58..18c1f9e 100644 --- a/docs-site/content/setup.mdx +++ b/docs-site/content/setup.mdx @@ -64,9 +64,9 @@ cd /opt/open_agent git clone https://github.com/Th0rgal/open-agent vaduz-v1 cd vaduz-v1 -cargo build --bin open_agent --bin host-mcp --bin desktop-mcp +cargo build --bin open_agent --bin workspace-mcp --bin desktop-mcp install -m 0755 target/debug/open_agent /usr/local/bin/open_agent -install -m 0755 target/debug/host-mcp /usr/local/bin/host-mcp +install -m 0755 target/debug/workspace-mcp /usr/local/bin/workspace-mcp install -m 0755 target/debug/desktop-mcp /usr/local/bin/desktop-mcp ``` diff --git a/src/api/system.rs b/src/api/system.rs index 7bf92f3..b1adcc9 100644 --- a/src/api/system.rs +++ b/src/api/system.rs @@ -576,7 +576,7 @@ fn stream_open_agent_update() -> impl Stream impl Stream Some("host-mcp"), + "workspace" => Some("workspace-mcp"), "desktop" => Some("desktop-mcp"), _ => None, }; diff --git a/src/opencode_config.rs b/src/opencode_config.rs index 9084028..5a3968c 100644 --- a/src/opencode_config.rs +++ b/src/opencode_config.rs @@ -351,7 +351,7 @@ pub async fn ensure_global_config(mcp: &McpRegistry) -> anyhow::Result<()> { tools_obj.insert("desktop_*".to_string(), json!(true)); tools_obj.insert("playwright_*".to_string(), json!(true)); tools_obj.insert("browser_*".to_string(), json!(true)); - tools_obj.insert("host_*".to_string(), json!(true)); + tools_obj.insert("workspace_*".to_string(), json!(true)); let payload = serde_json::to_string_pretty(&root)?; tokio::fs::write(&config_path, payload).await?; diff --git a/src/workspace.rs b/src/workspace.rs index 7623ddf..09661dd 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -711,19 +711,22 @@ async fn write_opencode_config( } } - // Disable OpenCode's builtin bash tools so agents must use the host MCP's bash. - // For container (nspawn) workspaces, the host MCP runs INSIDE the container via - // systemd-nspawn wrapping, so its bash tool has container networking (Tailscale, etc). + // Disable OpenCode's builtin bash tools so agents must use the workspace MCP's bash. + // + // The "workspace MCP" is the MCP provided by Open Agent that runs in the workspace's + // execution context. For container (nspawn) workspaces, this MCP runs INSIDE the + // container via systemd-nspawn wrapping (see lines 590-640), so its bash tool executes + // commands inside the container with container networking (Tailscale, etc). // For host workspaces, disable bash entirely (security: no host shell access). let mut tools = serde_json::Map::new(); match workspace_type { WorkspaceType::Chroot => { - // Disable OpenCode built-in bash - agents must use host MCP's bash + // Disable OpenCode built-in bash - agents must use workspace MCP's bash // which runs inside the container with container networking tools.insert("Bash".to_string(), json!(false)); // Claude Code built-in tools.insert("bash".to_string(), json!(false)); // lowercase variant - // Enable MCP-provided tools (host MCP runs inside container via nspawn) - tools.insert("host_*".to_string(), json!(true)); + // Enable MCP-provided tools (workspace MCP runs inside container via nspawn) + tools.insert("workspace_*".to_string(), json!(true)); tools.insert("desktop_*".to_string(), json!(true)); tools.insert("playwright_*".to_string(), json!(true)); tools.insert("browser_*".to_string(), json!(true)); @@ -735,8 +738,8 @@ async fn write_opencode_config( tools.insert("desktop_*".to_string(), json!(false)); tools.insert("playwright_*".to_string(), json!(false)); tools.insert("browser_*".to_string(), json!(false)); - // Only allow host MCP tools (files, etc) - tools.insert("host_*".to_string(), json!(true)); + // Only allow workspace MCP tools (files, etc) + tools.insert("workspace_*".to_string(), json!(true)); } } config_json.insert("tools".to_string(), serde_json::Value::Object(tools)); @@ -1648,7 +1651,7 @@ async fn sync_workspace_mcp_binaries( working_dir: &Path, container_root: &Path, ) -> anyhow::Result<()> { - for binary in ["host-mcp", "desktop-mcp"] { + for binary in ["workspace-mcp", "desktop-mcp"] { copy_binary_into_container(working_dir, container_root, binary).await?; } Ok(())