Add Context7 remote MCP server to auto-generated config
Validate / docs-check (push) Successful in 18s
Validate / validate-base (push) Failing after 11m26s
Validate / validate-omos (push) Failing after 13m14s

Context7 provides up-to-date library documentation for LLMs via a
remote endpoint — no local binary needed. Always registered since it
has no PATH dependency.

Also switches generated config from .json to .jsonc so we can include
a comment about the optional API key for higher rate limits. The
existing-config check now detects both file extensions.
This commit is contained in:
Joakim Persson
2026-05-02 21:24:04 +00:00
parent a6b0b59946
commit 3d4e739529
2 changed files with 41 additions and 11 deletions
@@ -96,6 +96,14 @@ def register_mcp_servers(config: dict) -> list[str]:
"enabled": False, "enabled": False,
} }
# Context7 — up-to-date library documentation for LLMs (remote).
# Free tier works without an API key; set CONTEXT7_API_KEY for higher
# rate limits. No local binary needed — purely a remote MCP endpoint.
servers["context7"] = {
"type": "remote",
"url": "https://mcp.context7.com/mcp",
}
if servers: if servers:
config["mcp"] = servers config["mcp"] = servers
@@ -110,14 +118,17 @@ def main() -> int:
home = Path(os.environ.get("HOME", "/home/developer")) home = Path(os.environ.get("HOME", "/home/developer"))
config_dir = home / ".config" / "opencode" config_dir = home / ".config" / "opencode"
config_file = config_dir / "opencode.json" config_file = config_dir / "opencode.jsonc"
config_file_legacy = config_dir / "opencode.json"
# CRITICAL: never overwrite an existing config. Users may have # CRITICAL: never overwrite an existing config. Users may have
# bind-mounted their host config directory, or their config may be # bind-mounted their host config directory, or their config may be
# persisted in a named volume from a previous run. # persisted in a named volume from a previous run.
if config_file.exists(): # Check both .json and .jsonc variants.
if config_file.exists() or config_file_legacy.exists():
existing = config_file if config_file.exists() else config_file_legacy
print( print(
f"Existing opencode.json found at {config_file}" f"Existing config found at {existing}"
"skipping generation.", "skipping generation.",
file=sys.stderr, file=sys.stderr,
) )
@@ -140,8 +151,23 @@ def main() -> int:
added = register_mcp_servers(config) added = register_mcp_servers(config)
config_dir.mkdir(parents=True, exist_ok=True) config_dir.mkdir(parents=True, exist_ok=True)
# Write as JSONC so we can include helpful comments.
content = json.dumps(config, indent=2)
# Insert a comment about Context7 API key after the context7 url line.
context7_comment = (
' "url": "https://mcp.context7.com/mcp"\n'
" // For higher rate limits, sign up at https://context7.com/dashboard\n"
' // and add: "headers": { "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" }'
)
content = content.replace(
' "url": "https://mcp.context7.com/mcp"',
context7_comment,
)
with config_file.open("w") as f: with config_file.open("w") as f:
json.dump(config, f, indent=2) f.write(content)
f.write("\n") f.write("\n")
if added: if added:
+11 -7
View File
@@ -160,11 +160,11 @@ else
fi fi
rm -f "$tmpout" rm -f "$tmpout"
# Config generation with anthropic provider writes valid JSON with the # Config generation with anthropic provider writes valid JSONC with the
# expected shape. The script's log message goes to stderr (line 1 of # expected shape. The script's log message goes to stderr (line 1 of
# generate-config.py uses file=sys.stderr) so capturing only stdout # generate-config.py uses file=sys.stderr) so capturing only stdout
# gives us clean JSON. # gives us clean JSONC. We strip // comments before validating JSON.
label="generate-config produces valid opencode.json" label="generate-config produces valid opencode.jsonc"
tmp=$(mktemp -d) tmp=$(mktemp -d)
if docker run --rm \ if docker run --rm \
-e OPENCODE_PROVIDER=anthropic \ -e OPENCODE_PROVIDER=anthropic \
@@ -173,24 +173,28 @@ if docker run --rm \
"$IMAGE" sh -c ' "$IMAGE" sh -c '
mkdir -p /tmp/home mkdir -p /tmp/home
python3 /usr/local/lib/opencode-devbox/generate-config.py 2>/dev/null python3 /usr/local/lib/opencode-devbox/generate-config.py 2>/dev/null
cat /tmp/home/.config/opencode/opencode.json cat /tmp/home/.config/opencode/opencode.jsonc
' > "$tmp/out.json" 2>/dev/null; then ' > "$tmp/out.jsonc" 2>/dev/null; then
# Strip single-line // comments for JSON validation
sed 's|//.*$||' "$tmp/out.jsonc" > "$tmp/out.json"
if python3 -c " if python3 -c "
import json, sys import json, sys
c = json.load(open('$tmp/out.json')) c = json.load(open('$tmp/out.json'))
assert c['model'].startswith('anthropic/'), c assert c['model'].startswith('anthropic/'), c
assert c['autoupdate'] is False assert c['autoupdate'] is False
assert c['share'] == 'disabled' assert c['share'] == 'disabled'
assert 'context7' in c.get('mcp', {}), 'context7 MCP not registered'
" 2>&1; then " 2>&1; then
pass "$label" pass "$label"
else else
fail "$label: output doesn't match expected shape: $(cat "$tmp/out.json")" fail "$label: output doesn't match expected shape: $(cat "$tmp/out.jsonc")"
fi fi
else else
fail "$label: container failed: $(cat "$tmp/out.json")" fail "$label: container failed: $(cat "$tmp/out.jsonc")"
fi fi
# Config generation is idempotent — running twice must not overwrite. # Config generation is idempotent — running twice must not overwrite.
# Tests both legacy .json and new .jsonc detection.
label="generate-config never overwrites existing config" label="generate-config never overwrites existing config"
if docker run --rm \ if docker run --rm \
-e OPENCODE_PROVIDER=anthropic \ -e OPENCODE_PROVIDER=anthropic \