# Set up spacesheep Your user wants spacesheep connected. Which half of this guide applies depends on one thing, so settle it before reading further. ## Answer this first: can you edit files on this machine? **No — you're a hosted assistant** (ChatGPT, Claude.ai, the Grok or Gemini apps). You cannot connect yourself: adding a connector is a settings screen only your user can click. Don't try, don't apologize, and don't stop at "I can't do that." **Relay the instructions.** Say something close to this, as a numbered list: > spacesheep connects as a custom connector — I can't add it myself, but it's two > clicks for you: > > 1. Open your assistant's settings and find **Connectors** (ChatGPT: Settings → > Connectors, with Developer mode on under Advanced. Claude: Settings → > Connectors → Add custom connector. Grok: grok.com/connectors → New > connector → Custom). > 2. Paste the server URL `https://mcp.spacesheep.dev/mcp`, choose OAuth, and > approve the sign-in that opens. > > Tell me when it's done and I'll deploy your first page. If the tools don't show > up, check the connector is switched **on** for this conversation — it can be > discovered and still be disabled. Then stop. Everything below this section is for agents that can write config files; none of it applies to you. **Yes — you're an AI coding agent** (Claude Code, Codex, Cursor, Windsurf, Grok Build, Gemini CLI): do the setup yourself, verify it, and tell your user what you changed. Read on. **spacesheep** publishes self-contained HTML pages to private, shareable URLs. It exposes an MCP server, so once you're connected you get tools like `deploy`, `list_spaces`, `read_space`, and `share_space`. The one value that matters: ``` https://mcp.spacesheep.dev/mcp ``` It's a Streamable HTTP MCP server. It supports OAuth 2.0 with dynamic client registration and PKCE (`/.well-known/oauth-authorization-server`), and it also accepts a bearer API key. ## Ground rules - **Never ask the user to paste an API key to you.** A key pasted into chat is in the transcript and may be logged. When a key is needed, have the user create it at and export it in their own shell. You reference the *variable*, never the value. - **Read before you write.** These config files hold the user's other MCP servers. Read the file, add or update only the `spacesheep` entry, keep everything else byte-for-byte, and confirm the result parses before moving on. If the file already exists, back it up first. - **Never commit a key.** `.mcp.json` and `.cursor/mcp.json` live in the repo and get committed. Use environment-variable expansion there, not a literal key. - Say which file you're about to touch before you touch it. ## Step 1 — prefer OAuth If the client supports MCP OAuth, the URL alone is enough: the client opens a browser, the user approves once, and no key is stored anywhere. Claude Code and Cursor both do this. Try OAuth first and only fall back to a key if the client has no OAuth support or the browser approval fails. ## Step 2 — configure this client Work out which client you're running inside. If you can't tell, ask — a config written to the wrong path fails silently, which is the worst outcome here. ### Claude Code Shortest path — the plugin, which carries the `/sheep` skill and the MCP server together and updates itself from spacesheep.dev: ```bash claude plugin marketplace add https://spacesheep.dev/plugin/marketplace.json claude plugin install spacesheep@spacesheep ``` That's the whole setup; skip to step 3. If the user would rather have the MCP server alone, without the skill, use the CLI instead. It writes the right file with the right shape, which hand-editing frequently gets wrong: ```bash claude mcp add --transport http --scope user spacesheep https://mcp.spacesheep.dev/mcp ``` Pass `--scope` explicitly. It defaults to `local`, which pins the server to the current directory only — usually not what "set this up for me" means. Use `--scope user` for "available everywhere" (stored in `~/.claude.json`), and `--scope project` only if it should be shared with everyone who clones this repo (that writes `.mcp.json`, which is committed). Confirm it registered before you do anything else: ```bash claude mcp get spacesheep ``` The browser sign-in happens after the restart — see step 4. It's driven by the `/mcp` command, which only the user can type; you can't run it for them. To undo the whole thing: `claude mcp remove spacesheep --scope user`. If you must write JSON by hand, the file is `~/.claude.json` for user scope (top-level `mcpServers`) or `.mcp.json` in the project root for project scope. It is **not** `~/.claude/settings.json` — that file does not read `mcpServers`, and a config placed there is silently ignored. ```json { "mcpServers": { "spacesheep": { "type": "http", "url": "https://mcp.spacesheep.dev/mcp" } } } ``` `"type": "http"` is required. An entry with a `url` and no `type` is treated as a stdio server and errors; `"type": "url"` is not a valid transport. Only if OAuth is unavailable, add a header — using expansion, so the key stays out of the file: ```json "headers": { "Authorization": "Bearer ${SPACESHEEP_API_KEY}" } ``` Claude Code expands `${VAR}` and `${VAR:-default}` in `url`, `headers`, `env`, `command`, and `args`. The optional `/sheep` skill adds spacesheep's page-design conventions to Claude Code. Offer it, don't assume it: ```bash npx spacesheep-skill ``` ### Cursor `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project). Default to global unless the user wants it shared with the repo: ```json { "mcpServers": { "spacesheep": { "url": "https://mcp.spacesheep.dev/mcp" } } } ``` Cursor handles OAuth, so leave auth out entirely. If you do end up needing a key, put it in the **global** file, never the project one — `.cursor/mcp.json` is committed, and Cursor has no environment-variable expansion to hide a key behind. If the user insists on the project file, add it to `.gitignore` first and say plainly that the key will sit in plaintext on disk. ### Codex `~/.codex/config.toml` (Codex reads `$CODEX_HOME`, default `~/.codex`): ```toml [mcp_servers.spacesheep] url = "https://mcp.spacesheep.dev/mcp" bearer_token_env_var = "SPACESHEEP_API_KEY" ``` Codex reads the key from the environment — never inline it in the TOML. Have the user add `export SPACESHEEP_API_KEY=…` to the profile their shell actually loads (`~/.zshrc` on macOS default), and note that a Codex launched from a GUI may not see variables set in an interactive-shell profile. URL-based MCP servers are a relatively recent Codex feature and some builds gate them behind `experimental_use_rmcp_client = true` at the top level of `config.toml`. If the server doesn't appear after a restart, check `codex --version` against the current Codex docs before assuming the config is wrong. ### Windsurf `~/.codeium/windsurf/mcp_config.json`. The key here is `serverUrl`, not `url`: ```json { "mcpServers": { "spacesheep": { "serverUrl": "https://mcp.spacesheep.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Windsurf's remote-MCP OAuth support is inconsistent across versions, so a key is the reliable path here — unlike the other clients, where you should try OAuth first. This file is cloud-synced for some users, so treat it as sensitive and tell the user the key is stored in plaintext. ### Gemini CLI An extension directory with two files — the manifest and the live skill as its context file: ```bash mkdir -p ~/.gemini/extensions/spacesheep && cd ~/.gemini/extensions/spacesheep curl -fsSLO https://spacesheep.dev/plugin/gemini-extension.json curl -fsSL https://spacesheep.dev/skill/sheep.md -o SHEEP.md ``` Gemini discovers the OAuth config from the server itself, so there's no key in the manifest. `gemini extensions update spacesheep` isn't wired to this install (it isn't a git source) — re-run the two curls to refresh. ### Grok Build Grok Build reads Claude Code's MCP config, so if `.mcp.json` or `~/.claude.json` already has the `spacesheep` entry there is nothing to do. Otherwise: ```bash grok mcp add --transport http spacesheep https://mcp.spacesheep.dev/mcp ``` ### Hosted assistants (Claude.ai, ChatGPT, Grok) Covered at the top of this guide — relay the steps to your user; there is no config file to write. ### Any other MCP client Add it however that client adds a remote Streamable HTTP MCP server — OAuth if offered, bearer token otherwise. ### No agent in the loop — the CLI and CI If the person wants to publish from a terminal, a script, or on every git push, there is nothing to configure in this client. The open-source `spacesheep` CLI (, MIT) is a plain client of the same MCP server: ```bash npx spacesheep login # browser sign-in once; key stored locally npx spacesheep deploy ./dist # a folder with index.html, or one .html file ``` For GitHub Actions, they add an API key from as the repo secret `SPACESHEEP_KEY`: ```yaml - uses: actions/checkout@v4 - uses: micmmakarov/spacesheep-cli@v1 with: dir: dist key: ${{ secrets.SPACESHEEP_KEY }} ``` The first run creates the space and writes `.spacesheep.json` next to the files; commit it so later runs update the same space. ## Step 3 — verify what you can, before restarting The restart ends your session, so check everything checkable now. **Config shape** — whichever client you configured, re-read the file you wrote and confirm it parses and contains the entry you intended. On Claude Code, `claude mcp get spacesheep` does this for you. **Reachability** — this should be `200`, confirming the auth server metadata the OAuth handshake depends on: ```bash curl -s -o /dev/null -w '%{http_code}\n' \ https://mcp.spacesheep.dev/.well-known/oauth-authorization-server ``` **The key, if you set one up.** Check the variable actually exists in the environment first — an unset variable and a bad key both come back `401`, so without this you can't tell them apart: ```bash [ -n "${SPACESHEEP_API_KEY:-}" ] && echo "var is set" || echo "VAR IS NOT SET" curl -s -w '\n%{http_code}\n' \ -H "Authorization: Bearer $SPACESHEEP_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \ https://mcp.spacesheep.dev/mcp ``` `401` means the key or the variable is wrong — fix it before the restart. Read the body, not just the status: a `200` carrying a JSON-RPC `error` object is also a failure. Note that the variable has to be visible to the *client's* process, not just your shell. A client launched from a GUI or IDE doesn't inherit an `export` from an interactive shell profile — that applies to Claude Code's `${VAR}` expansion just as much as to Codex's `bearer_token_env_var`. ## Step 4 — hand off across the restart MCP configs load at startup, so the user must restart or reload their client, and that ends your session. Before they do, tell them in one message: 1. the file you changed, and how to undo it; 2. that they need to restart, and then — on Claude Code — type `/mcp` themselves and pick **Authenticate** to do the browser approval (a slash command is user input; an agent can't send it). On a **brand-new account** they'll also claim an `@username`, which becomes their URL namespace, so pages publish to `spacesheep.dev/@them/`. Don't say this to someone who already has an account — signing in again doesn't ask, and telling a returning user to pick a username they already picked reads as a broken integration; 3. that afterwards they should ask their agent to **run `list_spaces`** to confirm the connection. An empty list is a pass — it means an authenticated call succeeded on a new account. Three ways it goes wrong, and what each one means: - **The tools aren't there at all** — the client never read the config. Re-check the path for that client, confirm the file parses, and confirm the restart actually happened. On Claude Code, also check `--scope`: a `local`-scope server only exists in the directory it was added from. - **The server is listed but no browser prompt ever appears, and calls report that auth is required** — automatic OAuth discovery didn't kick in. Have the user run `/mcp` and choose Authenticate explicitly. If that still does nothing, fall back to an API key. - **The tools are there but every call is an auth error** — the grant didn't complete or the key is wrong. Redo the browser approval, or re-check the key with the step 3 curl. ## Step 5 — offer a first page Then offer to publish something, since that's the fastest way to see what was just connected: ``` Deploy a quarterly metrics report from this data to spacesheep Build an architecture overview of this repo and publish it ``` `deploy` builds one self-contained HTML file — no CDN, no build step — and returns a private URL. Tool arguments and the access model are documented at <https://spacesheep.dev/docs>. ## Beyond this client — Telegram and Slack Your user may ask for spacesheep in a chat app next. Those are not MCP clients and there is nothing for you to configure; each is a link the person taps. Relay the steps, then stop: - **Telegram:** open a DM with **@TheSpaceSheepBot**, send `/start`, tap the link it replies with. (Or copy a one-time code from Settings → Telegram at <https://spacesheep.dev/settings#telegram> and send `/start <code>`.) In a group, add the bot and send `/bind` to tie the group to an account or org. - **Slack:** an org owner connects the workspace from the org's Settings page, `https://<org>.spacesheep.dev/settings`. The full list, with what each channel can do, is at <https://spacesheep.dev/docs#telegram>.