opencode remote MCP entry for Sume: env syntax and a longer timeout

The hosted Sume server in opencode.json: type remote, a bearer header from an env variable, a timeout above jobs_wait's 55 s cap. Checked by a script.

5 min readSume
All posts

In opencode, add the hosted Sume server under mcp in opencode.json as a remote entry pointing at the hosted MCP URL from the quickstart, read the API key from the environment with the {env:SUME_API_KEY} syntax, and set timeout above 55000. Per the opencode MCP servers documentation (read 2026-10-06), a remote entry takes type, url, enabled, headers, timeout and oauth, and the documented default timeout is 5000 ms (described for fetching tools). A 5 second limit is shorter than the 50 second default hold of jobs_wait, so if the same limit applies to a call, a healthy wait may look like an error; raising it is cheap insurance.

Unlike some clients, opencode does expand an environment reference inside a header, so the key never has to appear in the file.

How does the key get in without sitting in the file?

The header form is "Authorization": "Bearer {env:SUME_API_KEY}", which uses the {env:VAR_NAME} syntax that the opencode documentation shows for header values. Per Sume hosted OAuth and API keys, an API key sent as a bearer token gives the full hosted tool set, and writes and paid calls still need an idempotency_key. Set SUME_API_KEY in your shell profile or your secrets manager, not in the repository.

Should I turn OAuth off?

The oauth field is the other option. The opencode docs describe it as an object, or false to turn automatic OAuth off. If you send your own Authorization header, set "oauth": false so the client does not try a browser flow on top of it. If you prefer OAuth, drop headers entirely and sign in; the default grant is mcp:read, and write access needs the Write toggle at consent.

What does the whole entry look like, and how do I check it?

import json

cfg = json.loads("""
{
  "mcp": {
    "sume": {
      "type": "remote",
      "url": "https://mcp.sume.com/mcp",
      "enabled": true,
      "headers": {"Authorization": "Bearer {env:SUME_API_KEY}"},
      "timeout": 90000,
      "oauth": false
    }
  }
}
""")
e = cfg["mcp"]["sume"]
assert e["type"] == "remote" and e["url"].endswith("/mcp")
assert e["headers"]["Authorization"] == "Bearer {env:SUME_API_KEY}"
assert e["timeout"] > 55000, "jobs_wait can hold up to 55 s"
assert e["oauth"] is False
print("opencode entry ok")
Settings that matter for Sume, from the opencode docs and Sume hosted tools and gates (read 2026-10-06)
SettingValue hereWhy
typeremoteHosted server over HTTP
headersBearer {env:SUME_API_KEY}Key stays in the environment
timeout90000Above the 55 s jobs_wait cap
oauthfalseA header is already sent

How do I verify the connection?

After saving, start opencode and ask the agent to call tools_list, then account_me, which are the read-only checks in the hosted quickstart. If the server shows as failed, check the variable first: an unset SUME_API_KEY leaves an empty bearer value and the server answers with an auth error. When you later run a paid tool, pass an idempotency_key, run dry_run once, and when a wait ends with wait_slice_expired call jobs_wait again with the same job ids instead of creating the job a second time.

Two habits save time with this client. First, keep enabled true only for servers you use in the current project, because every enabled server adds its tools to the agent's context and a long tool list makes the model slower to choose. Second, if you share the file, share the {env:...} form and tell teammates which variable to set; a literal key committed to a repository must be rotated, and the key list in the Sume dashboard is where you do that. If a teammate would rather not manage a key at all, they can remove headers, set oauth back to its default and sign in through the browser, which gives them a read-only session by default.

The timeout deserves one more note. It is a request timeout, and a Sume job can outlive any one call: the job continues on the server, and jobs_wait returns a slice result you simply call again. So a value like 90000 is not a promise that renders finish in 90 seconds, only headroom for one hold of up to 55 seconds plus network time. For a clip that takes minutes, expect several waits in a row.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume