TL;DR A cloud routine reads nothing from your machine, including the servers you added with
claude mcp add. If the server has a public URL, add it as a connector atclaude.ai/customize/connectorsand turn it on in the task's Connectors tab. If it doesn't, runclaude mcp add --scope projectand commit the.mcp.json.
claude mcp add stores the server in ~/.claude.json, on your machine. A cloud scheduled task (what used to be called a routine) runs in an Anthropic container that clones your repository and nothing else, so that server doesn't exist there. The task's connector list doesn't show it either: it only lists the integrations on your claude.ai account.
And nothing warns you. The run shows Succeeded, because that status only means the session ended without an error. Missing tools show up in the transcript, not on the history row.
Where your server actually lives
By default claude mcp add uses the local scope: the server is tied to the folder you added it from, inside your ~/.claude.json. Run in a scratch folder, with one server added at the default scope and another with --scope user:
claude mcp add --transport http docs https://mcp.deepwiki.com/mcp
claude mcp add --transport http --scope user docs-user https://mcp.deepwiki.com/mcp
Added HTTP MCP server docs with URL: https://mcp.deepwiki.com/mcp to local config
File modified: /tmp/claude-0/tip/lab2/home/.claude.json [project: /tmp/claude-0/tip/lab2/work]
Added HTTP MCP server docs-user with URL: https://mcp.deepwiki.com/mcp to user config
File modified: /tmp/claude-0/tip/lab2/home/.claude.json
Neither one leaves that file. And from inside the repository folder, claude mcp list no longer sees the local one, because it was added one folder up:
docs-user: https://mcp.deepwiki.com/mcp (HTTP) - √ Connected
That detail matters later, in the setup script.
The three places the cloud does read
| claude.ai connector | Repository .mcp.json |
Environment setup script | |
|---|---|---|---|
| Server | Remote, with a public URL | HTTP or stdio | HTTP or stdio |
| Reaches | All your tasks, claude.ai and your terminal | Tasks with that repository as their only repo | Every session in that environment |
| Network | Through Anthropic's servers, no allowlist | The session's: its host in Allowed domains | The session's |
| Credentials | OAuth or headers in claude.ai | An environment network secret | An environment network secret |
1. It has a public URL: add it as a connector
At claude.ai/customize/connectors, add a custom connector with the server's URL and authenticate it there: OAuth, or a fixed header if the server takes an API key. Claude connects from Anthropic's cloud, so the server has to answer from the internet: behind a VPN or a firewall it won't connect, even if your laptop reaches it. On Team and Enterprise an Owner adds it and each person connects it afterwards.
Then open the task at claude.ai/code/routines, Edit, Connectors tab, and check it's there. A new task gets every connector you had connected when you created it, so if you added this one later, include it here (or with /schedule update).
2. It travels with the repository: commit the .mcp.json
claude mcp add --transport http --scope project docs https://mcp.deepwiki.com/mcp
git add .mcp.json && git commit -m "Add docs MCP server" && git push
{
"mcpServers": {
"docs": {
"type": "http",
"url": "https://mcp.deepwiki.com/mcp"
}
}
}
In your terminal, a .mcp.json server waits for your approval. A cloud session has nobody to ask, so Claude Code loads it straight away, as it does under claude -p. In that same scratch repository, the startup event of claude -p --output-format stream-json --verbose lists it as connected:
{ "name": "docs", "status": "connected", "source": "project" }
Three conditions break it without a word:
- The task has more than one repository. Only a task with a single repository loads its
.mcp.json. - The host isn't allowed. In the Default environment, with Trusted access, a request to a host off the list fails with
403andx-deny-reason: host_not_allowed. Connectors skip that path; this server doesn't. Add its host under the environment's Allowed domains. - The command doesn't exist in the container. A stdio server started with
npxworks, because package registries are allowed. A path like/Users/you/bin/my-serverdoesn't.
3. You want it in every task of an environment: the setup script
The setup script runs as root before Claude starts, and whatever it writes to ~/.claude.json holds for the session. That's how my tips routine publishes to wmedia.es: its environment starts with this line.
claude mcp add --transport http --scope user wmedia https://wmedia.es/mcp/wmedia
The --scope user is not optional. The script starts in the folder that holds the repositories, not inside one, and a local server added there isn't visible from the repository, as the output above shows.
The API key stays out of the script and out of the environment variables, which anyone using that environment can read. It goes in as a network secret: the session's proxy adds the Authorization header only to requests for wmedia.es.
Make the task check before it works
Since Succeeded won't tell you whether the task had the server, have the task say so. Put this at the top of the prompt:
Before anything else, check that you have the mcp__docs__ tools.
If they're missing, say which one and stop without doing anything else.
Start the first one with Run now and open the run: the answer is in its transcript, not in its status.
When the server only exists on your machine
A server on localhost or on your private network can't reach the cloud through any of the three. For that there's the desktop app's Local task, which runs on your computer with your files and your MCP servers, while the computer is awake: I cover it in local scheduled tasks. Adding servers and choosing their scope is in your first MCP server.
Official docs: Automate work with scheduled tasks · Cloud environments
Requirements
- A Pro, Max, Ultra, Team or Enterprise plan with cloud scheduled tasks. Output from Claude Code v2.1.318, in a cloud container, on November 4, 2026.