Skip to content

Web UI: MCP servers fail to spawn when Instance.directory resolves to base64-encoded path #18805

@david-strejc

Description

@david-strejc

Description

When using OpenCode Web UI (opencode web), switching between workspaces causes Instance.directory to resolve to a non-existent path containing a base64-encoded directory name. This causes all local MCP server processes to fail with ENOENT on posix_spawn, leaving sessions without any local MCP tools.

Environment

  • OpenCode version: 1.2.24 (upgraded to 1.3.0, untested yet)
  • Runtime: Bun
  • OS: Debian 12 (bookworm)
  • Setup: opencode web --port 3002 running as systemd service per user, 10 concurrent user instances on same server
  • MCP servers: 2 local (uv for Python, node for JS), 1 remote (HTTP)

Reproduction

  1. Start opencode web --port 3002 as a systemd service
  2. Open the Web UI and create a session in workspace /home/eva/workspace
  3. MCP servers start correctly — all 97 tools from unified-ads load fine
  4. Navigate to a different workspace or create additional sessions
  5. At some point, a new Instance is created where Instance.directory resolves to a base64-encoded path appended to the original workspace path

Observed Behavior

From the logs (~/.local/share/opencode/log/2026-03-12T065837.log):

Working (06:59) — real directory:

service=mcp key=unified-ads toolCount=97 create() successfully created client
directory=/home/eva/workspace

Working (07:06) — another real directory:

service=mcp key=unified-ads toolCount=97 create() successfully created client
directory=/home/eva

Broken (07:07) — base64-encoded path:

ERROR service=mcp key=unified-ads cwd=/home/eva/workspace/L2hvbWUvZXZhL3dvcmtzcGFjZQ error=ENOENT: no such file or directory, posix_spawn '/usr/local/bin/uv' local mcp startup failed
ERROR service=mcp key=imagemaker cwd=/home/eva/workspace/L2hvbWUvZXZhL3dvcmtzcGFjZQ error=ENOENT: no such file or directory, posix_spawn 'node' local mcp startup failed

An earlier log also shows:

cwd=Lw error=ENOENT ...

The string L2hvbWUvZXZhL3dvcmtzcGFjZQ is base64 of /home/eva/workspace.
The string Lw is base64 of /.

OpenCode's Web UI uses base64-encoded paths in URL routing (/<base64-dir>/session/<id>). It appears this base64 string is being used as a literal filesystem path for Instance.directory instead of being decoded first.

Impact

  • ALL local MCP servers fail (uv, node) — both unified-ads (Python/FastMCP) and imagemaker (Node.js) hit the same error
  • Only remote/HTTP MCP servers survive (they don't need posix_spawn)
  • Users see sessions where MCP tools are completely missing with no clear error in the UI
  • The ENOENT error message is misleading — it blames the executable (/usr/local/bin/uv) rather than the CWD (known Bun bug: Bun.spawn throws incorrect ENOENT error when cwd does not exist oven-sh/bun#24012)

Evidence This Is Not an MCP Configuration Issue

  1. Two completely independent MCP servers (Python via uv, Node.js via node) fail identically
  2. Both executables exist and work fine — which uv/usr/local/bin/uv, which node/usr/bin/node
  3. The MCP config is correct and works when Instance.directory is a real path
  4. OpenCode itself logs No such file or directory: '/home/eva/workspace/L2hvbWUvZXZhL3dvcmtzcGFjZQ'

Expected Behavior

Instance.directory should always resolve to a valid filesystem path. If the Web UI uses base64-encoded paths for URL routing, these should be decoded back to real paths before being used as CWD for MCP process spawning.

Potentially Related Issues

MCP Config (for reference)

{
  "unified-ads": {
    "type": "local",
    "command": ["/usr/local/bin/uv", "run", "--directory", "/opt/mcp/adsmcp", "python", "-m", "unified_ads_mcp"],
    "enabled": true,
    "environment": {
      "HOME": "/home/eva",
      "GOOGLE_ADS_CREDENTIALS": "/home/eva/google-ads.yaml",
      "META_ADS_CREDENTIALS": "/home/eva/meta-ads.yaml"
    }
  }
}

Note: There is no cwd field in the McpLocal schema (.strict() validation), so there is no workaround from the configuration side.

Suggested Fix

In the MCP spawning code, either:

  1. Decode the base64 path back to a real filesystem path before using it as CWD
  2. Validate that Instance.directory exists before passing it to Bun.spawn()
  3. Fall back to a safe default CWD (e.g., user's home directory or /tmp) if the directory doesn't exist
  4. Add a cwd option to the McpLocal schema so users can specify a fixed working directory for MCP processes

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)webRelates to opencode on web / desktop

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions