Claude Desktop Developer Mode: Configure a Custom API Endpoint
TL;DR: anthropic_base_url is not a Claude Desktop config key. Support is via Developer Mode third-party inference (inferenceGatewayBaseUrl + inferenceGatewayApiKey). Config tutorial below.
Where does the authentication key go in `claude_desktop_config.json`? Inside the env object of the individual MCP server entry that the key authenticates — not at the top level of the file. The documented schema of that file has one top-level key, mcpServers. There is no file-level API-key field, and no field in this file changes which API host Claude Desktop sends inference requests to.
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "your-brave-api-key"
}
}
}
}Each server carries its own env object, sitting next to command and args, inside that server's own entry. Two servers that need different credentials never share one, and a key scoped to one server is not exposed to the others. That structure is the one in the official MCP documentation for local servers.
To point the whole application at a different API host, this file is not the mechanism. Claude Desktop's documented route for third-party inference is Help → Troubleshooting → Enable Developer Mode, then Developer → Configure Third-Party Inference…. That window writes managed configuration (inferenceProvider, inferenceGatewayBaseUrl, inferenceGatewayApiKey), not claude_desktop_config.json.
The rest of this page is the long version of those two answers: the exact click path, the keys involved, what your gateway has to implement, and what to do if you followed older instructions that put an API host in the config file.
Table of Contents
What Changed on This Page
TL;DR: You change Claude Desktop’s API endpoint in Developer Mode (Help → Troubleshooting → Configure Third-Party Inference), not by editing claude_desktop_config.json — that file configures MCP servers only.
Earlier versions of this page, and a number of posts that copied it, described changing Claude Desktop's API endpoint by adding a top-level env object to claude_desktop_config.json, naming a gateway host and an API key.
That is not how the client works. Nothing in the official documentation for claude_desktop_config.json defines a file-level env object or an API-host key; the file is the MCP server registry. Instructing readers to add a key that the application never reads produces a config that looks correct, validates as JSON, and changes nothing — which is the worst kind of setup bug, because the failure is silent.
The corrected procedure is below. If you are here because that older advice did not work for you, that is the reason, and If You Followed the Older Instructions cleans it up.
TL;DRTL;DR: claude_desktop_config.json configures MCP servers only — there is no authentication key field in it. Your API key is entered once inside Developer Mode, not in the JSON file.
The Two Configuration Surfaces
TL;DR — claude_desktop_config.json never holds your API authentication key — it only registers MCP servers. Keys go in Developer Mode's third-party inference window, under the gateway provider entry.
Claude Desktop reads two unrelated configuration surfaces, and almost every confusing guide on this topic comes from mixing them up.
`claude_desktop_config.json` — MCP only. This file lists the local tool servers Claude can launch. Its path is ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. It is what the Developer-tab Edit Config button opens. Keys live inside each server entry, as shown at the top of this page.
Managed preferences and `Claude-3p/configLibrary/` — inference and app policy. Third-party inference settings live in OS-managed preference storage, or in the local configuration library that the in-app window writes:
macOS, managed:
/Library/Managed Preferences/<user>/com.anthropic.claudefordesktop.plistWindows, managed:
HKLM\SOFTWARE\Policies\Claude(machine) orHKCU\SOFTWARE\Policies\Claude(user)Linux, managed:
/etc/claude-desktop/managed-settings.jsonmacOS, local:
~/Library/Application Support/Claude-3p/configLibrary/Windows, local:
%LOCALAPPDATA%\Claude-3p\configLibrary\Linux, local:
~/.config/Claude-3p/configLibrary/
Two rules follow from that table. A managed source wins over locally written values, and on Windows the two policy hives are not merged: machine policy under HKLM causes the app to ignore HKCU entirely. Configuration is read at launch, so a change takes effect after a full quit and relaunch, not after closing the window.
Do not add third-party inference keys to `claude_desktop_config.json`. Putting inferenceProvider and inferenceGatewayBaseUrl into that file repeats the original mistake in a new spelling: it is still a key the file's schema does not define, and the client still will not read it.
Enable Developer Mode and Open the Third-Party Inference Window
TL;DR — Enable Developer Mode from the application menu (☰ on Windows, app menu on macOS), then open Help → Troubleshooting → the third-party inference window to enter gateway settings.
Three steps, in the order the application expects them.
Step 1 — enable Developer Mode. Open the application menu — the menu bar on macOS, or the ☰ menu at the top-left of the sign-in screen on Windows — and go to Help → Troubleshooting → Enable Developer Mode.
Step 2 — open the inference window. Choose Developer → Configure Third-Party Inference….
Step 3 — fill in Connection and apply. Set the inference provider to Gateway, enter the base URL and credential, then use Apply Changes to write the configuration to this device and relaunch into it. If you are deploying to a fleet rather than one machine, the same window's Export menu produces a .mobileconfig profile for macOS MDM, a .reg policy file for Windows, an ADMX template, a plain JSON config, or an egress allowlist for your network team.
Anthropic recommends the in-app window over hand-editing: it validates values as you type, shows which fields your chosen provider requires, tests the connection against your endpoint, and derives the network egress allowlist from your settings. That connection test is the closest thing to a pre-flight check you get before the client itself tries to use the gateway.
If a managed profile is already deployed on the machine, the window opens read-only and shows the deployed values. Author new configurations on a device without one.
TL;DRTL;DR: paste the gateway base URL and your API key into the Developer Mode inference window; the key is never stored in claude_desktop_config.json.
Fill In the Connection Settings
TL;DR — Three fields decide the connection: inferenceProvider = gateway, the custom base URL, and your provider's API key in the auth field. Save once — configuration applies at next launch.
These are the settings behind the window, as named in Anthropic's configuration reference:
`inferenceProvider`: set to
gateway. This selects a self-hosted gateway, such as LiteLLM, Portkey, or your own proxy, as the inference provider.`inferenceGatewayBaseUrl`: the full URL of your gateway endpoint. Available from Claude Desktop 1.2581.0.
`inferenceGatewayApiKey`: the API key for that gateway. Also from 1.2581.0.
`inferenceGatewayAuthScheme`: how the credential goes on the wire, either
bearer(the default) orx-api-key. Added in 1.3036.0. Set it only if your gateway accepts one header and not the other.`inferenceModels`: an explicit model list. Use it when your gateway does not implement
GET /v1/models, or when you want to control the picker order and labels. The first entry becomes the default.`inferenceStreamIdleTimeoutSec`: extra seconds to wait for model output on a streaming response that is currently sending only keep-alive pings. Default 300, range 300–1800, gateway provider only. Raise it if a slow upstream sends pings for minutes before the first token.
When you author policy by hand instead of exporting from the window, note that every value is written as a string in the OS preference store, including booleans and arrays. On Linux the managed file is real JSON and takes native types; on macOS and Windows an array such as inferenceModels is a single key whose value is a JSON document encoded as a string.
What Your Gateway Must Implement
This is the part that decides whether a given provider can work at all, and it is not negotiable:
Required:
POST /v1/messagesimplementing the Anthropic Messages API, including streaming and tool use.Optional:
GET /v1/models. If your gateway implements it, Claude Desktop auto-discovers the available models. If not, list them ininferenceModels.
Prompt caching is a strong recommendation rather than a requirement: Cowork and Code sessions send cache_control breakpoints with every turn, and a gateway that forwards those fields keeps the cache hits. A gateway that strips them, or that changes the system prompt or tool list between turns, makes the upstream reprocess the whole conversation every turn at full input-token cost. The check is in the usage numbers your gateway returns or logs: after the first request of a session, cache_read_input_tokens should be well above zero on most requests. If it is zero every time, look at the gateway's request transformation for that route.
This contract is also the fastest way to filter a provider. A service that only speaks the OpenAI chat-completions format is not a drop-in gateway for Claude Desktop, no matter how many models it lists.
Which Base URL to Enter
TL;DR — Enter your gateway's Anthropic-compatible endpoint as the custom api base url — the same value Claude Code users set as ANTHROPIC_BASE_URL, but entered in Developer Mode, not an env var.
Anthropic's own documentation shows two different forms, so this is worth stating carefully.
The in-app configuration table in the gateway guide shows a bare host: https://llm-gateway.example.corp. The Linux managed-settings example in the configuration reference shows a path suffix: https://gateway.example.com/v1.
Both appear in official material, and we have not verified the handshake in a real Claude Desktop installation, so this page does not claim that one form is required or that the other is wrong. What is certain is the endpoint the request has to reach: the client must end up sending POST /v1/messages to your gateway.
That gives you a concrete way to choose. Take the base URL form your gateway documents, and check that the client's final request path lands on /v1/messages. On our own endpoint the difference is observable: POST https://api.codegateway.dev/messages returns 404 Not found, while POST https://api.codegateway.dev/v1/messages returns 200. CodeGateway's own setup page recommends the host-only form, https://api.codegateway.dev, with no /v1 suffix. If your gateway's documentation says otherwise, follow your gateway — and if you are unsure, the in-app window's connection test tells you before you commit the change.
TL;DRTL;DR: send one test prompt and confirm your gateway log shows the Authorization header; if not, re-open Help → Troubleshooting and re-apply the key.
Verify the Round Trip
TL;DR: Send a test message in Claude Desktop and check your gateway logs for the request. If nothing arrives, re-check the endpoint URL and restart the app.
TL;DR — Send one message and watch your gateway's usage log. A request there proves the client is talking to your gateway; silence means the config applies only after a full restart.
Send one message in Claude Desktop and confirm a request appears in your gateway's usage log. That single check separates "the client is talking to the gateway" from "the client is still talking to Anthropic".
You can also test the gateway side directly, without the desktop client. This request was run against the endpoint shown; the response below is the real one, trimmed to the fields that matter here:
curl -s https://api.codegateway.dev/v1/messages \
-H "x-api-key: $CODEGATEWAY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":16,"messages":[{"role":"user","content":"Reply with exactly: ok"}]}'{"type":"message","model":"claude-haiku-4-5-20251001","stop_reason":"end_turn","content":[{"type":"text","text":"ok"}],"usage":{"input_tokens":12,"output_tokens":4}}A "type":"message" response means the path is live. 401 means the key is wrong or the auth scheme does not match what your gateway expects. A 404 means the base URL and the path the client appends do not line up — see the previous section.
One timing note worth knowing before you conclude something is broken. The first request after a restart can be much slower than the ones that follow. On our own endpoint, with claude-haiku-4-5, a cold first call took 22.2 seconds, the next streaming call 5.7 seconds, and a forced tool call 5.9 seconds. A gateway that looks hung on the first message is often just cold; send a second one before you start editing configuration.
One Working Implementation: CodeGateway
CodeGateway is one gateway that satisfies the contract above. It is not the only one, and any gateway implementing the Anthropic Messages API is configured the same way — the steps in this article do not change from provider to provider.
We tested the four requirements against the live endpoint on 2026-09-29, using claude-haiku-4-5 with max_tokens of 16, 16, and 64:
`POST /v1/messages`: HTTP 200,
type=message,stop_reason=end_turn,usageof 12 input and 4 output tokens.Streaming: HTTP 200 with a complete SSE sequence —
message_start,content_block_start, fivecontent_block_deltaevents,content_block_stop,message_delta,message_stop, plus aping.Tool use: HTTP 200 with a forced
tool_choice, returningstop_reason=tool_useand atool_useblock carrying{"city":"Tokyo"}as its input.Authentication: both
x-api-keyandAuthorization: Bearerare accepted, so the defaultbearerscheme works andx-api-keyworks too.
GET /v1/models is implemented as well, which means model discovery works and inferenceModels is optional. In discovery mode Claude Desktop keeps the ids that look like Claude models, so the claude-* entries in the catalog appear in the picker; the Claude Desktop setup guide covers how to replace that with an explicit lineup, order the picker, and declare 1M-context models correctly.
An example of the same settings in the managed-file shape, for a gateway that only accepts the x-api-key header:
{
"inferenceProvider": "gateway",
"inferenceGatewayBaseUrl": "https://api.codegateway.dev",
"inferenceGatewayApiKey": "sk-cg-...",
"inferenceGatewayAuthScheme": "x-api-key"
}Author this from the in-app window unless you are deploying by MDM. On Linux the file is /etc/claude-desktop/managed-settings.json and must be a regular file, owned by root, and not group- or world-writable; a file that fails those checks is rejected entirely, and the app then treats the device as managed but unreadable, which also disables local settings until it is fixed.
CodeGateway is an independent product. It is not affiliated with, endorsed by, or sponsored by Anthropic. Pricing for the gateway side lives on the pricing page, and how markup tiers work explains how usage is billed.
If you do not have an official Anthropic key yet, or you would rather not bind a foreign card for one, CodeGateway issues a key that already speaks the contract described above. Create a pay-as-you-go key, paste it into the Configure Third-Party Inference window as inferenceGatewayApiKey, and set inferenceGatewayBaseUrl to your gateway host — no separate client to install and no subscription to start. Usage is billed per token, so an evaluation costs cents rather than a monthly commitment. Register at CodeGateway, and the key is waiting on the first screen of your dashboard. Current per-model rates are listed on the API pricing page.
claude_desktop_config.json authentication key: where it goes
claude_desktop_config.json has no top-level authentication key field. The key belongs in the env object of the mcpServers entry it authenticates; the app itself only receives a key through Developer Mode → Configure Third-Party Inference.
{
"mcpServers": {
"your-server": {
"command": "npx",
"args": ["-y", "your-mcp-server"],
"env": { "API_KEY": "sk-..." }
}
}
}Official key path: create the key in the Anthropic Console (console.anthropic.com → API keys). Claude Desktop does not read that key from claude_desktop_config.json. To point the whole app at another host, use the third-party inference settings instead: inferenceGatewayBaseUrl plus inferenceGatewayApiKey.
ANTHROPIC_BASE_URL is not a Claude Desktop setting either — it is the Claude Code CLI environment variable. Claude Desktop changes hosts through third-party inference mode, exactly as the configuration walkthrough above shows.
No official Anthropic key, or no foreign card to bind? Create a CodeGateway key and paste it into the third-party inference window — the step-by-step route is on this page.
MCP Servers Alongside a Gateway
TL;DR: On Windows the config file is %APPDATA%\Claude\claude_desktop_config.json. Edit it before launching Claude Desktop; it configures MCP servers only — API endpoint changes use Developer Mode.
The two surfaces are independent, which is the practical reason not to merge them. MCP tool calls go through local process communication between Claude Desktop and the server it launched. Inference goes over the network to your gateway. Nothing about pointing inference at a gateway changes how MCP servers authenticate, and nothing about an MCP server's credentials changes where inference goes.
A file that does both, correctly, looks like this:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/yourname/projects"]
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "your-brave-api-key"
}
}
}
}Note what is not in that file: no env at the top level, no API host, no gateway key. The gateway settings live in the third-party inference configuration described above.
Claude Code Uses a Different Mechanism
TL;DR: The environment-variable method injects the API endpoint at the process level. Prefer Developer Mode’s Configure Third-Party Inference UI for most setups.
TL;DR — ANTHROPIC_BASE_URL is a Claude Code environment variable, not a Claude Desktop setting. In Claude Desktop the custom api base url is entered in Developer Mode's gateway window instead.
ANTHROPIC_BASE_URL is a real, documented environment variable — for Claude Code, Anthropic's command-line tool, which is a different product from Claude Desktop. Setting it in your shell is the supported way to point the CLI at a gateway:
export ANTHROPIC_BASE_URL="https://api.codegateway.dev"
export ANTHROPIC_API_KEY="sk-cg-..."
claude --print "hello"That variable has nothing to do with Claude Desktop's configuration file. If you have seen the two described together, that is the source of most of the confusion on this topic: the CLI reads environment variables, and the desktop client reads managed preferences. Our Claude Code one-liner setup covers the CLI path in full.
TL;DRTL;DR: older guides telling you to add an apiKey / authentication key to claude_desktop_config.json are wrong — that field does nothing; use Developer Mode instead.
If your coding agent ignores the project rules, start with the instruction chain: AGENTS.md not loading? Lookup order & 32 KiB limit explains why AGENTS.md loads in the wrong order or silently drops files.
If You Followed the Older Instructions
If you previously gave claude_desktop_config.json a top-level env object pointing at a gateway host, with an API key next to it:
{
"mcpServers": {},
"env": {
"YOUR_GATEWAY_HOST_VARIABLE": "https://some-gateway.example.com/v1",
"YOUR_GATEWAY_KEY_VARIABLE": "your-key"
}
}nothing was reading it. Remove that top-level env block, keep any env objects that sit inside individual mcpServers entries, and configure inference through the third-party inference window instead. Two details are easy to get wrong in the cleanup: the top-level env and a per-server env look identical at a glance but behave completely differently, and leaving the old block in place does no harm beyond confusion, so there is no reason to rush the edit on a machine you depend on.
Also note that a file-level env block was never an alternative way to set MCP credentials. If a guide told you to put an API key there and have all your MCP servers read it, the servers were not receiving it.
Troubleshooting
TL;DR — Configuration is read at launch — quit Claude Desktop fully and reopen after every edit. If the settings window shows saved but nothing changed, restart first, then re-check base URL and key.
The window says the configuration was applied but nothing changed. Configuration is read at launch. Quit the application fully — on macOS from the menu bar, on Windows from the system tray — and reopen it. Closing the window is not enough on either platform.
A managed profile is present and the window is read-only. That is expected: managed values win. Edit the profile through your MDM, or test on a device without one.
The connection test fails on Linux. Check the file's ownership and permissions first. /etc/claude-desktop/managed-settings.json must be owned by root and neither group- nor world-writable, and /etc/claude-desktop must be a real directory rather than a symlink. A rejected file applies none of its settings and logs the reason to main.log in the app's logs directory, alongside any key that fails schema validation. Start there rather than re-entering values.
The first message hangs for a long time. See the timing note above; cold starts are real. If it happens on every streaming response rather than once per launch, look at inferenceStreamIdleTimeoutSec and at whether your gateway emits keep-alive pings while the upstream model is silent.
Streaming works but tool calls fail. Your gateway is not implementing the full contract. Tool use is a hard requirement, not a nice-to-have: an agent loop that never receives a tool_use block stops being an agent.
FAQ
Can I use Claude Desktop with a third-party API and skip an Anthropic subscription?
Yes — that is exactly what the gateway provider mode is for. Anthropic documents it for self-hosted gateways such as LiteLLM, Portkey, or an in-house proxy, and the client is configured only with a base URL and a credential. What you cannot skip is the interface: the gateway must implement the Anthropic Messages API, with POST /v1/messages, streaming, and tool use. A gateway that speaks only the OpenAI format needs a translation layer in front of it. Your account and billing relationship for inference move to whoever operates the gateway; the desktop application itself is still Anthropic's client.
Where does the configuration go — `claude_desktop_config.json` or somewhere else?
Different settings, different containers. claude_desktop_config.json holds the MCP server list, and each server's authentication key goes in that server's own env object. Third-party inference settings — inferenceProvider, inferenceGatewayBaseUrl, inferenceGatewayApiKey — go in OS-managed preferences (a .mobileconfig profile on macOS, registry policy on Windows, /etc/claude-desktop/managed-settings.json on Linux) or in the local Claude-3p/configLibrary/ directory that the in-app window writes to. There is no file-level API key field in claude_desktop_config.json, and no inference key belongs in it. When a managed source exists, it wins over the local one.
How does this relate to MCP?
They are separate systems that happen to live in the same application. MCP is how Claude Desktop launches and talks to local tool servers; the inference gateway is where model requests go. Changing one does not change the other. The one real interaction is a file-level one: both are configured on the same machine, and the MCP file's name sounds like it should hold API settings, which is why so many guides put gateway keys in the wrong place. Keep MCP keys inside their server entries and inference settings inside the third-party inference configuration, and the two never collide.
Q: Does claude_desktop_config.json support an authentication key or apiKey field? No. claude_desktop_config.json only lists MCP servers. Authentication for a third-party endpoint is entered in Developer Mode (Help → Troubleshooting → Developer Mode) and stored in the app's local settings, not the JSON file.
Related Resources
Claude Desktop with CodeGateway — the full setup page, including the model picker lineup and 1M-context declarations
Claude Code one-liner setup — the CLI path, where the API host is set by environment variable rather than by a config file
Error troubleshooting — 401, 404, 429, and 451 explained
Tiered pricing explained — how gateway usage is metered and billed
Claude Code vs Cursor vs GitHub Copilot — where the desktop client fits among the coding tools
Sources
Deploy Claude Desktop on 3P with an LLM gateway — provider keys, required Messages API surface, authentication options
Claude Desktop on 3P configuration reference — managed and local configuration locations, key reference, Linux managed file
In-app configuration — the Developer → Configure Third-Party Inference window and its exports
Connect to local MCP servers —
claude_desktop_config.jsonstructure and the per-serverenvexampleAnthropic Messages API — the interface a gateway has to implement
