Add a Remote MCP Server to OpenCode: Config, OAuth and Fixes
How to add a remote MCP server to OpenCode: the type remote entry in opencode.json, headers with {env:...}, OAuth that starts on a 401, opencode mcp auth and debug, the timeout in milliseconds, and fixing a server that will not connect.
OpenCode takes a remote MCP server as one entry under mcp in opencode.json, with "type": "remote" and the server's url [1]:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"my-server": {
"type": "remote",
"url": "https://mcp.example.com/mcp",
"enabled": true
}
}
}
Or run opencode mcp add, which walks you through adding a local or a remote server [3].
Everything below is checked against OpenCode's documentation on 2 November 2026 [1][2][3].
TL;DR:
typeis"remote", nothttporstreamable-http. It is required, and so isurl[1].- Two places for the file:
~/.config/opencode/opencode.jsonfor every project,opencode.jsonin a project's root for one [2]. They merge; they do not replace each other [2]. - OAuth starts on its own when the server answers
401, and registers itself with the server where it can [1]. timeoutis in milliseconds, default 30000 when connecting and fetching tools [1].
Where the entry goes
| File | Scope |
|---|---|
~/.config/opencode/opencode.json |
Every project on this machine [2] |
opencode.json in the project root |
This project. OpenCode looks in the current directory, then up to the nearest Git directory [2] |
The path in OPENCODE_CONFIG |
A custom file, loaded after the global one and before the project's [2] |
Files are merged, so a server in the global file and another in the project file are both loaded. Where the same key is set twice, the later source wins, and the project file comes after the global one [2]. Both files may be JSONC, so comments are allowed [2].
The URL is the MCP endpoint itself, usually ending in /mcp, not the product's homepage or its docs page.
The fields a remote entry takes
| Field | Required | What it does [1] |
|---|---|---|
type |
Yes | Must be "remote" |
url |
Yes | The server's endpoint |
enabled |
No | false keeps the entry but skips it on startup |
headers |
No | Headers sent with every request |
oauth |
No | Sign-in settings, or false to turn sign-in detection off |
timeout |
No | Milliseconds, including tool calls |
Keep the token out of the file
OpenCode replaces {env:NAME} with an environment variable and {file:path} with a file's contents [2]. A server that takes an API key:
"my-server": {
"type": "remote",
"url": "https://mcp.example.com/mcp",
"oauth": false,
"headers": {
"Authorization": "Bearer {env:MY_SERVER_TOKEN}"
}
}
An unset variable becomes an empty string [2], so a missing export shows up as a 401, not as an error in the file. "oauth": false tells OpenCode the server uses a key, so it does not try to start a sign-in [1].
Sign in to a server that needs it
You usually configure nothing. When a server answers 401, OpenCode starts the OAuth flow, uses Dynamic Client Registration if the server supports it, and keeps the tokens for later requests [1]. It asks you on first use, or you start it yourself [1]:
opencode mcp auth my-server
That opens your browser to the server's sign-in page [1]. Tokens are stored in ~/.local/share/opencode/mcp-auth.json [1].
If the server does not support self-registration, give OpenCode a client you registered with it [1]:
"my-server": {
"type": "remote",
"url": "https://mcp.example.com/mcp",
"oauth": {
"clientId": "{env:MY_SERVER_CLIENT_ID}",
"clientSecret": "{env:MY_SERVER_CLIENT_SECRET}",
"scope": "tools:read"
}
}
MCP OAuth covers what a server has to publish for that sign-in to work.
The mcp commands
| Command | What it does [3] |
|---|---|
opencode mcp add |
Walks you through adding a local or remote server |
opencode mcp list (or ls) |
Every configured server and its connection status |
opencode mcp auth [name] |
Signs in to an OAuth server; without a name, you pick one |
opencode mcp auth list |
Which servers use sign-in and whether you are signed in |
opencode mcp logout [name] |
Removes the stored credentials |
opencode mcp debug <name> |
Shows the sign-in status, tests the HTTP connection and tries the OAuth discovery flow [1] |
Keep the tool list small
Every tool a server exposes goes into the model's context, and OpenCode's documentation warns this "can quickly add up if you have a lot of tools" [1]. Tools are named with the server's name as a prefix, so one glob switches a whole server's tools off [1]:
{
"tools": {
"my-server_*": false
}
}
Turn them back on for one agent by setting "my-server_*": true in that agent's tools [1]. How many tools should an MCP server have covers the server side of the same problem.
When it will not connect
| What you see | Usual cause | Fix |
|---|---|---|
The server is missing from opencode mcp list |
type is not "remote", or the file is not the one OpenCode reads |
Use "type": "remote"; check the path and OPENCODE_CONFIG |
| It is listed but skipped | "enabled": false |
Set it to true |
401 with a key in headers |
The {env:...} variable is unset, so the header is empty |
Export it in the shell you start OpenCode from |
401, then a browser tab you did not expect |
The server uses OAuth | Finish the sign-in, or run opencode mcp auth my-server |
| Sign-in fails | The server does not allow self-registration, or its metadata is wrong | Run opencode mcp debug my-server; add clientId if you have one |
| Signed in as the wrong account | Old tokens are still stored | opencode mcp logout my-server, then sign in again |
| The model gets slower or loses track | Too many tools in context | Switch tools off with a "my-server_*": false glob |
| A slow tool fails | The timeout | Raise timeout, in milliseconds |
For what the server's own error codes mean, see MCP server errors and MCP server connection failed.
Check it from outside before you share it
OpenCode connects from your own machine, so a server on localhost or your VPN works for you and for nobody else. Our MCP connection test calls your server from our network, runs the handshake and tools/list, and reports what a stranger on the internet gets back, with a dated URL you can share. If it passes there and fails in OpenCode, the problem is in your configuration, not the server.
The same setup in other clients is in Claude Code, Codex, Gemini CLI, GitHub Copilot CLI, Warp, Cursor, VS Code, Cline, LibreChat, Claude Desktop and ChatGPT, and remote MCP server vs stdio covers whether your server should have a public address at all.