Power your agent
คำสั่งของผู้เผยแพร่เอง ไม่ใช่เอนด์พอยต์ของ PlugMCP
Host a copy with our keys and logs.
npx -y [email protected]Claude Code ไม่มีลิงก์ติดตั้งสำหรับคำสั่งแบบโลคัล ให้คัดลอกคำสั่งด้านล่างแล้วรันในเทอร์มินัล
claude mcp add opencode-llm-proxy -- npx -y opencode-llm-proxy@1.13.0รันในเทอร์มินัล
{ "mcpServers": { "opencode-llm-proxy": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}claude_desktop_config.json
URL แบบรีโมตหรือคำสั่งบนเครื่องของคุณ? การติดตั้งสองแบบต่างกันอย่างไร
รันบน PlugMCP
A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.
เปิดopencode-llm-proxy is an OpenCode plugin that starts a local HTTP server on http://127.0.0.1:4010. It translates between the API format your tool speaks and whichever LLM provider OpenCode has configured — so you never reconfigure the same models twice.
Your tool (OpenAI / Anthropic / Gemini SDK, coding agent, etc.)
│
▼ http://127.0.0.1:4010
opencode-llm-proxy
│
▼ OpenCode SDK
GitHub Copilot · Anthropic · Gemini · Ollama · OpenRouter · Bedrock · …
Supported API formats — all with streaming and tool/function calling:
✨ Tool calling works with all four formats — including parallel tool calls. Point a coding agent (Claude Code, Cursor, Continue, Cline, your own agent loop, ...) at the proxy and its tools/tool_choice calls are translated through to whatever model OpenCode has configured, with a real tool_calls / tool_use / functionCall response handed back — one call or several in a single turn. See Tool calling.
See also: Security · Comparisons · All recipes
Most LLM tools speak exactly one API dialect. OpenCode already manages connections to every provider you use. This proxy bridges the two — your tools keep working as-is, and you change which model they use in one place.
Common situations it solves:
base_url to the proxy and use your Ollama model IDs directly.0.0.0.0 and give teammates the URL.npm install opencode-llm-proxy
Add to opencode.json:
{
"plugins": ["opencode-llm-proxy"]
}
This is the OpenCode V2 format. OpenCode V1 uses the singular key: "plugin": ["opencode-llm-proxy"]. See Compatibility.
Start OpenCode — the proxy starts automatically:
opencode
This package is an OpenCode plugin, not a standalone server. It intentionally has no npm start command; load it through OpenCode as shown above.
Send a request:
curl http://127.0.0.1:4010/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "github-copilot/claude-sonnet-4.6",
"messages": [{"role": "user", "content": "Hello!"}]
}'
npm install opencode-llm-proxy
Add to your global ~/.config/opencode/opencode.json (works everywhere) or a project-level opencode.json:
{
"plugins": ["opencode-llm-proxy"]
}
On OpenCode V1, use "plugin" instead of "plugins".
Global — loaded for every OpenCode session:
curl -o ~/.config/opencode/plugins/llm-proxy.js \
https://raw.githubusercontent.com/KochC/opencode-llm-proxy/main/dist/llm-proxy.js
Per-project — loaded only in this directory:
mkdir -p .opencode/plugins
curl -o .opencode/plugins/llm-proxy.js \
https://raw.githubusercontent.com/KochC/opencode-llm-proxy/main/dist/llm-proxy.js
The bundled file contains all proxy runtime modules. On OpenCode V1, tool calling also needs
mcp-tool-bridge.jsalongside it, so use the npm install method for tool-using clients there. On OpenCode V2 the bundled file supports tool calling on its own.
Use x-opencode-variant to select an OpenCode model variant for a request. The proxy accepts multimodal image, document, and file inputs in each API's native content shape, using embedded data URLs and validating model capabilities. Remote URLs are rejected unless the SSRF-safe remote-media fetcher is explicitly enabled; fetched content is converted to a data URL before it reaches OpenCode. Structured JSON output is supported through OpenAI response_format.json_schema, Responses API text.format.schema, and Gemini generationConfig.responseSchema.
Generation temperature, top-p (top_p/topP), and top-k (topK) values are validated and applied through the plugin's chat.params hook. Maximum-token fields (max_tokens, max_completion_tokens, max_output_tokens, and Gemini maxOutputTokens) are accepted where clients require them, but the current OpenCode SDK cannot enforce them. OpenAI and Anthropic requests reject unsupported controls (stop, seed, frequency_penalty, presence_penalty, logprobs, and n) with 400 instead of silently ignoring them.
OPENCODE_LLM_PROXY_HOST=0.0.0.0 \
OPENCODE_LLM_PROXY_TOKEN=my-secret \
opencode
The proxy supports real tool/function calling on all four API formats — OpenAI function tools (tools on /v1/chat/completions and /v1/responses), Anthropic tools (tools on /v1/messages), and Gemini function declarations (tools on :generateContent/:streamGenerateContent). This is what lets coding agents and other tool-using clients work through the proxy, not just plain chat.
curl http://127.0.0.1:4010/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "github-copilot/claude-sonnet-4.6",
"messages": [{"role": "user", "content": "What is the weather in NYC?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}]
}'
{
"choices": [{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_...",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"NYC\"}" }
}]
}
}]
}
Send the tool's result back on your next request (role: "tool" / tool_result / functionResponse, per your API's convention) alongside the full conversation history, same as any other multi-turn request — the proxy is stateless between calls either way.
When the model decides to call several tools at once, you get all of them back in a single response — a tool_calls array (OpenAI), multiple tool_use blocks (Anthropic), or multiple functionCall parts (Gemini), streaming or not. Ask a model for the weather in Paris and Tokyo and you'll get two fully-formed calls with their own IDs and arguments, ready to execute in parallel:
{
"choices": [{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{ "id": "call_1", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } },
{ "id": "call_2", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Tokyo\"}" } }
]
}
}]
}
OpenCode's own agent loop always executes tools itself, server-side, so there's no native concept of a "client-executed" tool call to hand off to. To bridge that gap, when a request includes tools:
OpenCode V2
px0_, so they never collide with OpenCode's own tools). Their executors run nothing.OpenCode V1
mcp-tool-bridge.js).tool_calls (OpenAI), tool_use (Anthropic), or functionCall parts (Gemini) — instead of a text answer.tool_choice: "none" (OpenAI/Gemini mode: "NONE"/Anthropic type: "none") disables tool calling for that request; forcing a specific named tool is supported.px_tools_0, px_tools_1, ...) rather than registered fresh per request, since OpenCode's server API has no endpoint to deregister an MCP server once added. Configure the pool size with OPENCODE_LLM_PROXY_TOOL_BRIDGE_POOL_SIZE (default 8) if you expect more than 8 concurrent in-flight tool-calling requests.OPENCODE_LLM_PROXY_TOOL_BRIDGE_MAX_QUEUE requests wait for a bridge slot. A request arriving when that queue is full receives 429; a queued request that exceeds the bridge acquisition timeout receives 503.node, so node must be on PATH wherever OpenCode is running.import OpenAI from "openai"
const client = new OpenAI({
baseURL: "http://127.0.0.1:4010/v1",
apiKey: "unused",
})
const response = await client.chat.completions.create({
model: "github-copilot/claude-sonnet-4.6",
messages: [{ role: "user", content: "Explain recursion." }],
})
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:4010/v1", api_key="unused")
response = client.chat.completions.create(
model="ollama/qwen2.5-coder",
messages=[{"role": "user", "content": "Write a Python function to reverse a string."}],
)
print(response.choices[0].message.content)
import anthropic
client = anthropic.Anthropic(
base_url="http://127.0.0.1:4010",
api_key="unused",
)
message = client.messages.create(
model="anthropic/claude-3-5-sonnet",
max_tokens=1024,
messages=[{"role": "user", "content": "What is the Pythagorean theorem?"}],
)
print(message.content[0].text)
import Anthropic from "@anthropic-ai/sdk"
const client = new Anthropic({
baseURL: "http://127.0.0.1:4010",
apiKey: "unused",
})
const message = await client.messages.create({
model: "anthropic/claude-opus-4",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain async/await." }],
})
import { GoogleGenerativeAI } from "@google/generative-ai"
const genAI = new GoogleGenerativeAI("unused", {
baseUrl: "http://127.0.0.1:4010",
})
const model = genAI.getGenerativeModel({ model: "google/gemini-2.0-flash" })
const result = await model.generateContent("What is machine learning?")
console.log(result.response.text())
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="anthropic/claude-3-5-sonnet",
openai_api_base="http://127.0.0.1:4010/v1",
openai_api_key="unused",
)
response = llm.invoke("What are the SOLID principles?")
print(response.content)
http://127.0.0.1:4010/v1OPENCODE_LLM_PROXY_TOKEN)Running Open WebUI in Docker? Use
http://host.docker.internal:4010/v1and setOPENCODE_LLM_PROXY_HOST=0.0.0.0.
The proxy lets n8n's native AI nodes use whatever models OpenCode already has authenticated access to — GitHub Copilot, Anthropic, Bedrock, local Ollama models, etc. — without configuring separate API keys in n8n at all. This works with n8n's regular LangChain-based Chat Model nodes, including real tool/function calling (e.g. an "AI Agent" node with a Tool attached) since Tool calling support was added.
OPENCODE_LLM_PROXY_HOST=0.0.0.0 \
OPENCODE_LLM_PROXY_TOKEN=some-long-random-token \
opencode
http://<opencode-host-ip>:4010/v1, API Key = your tokenhttp://<opencode-host-ip>:4010 (no /v1 — the node adds /v1/messages itself), API Key = your tokenGET /v1/models on the proxy, so it auto-populates with every model OpenCode has connected (github-copilot/claude-sonnet-5, anthropic/claude-3-5-sonnet, ollama/qwen2.5-coder, ...) — pick one directly, no manual typing needed.n8n running in Docker on a different machine on your LAN (a common setup)? Use that machine's actual LAN IP for
<opencode-host-ip>— notlocalhost/host.docker.internal, which only resolve to the OpenCode host if Docker is running on that same machine. Make sure your firewall allows incoming connections to theopencodebinary (macOS's Application Firewall in particular will silently drop connections from an app it hasn't been told to allow, even with the port open).
Settings → AI Provider → OpenAI API → set API Host to http://127.0.0.1:4010.
In ~/.continue/config.json:
{
"models": [
{
"title": "Claude via OpenCode",
"provider": "openai",
"model": "anthropic/claude-3-5-sonnet",
"apiBase": "http://127.0.0.1:4010/v1",
"apiKey": "unused"
}
]
}
In ~/.config/zed/settings.json:
{
"language_models": {
"openai": {
"api_url": "http://127.0.0.1:4010/v1",
"available_models": [
{
"name": "github-copilot/claude-sonnet-4.6",
"display_name": "Claude (OpenCode)",
"max_tokens": 8096
}
]
}
}
}
curl http://127.0.0.1:4010/v1/models | jq '.data[].id'
# "github-copilot/claude-sonnet-4.6"
# "anthropic/claude-3-5-sonnet"
# "ollama/qwen2.5-coder"
# ...
Use provider/model for clarity. Bare model IDs (e.g. gpt-4o) work if unambiguous across your providers.
To force a specific provider without changing the model string, add:
x-opencode-provider: anthropic
{ "healthy": true, "service": "opencode-openai-proxy" }
Returns all models from all configured providers in OpenAI list format.
When OPENCODE_LLM_PROXY_METRICS_ENABLED=true, returns Prometheus text exposition data. The endpoint uses the same bearer-token authentication as every other route and is not registered when disabled.
Metrics cover HTTP request counts and duration by bounded method/route/status labels, active and queued requests, upstream attempt outcomes, input/output token totals, and remote-media request outcomes, bytes, redirects, in-flight fetches, and duration. Streaming HTTP duration is recorded when the stream finishes, errors, or is cancelled.
OpenAI Chat Completions. Required: model, messages. Supported optional fields include stream, temperature, top_p, topK, max_tokens, max_completion_tokens, tools, tool_choice, response_format.json_schema, and compatible multimodal content parts. Maximum-token fields are accepted for client compatibility but are not enforceable.
OpenAI Responses API. Required: model, input. Supported optional fields include instructions, stream, temperature, top_p, topK, max_output_tokens, tools, tool_choice, text.format.schema, and compatible multimodal input items. max_output_tokens is accepted for client compatibility but is not enforceable.
Anthropic Messages API. Required: model, messages. Supported optional fields include system (string or an array of {type: "text", text: string} blocks), max_tokens, stream, temperature, top_p, topK, tools, tool_choice, and native image/document blocks. max_tokens is accepted for required Anthropic client compatibility but is not enforceable.
Errors are returned in Anthropic format: { "type": "error", "error": { "type": "...", "message": "..." } }.
Google Gemini non-streaming. Model name in URL path. Required: contents. Supported optional fields include systemInstruction, generationConfig (temperature, topP, topK, maxOutputTokens, and responseSchema), tools, toolConfig, and native inline/file media parts. maxOutputTokens is accepted but is not enforceable.
Same as above, returning a newline-delimited JSON stream. A tool-using turn may emit intermediate text chunks followed by a final chunk containing one or more functionCall parts.
Each request:
provider/model, bare model ID, or Gemini URL pathfileIndex, including media nested in tool resultsOPENCODE_LLM_PROXY_KEEP_SESSIONS=truectx.session.prompt; V1: client.session.prompt / client.session.promptAsync)Streaming uses OpenCode's event stream (V2: ctx.event.subscribe(); V1: client.event.subscribe()). Text deltas are forwarded in real time, and the upstream async iterator is explicitly closed on completion, error, cancellation, or early tool-call termination. If the event stream stops delivering, the turn still completes from the session's stored messages, and any text the stream missed is sent to streaming clients.
On OpenCode V2 the proxy session receives only your request: your system prompt replaces OpenCode's coding-agent prompt and instructions, and the session gets no OpenCode tools.
The package supports OpenCode V2 and V1 from one default export, { id, setup, server }: V2 calls setup (see the V2 plugin guide), V1 calls server.
"plugins" in opencode.json (or the bundled file under .opencode/plugins/). OpenCode V2 runs one plugin instance per project location in a single process; they share one proxy server, which keeps running until the last instance unloads."plugin". OpenCode V1 detects the descriptor (present in every release checked back to 1.15) and loads the plugin cleanly. On older builds the legacy loader probes every exported function, so you may see a harmless failed to load plugin ... is not a function line per worker in the startup log — the proxy still starts and serves normally.temperature, top-p (top_p/topP), and top-k (topK) are applied through OpenCode's plugin hook. Maximum-token controls are accepted for client compatibility but are not enforced.response_format / text.format / responseSchema) is requested through an instruction with the JSON Schema, and the reply is parsed as JSON; V2 has no native structured-output setting for sessions.MIT
Local AI gateway for OpenCode with tool/function calling — use any model via OpenAI, Anthropic, or Gemini API format
{ "mcpServers": { "opencode-llm-proxy": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}เครื่องมือ
ยังไม่มีรายการเครื่องมือ เซิร์ฟเวอร์แบบรีโมตจะได้รายการหลังการตรวจสอบสถานะครั้งแรก
FAQ
คัดลอกคอนฟิก stdio สำหรับ Cursor, Claude Desktop, Claude Code หรือ VS Code ได้ในหน้านี้ คอนฟิกนี้ใช้การติดตั้งของผู้เผยแพร่ ไม่ใช่พร็อกซีของ PlugMCP
ระเบียนนี้ไม่ได้ระบุตัวแปรสภาพแวดล้อมที่จำเป็น
Opencode Llm Proxy ทำงานแบบโลคัลผ่าน stdio
ตรวจสอบล่าสุดเมื่อ 2026-11-14 Local AI gateway for OpenCode with tool/function calling — use any model via OpenAI, Anthropic, or Gemini API format