SpaceDock
Provides Git workspace tools for status, diff, and log operations, and supports managed Git worktrees for isolated agent work.
Integrates with GitHub Copilot through the ACP provider, enabling agent runs and prompts via Copilot ACP sessions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SpaceDockshow me the git status in the github workspace"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
English | 한국어
SpaceDock
SpaceDock is a self-hosted MCP development runtime for controlling remote development servers from ChatGPT. It combines DevSpace-style Allowed Root/Workspace boundaries with structured Go-native development tools, and includes remote OAuth, persistent systemd operation, managed Git worktrees, real ACP prompt/turn handling, and bounded subagents from the initial release.
Subagents are not forced through a single protocol:
Codex uses the installed
codexCLI directly through itsapp-server. Nocodex-acpadapter is required.GitHub Copilot uses the ACP provider, typically by launching
copilot --acp.
Install
End users do not need Go. Node.js 18+ and npm are enough to install the prebuilt Go binary.
npm install -g @starlove7/spacedock
spacedock versionSupported targets are Linux, macOS, and Windows on x64/amd64 and arm64.
Related MCP server: codex-mcp
Local usage
For a local MCP client, the recommended setup is:
npm install -g @starlove7/spacedock
spacedock init --root /home/you/src --root-id src --root-name "Local source"
spacedock serve --stdiospacedock init creates the minimal local configuration and a valid owner token file. A manual minimal configuration must still use the parser's structure, for example:
state_dir: ~/.spacedock
server:
oauth:
owner_token_file: ~/.spacedock/oauth-owner.token
allowed_roots:
- id: src
path: /home/you/src
permissions: [fs.read, fs.write, workspace.manage]This is the minimum permission set for the filesystem tools. Add command.execute to the Allowed Root to use exec_command, and add agent.execute to use agent tools.
After initialization, manage additional Allowed Roots without editing YAML directly:
spacedock root add --path /home/you/other-project --id other --name "Other project"
spacedock root list
spacedock root remove otherEach command accepts --config <path>; when omitted, SpaceDock uses ~/.spacedock/config.yaml. A root added without an explicit ID or name derives them from the path. root add grants the same nine default permissions as spacedock init: fs.read, fs.write, command.execute, git.read, workspace.manage, recall.read, recall.write, acp.connect, and agent.execute. Changes are read when the next serve process or service restart starts; a running server is not hot-reloaded.
Config.Load validates owner_token_file even for stdio, although stdio does not use the HTTP OAuth middleware. The token file itself must therefore exist and contain a valid token; using init is recommended because it creates it.
The transport information guaranteed by SpaceDock for an stdio MCP client is:
command: spacedock
args: serve --stdio
transport: stdioWith a custom configuration, add --config <path> to the arguments. This describes the transport only and does not assume a particular client's JSON schema. Local HTTP is also supported with spacedock serve: it listens on loopback and serves /mcp, with the OAuth middleware applied. Prefer stdio for local clients that do not support OAuth.
Connect local stdio SpaceDock to ChatGPT
ChatGPT cannot attach directly to a local process's stdio pipe by registering an MCP URL such as https://spacedock.example.com/mcp. To keep SpaceDock local while using it from ChatGPT, use OpenAI Secure MCP Tunnel. tunnel-client keeps an outbound connection to OpenAI and launches SpaceDock locally as its stdio MCP child process; SpaceDock itself does not need a public inbound endpoint.
Create or select a tunnel in OpenAI Platform Tunnels. The tunnel must be scoped so it is available to the ChatGPT workspace that will use it.
Install a supported
tunnel-client, then create a restricted Runtime API key with Tunnels Read + Use permission. Keep that key inCONTROL_PLANE_API_KEY; do not put the secret directly in the MCP command or commit it to the repository.Create a local stdio profile for SpaceDock:
export CONTROL_PLANE_API_KEY="sk-..."
tunnel-client init \
--sample sample_mcp_stdio_local \
--profile spacedock-local \
--tunnel-id tunnel_0123456789abcdef0123456789abcdef \
--mcp-command "spacedock serve --stdio"
tunnel-client doctor --profile spacedock-local --explain
tunnel-client run --profile spacedock-localIf SpaceDock uses a non-default config, set the command to spacedock serve --stdio --config /absolute/path/to/config.yaml instead. Do not start a separate spacedock serve --stdio process for this profile: tunnel-client owns the stdio pipes and starts SpaceDock itself.
While
tunnel-client run --profile spacedock-localis healthy and running, open ChatGPT connector settings, choose Connection: Tunnel, and select the same tunnel or paste itstunnel_id. Keep the tunnel runtime running for connector discovery and later MCP calls.
The resulting path is:
ChatGPT
↕ Secure MCP Tunnel
OpenAI tunnel control plane
↕ outbound HTTPS
local tunnel-client
↕ stdio
spacedock serve --stdioThis is different from remote HTTPS deployment: a public SpaceDock endpoint such as https://spacedock.example.com/mcp is registered as a URL, while local stdio SpaceDock is exposed to ChatGPT through the tunnel object rather than through a public URL.
Local Codex use requires the codex CLI to be installed, available in the execution environment, and authenticated there. agents.codex.command may be a PATH name or an executable path; SpaceDock launches Codex's app-server. For example:
agents:
codex:
command: codex
profiles:
- id: local-codex
provider: codex
model: gpt-5.6-luna
effort: medium
write_mode: allowedLocal Copilot ACP use requires an executable endpoint command. The parser requires an absolute executable path, with args: [--acp]; the profile uses provider: acp and the endpoint's endpoint_id:
acp:
endpoints:
- id: copilot
command: /absolute/path/to/copilot
args: [--acp]
env_from: {}
agents:
profiles:
- id: local-copilot
provider: acp
endpoint_id: copilotThe local agent flow is agent_run(workspace_id, profile_id, prompt) → agent_show(workspace_id, agent_id[, wait_ms]) →, when needed, agent_continue(workspace_id, agent_id, prompt) → agent_show again → agent_stop(workspace_id, agent_id) when cancellation or shutdown is needed. agent_continue reuses the same provider session: the same Codex thread or the same ACP remote session. agent_stop cancels the running turn and closes the provider session. Agent tools require the Allowed Root's agent.execute permission.
All local modes still apply Allowed Root and Workspace permissions. The structured filesystem tools follow workspace_list → workspace_open → workspace-scoped read_file, list_dir, list_files, search_text, and file_edit. For commands, use exec_command; when it returns a running session, use session_observe to inspect it and session_act to interact with it.
Choose checkout when you intentionally want to modify the current checkout directly. Choose a managed worktree for an isolated detached task; a dirty managed worktree is not closed normally and requires an intentional discard action.
The structured filesystem tools always deny built-in sensitive components such as .ssh, .aws, .gnupg, .env/.env.*, credentials files, SSH keys and known_hosts, and .pem, .key, .pfx, or .p12 files. security.sensitive_paths.additional_patterns adds component globs; the built-in protection cannot be disabled by configuration. Direct access returns PERMISSION_DENIED, while broad listings and searches hide sensitive entries and do not count them. This layer applies only to structured filesystem tools. command.execute is not an OS sandbox: shell subprocesses run with the SpaceDock process's OS-user permissions, and this sensitive-path layer does not block arbitrary shell commands.
Mode | Transport | OAuth | Typical use |
Local stdio |
| HTTP OAuth middleware not used | Local MCP clients directly; ChatGPT through Secure MCP Tunnel |
Local loopback HTTP |
| Applied | Local HTTP clients that support OAuth |
Remote HTTPS | HTTPS reverse proxy/tunnel → loopback SpaceDock | Applied | ChatGPT/remote operation; operator-managed proxy/tunnel and usually systemd |
Quick start for remote ChatGPT use
For example, to allow projects below /home/ubuntu/github on an OCI host:
spacedock init \
--root /home/ubuntu/github \
--root-id github \
--root-name "GitHub Projects" \
--public-base-url https://spacedock.example.comThe default config is ~/.spacedock/config.yaml; the owner approval token is ~/.spacedock/oauth-owner.token. The token contents are never printed by init.
Then configure agent providers/profiles in config.yaml. See config.example.yaml for a complete example.
Codex CLI provider
Codex uses the Codex CLI itself, not an ACP adapter.
agents:
max_concurrent: 4
codex:
command: codex
profiles:
- id: codex1
name: codex1
description: Codex worker that implements an approved patch specification
provider: codex
instructions: Implement only the supplied patch specification.
model: gpt-5.6-luna
effort: medium
write_mode: allowedSpaceDock creates a Codex provider session with this lifecycle:
codex app-server
↓
initialize / initialized
↓
first turn: thread/start
later turn: thread/resume
↓
turn/start
↓
turn/completedagent_continue reuses the same Codex thread ID through thread/resume, preserving provider conversation context. Profile instructions are prepended only to the first agent_run; they are not re-applied on agent_continue.
write_mode maps to the Codex sandbox:
read_only -> read-only / readOnly
allowed -> workspace-write / workspaceWrite(networkAccess=true)
full_access -> danger-full-access / dangerFullAccessSpaceDock uses approvalPolicy=never for Codex worker turns so a non-interactive subagent cannot stall waiting for an approval prompt. Choose the Workspace permissions and write_mode up front according to the worker's required authority.
agents.codex.command defaults to codex and is resolved from PATH. A systemd user service may have a different PATH from your login shell. If Codex was installed through nvm or another shell-specific environment, an absolute path is safer:
agents:
codex:
command: /home/ubuntu/.nvm/versions/node/v22.23.2/bin/codexCopilot ACP provider
GitHub Copilot is connected through ACP. ACP endpoint command must be an absolute executable path.
agents:
profiles:
- id: copilot1
name: copilot1
description: Copilot ACP worker
provider: acp
endpoint_id: copilot
instructions: Implement only the supplied patch specification.
permission_policy: manual
config_options: {}
acp:
endpoints:
- id: copilot
name: GitHub Copilot ACP
command: /absolute/path/to/copilot
args: [--acp]
env_from: {}Even if copilot is available in your interactive PATH, ACP endpoints intentionally use explicit absolute paths. Use which copilot (or the platform equivalent) to locate the executable.
For provider: acp, use endpoint_id, permission_policy, mode_id, and config_options. model, effort, and write_mode are Codex-provider fields.
Persistent systemd operation
The primary Linux deployment is a user systemd service.
spacedock service install
spacedock service statusOther service commands:
spacedock service start
spacedock service stop
spacedock service restart
spacedock service status
spacedock service uninstallservice install writes ~/.config/systemd/user/spacedock.service using the current SpaceDock executable and an absolute config path, then runs systemctl --user enable --now spacedock.service.
The SpaceDock HTTP listener is intentionally loopback-only (127.0.0.1, ::1, or localhost). A user-managed HTTPS reverse proxy or tunnel must forward the public address to 127.0.0.1:8766.
ChatGPT
│ HTTPS + OAuth MCP
▼
Reverse Proxy / Tunnel
│
▼
127.0.0.1:8766
│
▼
spacedock serve (systemd --user)SpaceDock does not configure Cloudflare Tunnel/ngrok, tunnel credentials, sudo, or loginctl enable-linger. If the user service must remain active after logout, enabling linger is an operator-managed step.
ChatGPT OAuth connection
Register this MCP URL in ChatGPT:
https://spacedock.example.com/mcpRemote HTTP MCP uses OAuth access tokens, not a static bearer token. SpaceDock provides:
Protected Resource Metadata
Authorization Server Metadata
Dynamic Client Registration compatibility
Authorization Code + PKCE S256
owner-token approval page
access and refresh tokens
refresh-token rotation
scope/resource validation
RFC 9207 authorization-response
iss
When the authorization page appears, enter the contents of ~/.spacedock/oauth-owner.token. This value is an owner approval secret, not the client's OAuth access token.
Enable trust_proxy: true only behind a trusted reverse proxy that sets X-Forwarded-For correctly; it affects the client IP used for OAuth rate limiting.
Allowed Roots and Workspaces
An Allowed Root is an authorization boundary, not one project. For example:
allowed_roots:
- id: github
name: GitHub Projects
path: /home/ubuntu/github
permissions:
- fs.read
- fs.write
- command.execute
- git.read
- workspace.manage
- recall.read
- recall.write
- acp.connect
- agent.executeTypical ChatGPT flow:
workspace_list
↓
workspace_open(root_id="github", path="spacedock", mode="checkout")
↓
ws_... workspace ID
↓
workspace-scoped toolspath is relative to the Allowed Root. Absolute paths, .. escapes, URI/UNC/volume paths, and symlink escapes are rejected.
checkout
Use the existing checkout directly:
workspace_open(root_id="github", path="spacedock", mode="checkout")worktree
For isolated agent work, open a managed Git worktree:
workspace_open(
root_id="github",
path="spacedock",
mode="worktree",
base_ref="HEAD"
)Managed worktrees are detached and created below <state_dir>/worktrees/<workspace-id>. SpaceDock does not silently widen the boundary to a parent Git repository.
A dirty managed worktree is not removed by normal workspace_close; SpaceDock returns WORKTREE_DIRTY. Use workspace_discard(force=true) only when you intentionally want to discard it.
Workspace and managed-worktree metadata are persisted in workspaces.json and restored after a SpaceDock/systemd restart. Codex app-server processes, ACP processes, and agent execution sessions are process-local and are not restored.
Generic ACP tools
ACP endpoints can also be used directly, independently of Copilot subagent profiles:
acp_list
acp_connect
acp_capabilities
acp_prompt
acp_events
acp_cancel
acp_interactions
acp_respond
acp_disconnectacp_connect performs a real session/new after initialization. acp_prompt runs session/prompt on the same remote session and collects session/update notifications into a bounded event ring. Exact agent_thought_chunk events are filtered before storage/exposure.
permission_policy is manual or allow_once. In manual mode, permission requests are exposed through acp_interactions and answered through acp_respond; permanent/always options are not automatically exposed or selected.
Agent tools
The high-level Agent API is provider-agnostic:
agent_list
agent_run
agent_show
agent_continue
agent_stopagent_runresolves the profile and starts either a Codex CLI or ACP provider turn.agent_showreturns a generic run state and final response regardless of provider.agent_continuereuses the same provider session: same Codex thread or same ACP remote session.agent_stopcancels the running turn and closes the provider session.agents.max_concurrentlimits simultaneously running turns, not total agent processes.
Agent records include provider and provider_session_id. For Codex, provider_session_id is the Codex thread ID. For ACP providers it is SpaceDock's local ACP session ID.
Tool groups
SpaceDock exposes structured MCP tools instead of putting every operation behind one shell tool.
Workspace: workspace_list, workspace_open, workspace_close, workspace_discard
Files: read_file, list_dir, list_files, search_text, file_edit
Command: exec_command, session_observe, session_act
Git: git_status, git_diff, git_log
Recall: recall_search, recall_read, recall_write, recall_delete
ACP: acp_list, acp_connect, acp_capabilities, acp_prompt, acp_events,
acp_cancel, acp_interactions, acp_respond, acp_disconnect
Agent: agent_list, agent_run, agent_show, agent_continue, agent_stopFile/Git paths and command working directories are scoped to an opened Workspace.
Security boundaries
fs.* operations and the Workspace path resolver enforce Allowed Root containment. command.execute, however, is not an OS sandbox. Spawned subprocesses have the authority of the local OS user that runs SpaceDock.
The sensitive-path deny layer applies only to structured filesystem tools. It always denies .ssh, .aws, .gnupg, .env and .env.*, credentials and SSH key/known_hosts names, and .pem, .key, .pfx, and .p12 extensions. Additional component globs can be configured under security.sensitive_paths.additional_patterns; the built-in list cannot be disabled. Direct access is returned as structured PERMISSION_DENIED; broad listing/search omits sensitive entries. This layer does not restrict command.execute or arbitrary shell commands.
Codex write_mode is an additional Codex-provider execution policy; it does not replace SpaceDock's Allowed Root/permission model. ACP permission requests are also a separate layer from SpaceDock's agent.execute/acp.connect permissions.
Recommended practices:
register only trusted development directories as Allowed Roots
omit
command.execute,fs.write, andagent.executewhere they are not neededuse the minimum necessary Codex
write_modekeep the SpaceDock HTTP listener on loopback
expose it externally only through HTTPS reverse proxy/tunnel infrastructure
protect the owner token and OAuth state directory
enable
trust_proxyonly behind a trusted proxy
stdio mode
HTTP + OAuth + systemd remains the remote ChatGPT deployment. stdio is the local MCP transport; SpaceDock guarantees command: spacedock, args: serve --stdio, and transport: stdio (add --config <path> for a custom config). It does not prescribe a client-specific JSON schema, and HTTP OAuth middleware is not used in stdio mode.
spacedock serve --stdioBuild and verify from source
go test ./...
go test -race ./...
go vet ./...
go build ./cmd/spacedock
npm run build:npm-binariesThe Go module path is github.com/starlove7/spacedock.
This server cannot be deployed
Maintenance
Related MCP Connectors
The Remote MCP server acts as a standardized bridge between LLM applications (like Claude, ChatGPT, and Cursor) and external services, enabling AI agents to access external tools and resources. Its primary capability is providing a centralized search tool to discover other MCP servers and their respective tools. Unlike local implementations, it runs remotely with OAuth authentication and permission controls for security.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Connect AI agents to Filepad workspaces through OAuth MCP.
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables ChatGPT to inspect and edit local projects through a secure MCP interface, offering workspace management, file operations, git integration, and safe command execution.4MIT
- AlicenseNot gradedqualityBmaintenanceRemote MCP coding bridge that gives ChatGPT/Codex secure local workspace access, including file retrieval, semantic code intelligence, Git, diagnostics, and guarded shell execution.18MIT
- AlicenseNot gradedqualityDmaintenanceEnables ChatGPT to securely control a local workstation via an MCP tunnel, exposing 44 tools for file/project editing, git, process supervision, browser automation, and Office document handling across macOS, Linux, and Windows.5MIT
- AlicenseAqualityCmaintenanceEnables ChatGPT web to interact with local Windows/WSL shell and code workspaces via an MCP server, providing file access, shell execution, and snapshot-based workspace management with per-command authorization.18MIT