Add a Remote MCP Server to LibreChat: librechat.yaml, OAuth and Fixes
How to add a remote MCP server to LibreChat: the mcpServers block in librechat.yaml or the Add MCP form, why a missing type means SSE, per-user keys with customUserVars, OAuth sign-in, timeouts, private addresses, and fixing a server that will not connect.
An admin adds a remote MCP server to LibreChat as one entry under mcpServers in librechat.yaml [1]:
mcpServers:
my-server:
type: streamable-http
url: https://mcp.example.com/mcp
Restart LibreChat afterwards: servers in librechat.yaml are set up at startup, so a change to the file needs a restart [1]. If your role allows it, you can also add a server from the chat UI under MCP Settings, and it works at once [1][2].
Everything below is checked against LibreChat's documentation on 2 November 2026 [1][2].
TL;DR:
- Always write
type: streamable-http. Without atype, anhttps://URL is read as the older SSE transport [1]. - Each user can bring their own key through
customUserVars, entered in the UI and stored per user [1]. - OAuth works without a client ID: leave it out and LibreChat registers itself with the server [1].
timeoutis in milliseconds, default 60000. Connecting has its owninitTimeout, default 30000 [1].
Add the server in librechat.yaml
A fuller entry, with the fields you are most likely to need [1]:
mcpServers:
my-server:
type: streamable-http
url: https://mcp.example.com/mcp
headers:
Authorization: "Bearer ${MY_SERVER_TOKEN}"
X-User-ID: "{{LIBRECHAT_USER_ID}}"
timeout: 120000
serverInstructions: true
| Field | What it does [1] |
|---|---|
type |
streamable-http (or its alias http), sse, or websocket |
url |
The MCP endpoint; https:// for HTTP transports, wss:// for websocket |
headers |
Sent with every request; takes ${ENV_VAR} and {{LIBRECHAT_USER_*}} placeholders |
timeout |
Milliseconds per request, tool calls included; default 60000 |
initTimeout |
Milliseconds to connect; default 30000 |
serverInstructions |
true passes the server's own instructions to the model |
startup |
false skips connecting when LibreChat starts |
chatMenu |
false hides it from the chat composer; agents can still use it |
${MY_SERVER_TOKEN} comes from the LibreChat server's environment, so the key lives in your .env, not in the YAML [1]. {{LIBRECHAT_USER_ID}} is filled with the signed-in user's ID, which lets the MCP server tell your users apart [1].
Why the type field matters
LibreChat infers the transport when type is missing, and it infers the old one: an http:// or https:// URL becomes sse, a ws:// or wss:// URL becomes websocket [1]. A server that only speaks Streamable HTTP then fails to connect even though the URL is right. Writing type: streamable-http removes the guess.
Let each user bring their own key
When every user has their own account on the MCP server, declare the key as a user variable and put it in a header [1]:
mcpServers:
my-server:
type: streamable-http
url: https://mcp.example.com/mcp
headers:
Authorization: "Bearer {{MY_SERVER_API_KEY}}"
customUserVars:
MY_SERVER_API_KEY:
title: "My Server API key"
description: "Create one under Settings, API keys in My Server"
Each variable needs a title and a description [1]. Users enter the value the first time they connect, can change it later from Configure in the chat composer or in MCP Settings, and it is stored per user and per server [1].
Sign in to a server that needs it
Every oauth subkey is optional. With no client_id and client_secret, LibreChat uses Dynamic Client Registration [1]:
mcpServers:
my-server:
type: streamable-http
url: https://mcp.example.com/mcp
oauth:
scope: "read write"
For a server that wants a pre-registered client, add client_id, client_secret, and if needed authorization_url, token_url and redirect_uri [1]. LibreChat detects sign-in on its own; set requiresOAuth: false for a server protected by a fixed Authorization header [1].
What the user sees: a Connect dialog with Continue with OAuth, which opens the server's sign-in page in a new tab. After approving, the server shows Connected [2]. They have 10 minutes to finish unless the admin changes it [2]. Revoke on the server's card in MCP Settings drops the stored tokens [2]. MCP OAuth covers what a server has to publish for the sign-in to work.
Add the server from the UI
In MCP Settings in the side panel, click + ("Add MCP") [2]. The form asks for a name, the MCP Server URL, the transport (Streamable HTTPS or SSE), and how it authenticates: auto-detect, API key or OAuth [2]. Tick "I trust this application" and click Create [2]. The interface.mcpServers setting decides who may create and share servers [2].
A server added this way can only reach a remote URL, and it cannot use the server's environment variables or the user placeholders [2]. Anything that needs ${ENV_VAR} or {{LIBRECHAT_USER_ID}} belongs in librechat.yaml.
To use the tools in a chat, open the composer's + menu, pick the server under MCP Servers, and it shows as a chip on the composer [2]. For an agent, add it from Tools in the Agent Builder [2]. The model has to support tool calls, or it never calls the server [2].
When it will not connect
| What you see | Usual cause | Fix |
|---|---|---|
| A known-good server fails to connect | No type, so LibreChat spoke SSE |
Add type: streamable-http |
| A change to the YAML does nothing | The file is read at startup | Restart LibreChat [1] |
A server on 192.168.x.x or host.docker.internal is refused |
Private addresses must be allowed explicitly [1] | Add it to mcpSettings.allowedAddresses [1] |
401 with a ${...} header |
The variable is not set where LibreChat runs | Add it to the server's environment and restart |
| The server stays on Needs Auth | Nobody has signed in yet | Click it and finish the OAuth sign-in [2] |
| A shared API-key server stuck on Needs Auth | Stale stored metadata | Edit and save the server once [1] |
| Long tool calls are cut off | A reverse proxy's timeout, or timeout |
Raise the proxy timeout and timeout [1] |
| The server's tools never get called | The model does not support tool calls | Switch to a model that does [2] |
| Two servers, one set of tools missing | Names that normalise to the same value | Rename one [1] |
For what the server's own error codes mean, see MCP server errors and MCP server connection failed.
Check it from outside before you share it
LibreChat calls the server from wherever LibreChat runs, so an address that works from your laptop can still fail from the LibreChat host. Our MCP connection test calls your server from our network, runs the handshake and tools/list, and reports what a stranger on the internet gets back, with a dated URL you can share. If it passes there and fails in LibreChat, look at the YAML and the address rules first.
The same setup in other clients is in OpenCode, Warp, Claude Desktop, ChatGPT, LM Studio, Claude Code, Cursor, VS Code and Cline, and remote MCP server vs stdio covers whether your server should have a public address at all.