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.Antigravity uses the ACP provider with built-in binary auto-discovery.
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: ChatGPT MCP Bridge
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. Runtime configuration remains in config.yaml, while the profile is a Markdown file:
agents:
codex:
command: codexSave the profile as ~/.spacedock/agents/local-codex.md (or in the workspace-local .spacedock/agents/ directory):
---
schema: spacedock-agent/v1
id: local-codex
provider: codex
model: gpt-5.6-luna
effort: medium
write_mode: allowed
---
Implement only the supplied approved patch specification.Local Copilot ACP use requires an executable endpoint command. The parser requires an absolute executable path, with args: [--acp]; runtime endpoint configuration remains in config.yaml, and the profile is Markdown:
acp:
endpoints:
- id: copilot
command: /absolute/path/to/copilot
args: [--acp]
env_from: {}Save ~/.spacedock/agents/local-copilot.md:
---
schema: spacedock-agent/v1
id: local-copilot
provider: acp
endpoint_id: copilot
permission_policy: auto
config_options: {}
---
Follow the supplied task scope and report blockers.Agent profiles
Primary agent profiles are Markdown files with YAML frontmatter and a Markdown body. The required frontmatter is schema: spacedock-agent/v1, id, and provider; optional fields are name, description, endpoint_id, permission_policy, mode_id, config_options, model, effort, and write_mode. The body is the instructions; instructions is not a frontmatter field.
SpaceDock reads global profiles from <state_dir>/agents/*.md (by default ~/.spacedock/agents/*.md) and workspace-local profiles from <workspace-root>/.spacedock/agents/*.md. A global Markdown profile with the same ID replaces a legacy YAML profile. Local Markdown profiles may add profiles, but cannot shadow any machine-owner ID from the global Markdown or legacy configuration; such collisions are rejected. Missing agent directories are allowed. spacedock init creates the global agents directory but no default profile files.
Profiles are reread on every agent_list and agent_run, so Markdown edits take effect without restarting SpaceDock. Changes to runtime/provider settings in config.yaml—including agents.max_concurrent, agents.codex.command, and acp.endpoints—still require a process/service restart. Legacy agents.profiles in config.yaml is supported only as a compatibility fallback and is not the recommended setup. See examples/agents/ for examples.
The 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.
Configure runtime/provider settings in config.yaml; define agent profiles as Markdown in ~/.spacedock/agents/*.md or workspace .spacedock/agents/*.md. See config.example.yaml and examples/agents/ for examples.
Codex CLI provider
Codex uses the Codex CLI itself, not an ACP adapter.
agents:
max_concurrent: 4
codex:
command: codexCreate a profile such as ~/.spacedock/agents/codex1.md with provider: codex, optional model and effort, and write_mode (read_only, allowed, or full_access; default read_only). Put the worker instructions in the Markdown body. See codex-implementer .
SpaceDock 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 body 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.
acp:
endpoints:
- id: copilot
name: GitHub Copilot ACP
command: /absolute/path/to/copilot
args: [--acp]
env_from: {}Create ~/.spacedock/agents/copilot1.md with provider: acp, required endpoint_id, optional mode_id and config_options, and permission_policy (auto, manual, or allow_once; default auto). auto is specific to high-level Agent profiles: agent_run maps it to ACP allow_once so non-interactive workers can approve one-shot tool requests without stalling. Codex-only fields model, effort, and write_mode are invalid for ACP profiles. See copilot-worker.
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.
Antigravity ACP provider
Antigravity connects to SpaceDock via the Agent Control Protocol (ACP). With the builtin: antigravity preset, SpaceDock automatically discovers and configures the executable, eliminating the need to look up absolute paths manually.
Runtime configuration (config.yaml)
In most cases, specifying builtin: antigravity is all that is required:
acp:
endpoints:
- id: antigravity
name: Antigravity ACP
builtin: antigravity
env_from: {}Note: If you prefer to point to a specific binary path rather than relying on auto-discovery, you can explicitly set
command: /path/to/agy_acp_serverjust like standard ACP endpoints.
Agent profile (~/.spacedock/agents/antigravity-worker.md)
Create an ACP profile with provider: acp and endpoint_id: antigravity (see antigravity-worker):
---
schema: spacedock-agent/v1
id: antigravity-worker
name: Antigravity Worker
description: Executes tasks using Antigravity via ACP.
provider: acp
endpoint_id: antigravity
permission_policy: auto
config_options: {}
---
Follow the supplied task scope exactly. Report blockers instead of expanding the task or inventing new requirements.Executable resolution order
When using builtin: antigravity, SpaceDock searches for the executable in the following priority order, automatically normalizing the resolved binary to an absolute path:
Explicit
command: Directly specified inconfig.yamlEnvironment variables:
ANTIGRAVITY_COMMAND→AGY_ACP_COMMANDagy_acp_serverwrapper (Recommended): Found inPATHor~/.local/binPreferred because authenticated installations may use it to inject necessary runtime libraries and identity arguments.
agy_acp_server.parbinary: Found inPATHor~/.local/share/agy_acp_server(agy_acp_server.exeon Windows)
Key behaviors and tips
Automatic path normalization: Unlike manual ACP endpoints that require manual
whichinspection, SpaceDock automatically resolves and normalizes the executable to an absolute path before launch.Automatic
--uid=argument on Linux: When directly launching the.parbinary on Linux withargsomitted,--uid=is appended automatically for environment compatibility. Specifyargs: []to suppress this default, or provide your own argument list.Unified lifecycle: Registered Antigravity agents integrate directly with both high-level Agent tools (
agent_run,agent_continue,agent_show) and low-levelacp_*tools following the standardinitialize→session/new→session/promptworkflow.
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.
For low-level acp_connect, permission_policy remains manual or allow_once and defaults to manual. In manual mode, permission requests are exposed through acp_interactions and answered through acp_respond; permanent/always options are not automatically exposed or selected. The high-level Agent profile additionally supports auto; agent_run translates auto to a one-shot allow_once ACP session policy and never selects permanent/always permission options.
Agent tools
The high-level Agent API is provider-agnostic:
agent_list
agent_run
agent_show
agent_continue
agent_stopagent_runresolves the Markdown (or legacy fallback) profile and starts either a Codex CLI or ACP provider turn. ACP Agent profiles default topermission_policy: auto, which is mapped internally to one-shotallow_onceapproval for the worker session.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.
References
SpaceDock is inspired by and references ideas from the following open-source projects:
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.
Connect any AI agent to 1,000+ apps and 27,000+ actions through one remote MCP server (OAuth).
Related MCP Servers
- 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.7MIT
- AlicenseNot gradedqualityBmaintenanceEnables ChatGPT to read and edit local project files, inspect Git changes, and run approved development scripts through a secure MCP tunnel, with optional Codex Desktop integration.99 npm4Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables ChatGPT to access a remote computer or server via an outbound-only agent, providing filesystem inspection, file editing, Git inspection, and optional shell execution through MCP.MIT
- AlicenseNot gradedqualityAmaintenanceConnects ChatGPT and MCP clients to authorized local development environments, enabling secure file access, shell execution, persistent tasks, browser/desktop control, and remote management of projects.13MIT