Docs > Change
Attach a desktop agent
This page describes the MCP endpoint that every interactive Shift session serves, the four tools it offers, the policy and security rules that apply to callers, and how to attach Codex, Claude Desktop and ChatGPT to the terminal session you already have open. The last section covers the other direction: Shift as an MCP client that uses other servers' tools.
The endpoint
An interactive session starts an HTTP MCP server inside its own Guile process. The first session listens at:
http://127.0.0.1:7331/mcp
The Session tab shows the address of the current session. There is no daemon, no separate executable and no stdio transport: the session is the server. It shares the terminal's settings, conversation, generation and approval policy, and the endpoint stops when the session ends. A port collision fails with a clear error rather than attaching to another session.
Three options control it:
--mcp-port PORTpins a port. It also starts the endpoint for sessions with piped input, which otherwise do not serve one.--no-mcpdisables the endpoint for the session.- Leaving
mcpout ofSHIFT_BUILTINSdisables it as a built-in.
The server answers Streamable HTTP POST requests with JSON responses and has no notification stream. A GET returns 405.
The tools
| Tool | What it does |
|---|---|
shift_status | Reports the process ID, project, session, settings, generation and current turn. |
shift_prompt | Submits a prompt as a turn in the session's current mode. While a turn is running, a second mutating request gets a busy error. |
shift_inspect | Runs a read-only command such as /show or /receipt. It cannot invoke /eval, change the mode, or pass slash commands through the prompt tool. |
shift_cancel | Cancels the active turn and keeps the checkpoint taken before it. |
Terminal and MCP share one controller. Mutating requests serialize, and status stays available while a turn runs. Clients that keep the Mcp-Session-Id returned by initialize appear in the terminal as peers, with their calls listed beside them.
Policy still applies
A prompt from an MCP client runs under the same rules as a typed one: the current mode, the allowlist, the judge and the receipt. Anything that needs an interactive approval is denied to the caller. Approve it from the terminal instead, where the peer's request is visible. Tool policy describes the modes.
Security
- The server binds the loopback interface only. Nothing outside the machine can reach it unless you put a tunnel in front of it.
- Every request's
HostandOriginheaders are validated. - Set
SHIFT_MCP_TOKENin the session's environment to require a Bearer token from clients.
Attach Codex
Codex reads MCP servers from .codex/config.toml. The Shift repository registers the endpoint this way, so a Codex session opened in the checkout can call shift_status and shift_prompt against the terminal you have open:
[mcp_servers.shift]
url = "http://127.0.0.1:7331/mcp"
startup_timeout_sec = 10
tool_timeout_sec = 600
Attach Claude Desktop
Claude Desktop launches stdio servers from its configuration file, so it needs a bridge to the HTTP endpoint. To attach it:
- Start a Shift session in the terminal.
- Add the following to
claude_desktop_config.json:{ "mcpServers": { "shift": { "command": "npx", "args": ["-y", "mcp-remote", "http://127.0.0.1:7331/mcp"] } } } - Restart Claude Desktop.
mcp-remote runs through npx and forwards the app's stdio session to the URL.
Attach ChatGPT
ChatGPT's connectors take an MCP URL, but the app has to reach it, and this server binds loopback only. To attach it:
- Set
SHIFT_MCP_TOKENbefore you start the session. The tunnel in step 3 makes the session reachable from outside your machine, so the token is required here, not optional. - Start the session.
- Put a tunnel in front of the port.
- Register the tunnel's URL as the connector's MCP URL.
Note: Whatever the client, prompts run in the current mode, approvals stay in the terminal, and the terminal shows each client as a peer with its calls. Attaching a desktop agent adds a caller; it does not add authority.
Use MCP servers from Shift
Shift is also an MCP client. Servers are data in .shift/mcp.scm in the project, which you can commit, and in ~/.config/shift/mcp.scm for your user. Shift reads the file and never evaluates it, and a project server shadows a user server of the same name. To lint a file, run ./bin/shift-agent --check-mcp FILE.
((server "github"
(command "npx" "-y" "@modelcontextprotocol/server-github")
(env GITHUB_TOKEN))
(server "docs"
(url "https://docs.example.com/mcp")
(header "Authorization" "Bearer $DOCS_TOKEN")))
A command server starts as a child of the session with a minimal environment plus the variables named in env. A url server speaks Streamable HTTP and keeps its Mcp-Session-Id. Secrets come only from the project's local environment file: env names are copied from there and $NAME in a header expands from there, so a committed file cannot read a variable you did not put in it.
Servers connect at the first tool_search or /mcp connect NAME, with a ten-second budget; a failure is kept with its reason until you retry. Tools are named SERVER__TOOL, and a tool that would shadow a built-in is refused. Their schemas never sit in the system prompt. The model sees server names and one-line descriptions, calls tool_search with a few words or select:SERVER__TOOL, and up to eight matching tools become callable for the rest of the turn. The receipt lists them as mcp_tools.
Policy treats an MCP tool like any other: manual mode asks, autopilot allows, and plan mode allows only tools the server marks as read-only, non-destructive and closed-world. /allow-mcp SERVER__TOOL [project|user] puts a tool on the same scoped allowlist as runs, so a project can commit that github__search_issues never asks.
| Command | Effect |
|---|---|
/mcp | Lists servers with their state and tool counts. |
/mcp connect NAME | Connects a server now instead of at the first search. |
/mcp disconnect NAME | Drops the connection. |
/mcp tools NAME | Shows the tools a connected server offers. |
The Session tab's SERVERS section shows the same state, and clicking a server that is not connected connects it. Results are bounded to 64 KiB; images and other non-text content are named with their type and size rather than inlined.
What's next
- Tool policy for the modes that decide what an attached client's prompt may do.
- Terminal for the Session tab, where peers and servers appear.
- Sessions for the session the endpoint belongs to.