MCP servers and custom tools
Give the agent access to a database, an issue tracker or a browser through MCP, and manage the context cost and trust that comes with it.
Local and remote servers
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"filesystem": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."],
"enabled": true
},
"postgres": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-postgres"],
"environment": { "DATABASE_URL": "{env:DATABASE_URL}" }
},
"sentry": {
"type": "remote",
"url": "https://mcp.sentry.dev/mcp",
"enabled": false
}
}
}| Field | Applies to | Notes |
|---|---|---|
type | Both | local speaks stdio, remote speaks HTTP |
command | Local | Argv array - no shell parsing |
environment | Local | Environment for the child process |
url | Remote | The server endpoint |
headers | Remote | Auth headers, if the server needs them |
enabled | Both | Keep disabled entries configured but off |
- Tools appear to the agent prefixed with the server name, so
postgrescontributes tools namedpostgres_*. - Keep unused servers in the file with
enabled: false- the configuration is the documentation of what is available.
Every tool has a context price
Tool definitions from connected servers are part of the prompt on every turn. Adding four servers with twenty tools each makes the session permanently more expensive and, more subtly, makes tool selection harder: the model has more ways to be wrong.
# how much context is in play right now
/context
# a rough comparison: connect one server, measure, connect another, measure
opencode run "how many tools do you currently have available?"⚠️
MCP output is untrusted text that lands in your context. A server that reads an issue tracker can carry a stranger's words straight into the model's reasoning, and a server with a write-capable token can be talked into using it. Use read-only credentials where possible, and prefer a token scoped to one resource over an account-wide key.
Scoping and troubleshooting
{
"mcp": {
"postgres": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-postgres"],
"environment": { "DATABASE_URL": "{env:DATABASE_READONLY_URL}" }
}
},
"permission": {
"bash": { "*": "ask", "git status*": "allow" }
}
}- Point the agent at a read-only database role so the worst case is a bad query, not a bad write.
- A local server that fails to start produces no tools and no obvious error in the TUI; run the command by hand to see why.
- Remote servers usually authenticate with OAuth on first use, and the token is stored with your other credentials.
- Disable a server rather than deleting it when you are debugging - it is one flag to restore.
The honest test of whether a server is worth its context is whether you would notice its absence. If you would not, disable it.
FAQ
What is the difference between a local and a remote MCP server?
A local server is a process started on your machine and spoken to over stdio; a remote server is an HTTP endpoint you connect to. Local servers can reach localhost-only services and your filesystem. Remote servers are easier to share across a team but send tool arguments to a third party.
My MCP server is enabled but the agent never uses it. Why?
Check that the server actually started - run its command by hand. If it starts, the issue is usually that its tool descriptions are vague, so the agent cannot tell when to use them. Ask the agent to list its tools to confirm they are visible.
Related
Skills, plugins and custom commands Permissions, privacy and secret handling
Last refreshed 2026-09-18.