MCPServer
Scope: namespaced · Modes: catalog (bundled, licensed) · external (free)
An MCPServer defines a single Model Context Protocol server that one or more ChatUIs can use. Define it once and reference it from any ChatUI via spec.mcpRefs — the operator wires it into LibreChat (the Agents endpoint) for you.
Spec
| Field | Type | Description |
|---|---|---|
mode | enum catalog | external (required) | Bundled server vs. user-managed endpoint |
catalog | string | Bundled server key (mode=catalog), e.g. websearch |
external | object | User-managed endpoint (mode=external) |
displayName | string | The server name shown in LibreChat (defaults to the catalog key or CR name) |
serverInstructions | string | Override the model-facing tool guidance |
external
| Field | Description |
|---|---|
url | The MCP endpoint (e.g. http://host:8080/mcp) |
type | Transport: streamable-http (default) or sse |
inCluster | Force SSRF-allowlist treatment. Omit to auto-detect from the host (service DNS / private IP) |
timeoutMs | Per-request timeout (default 60000) |
headersSecretRef | Same-namespace Secret whose keys become HTTP headers (injected via env, never written into the rendered config) |
oauth | OAuth 2.0 authentication to a protected MCP endpoint (licensed: mcp-oauth) — see OAuth authentication |
external.oauth (licensed: mcp-oauth)
Set exactly one of interactive or onBehalfOf (a validation rule enforces this). Without the mcp-oauth license the MCPServer is Refused (MCPOAuthUnlicensed) and a ChatUI referencing it stays unwired.
| Field | Description |
|---|---|
interactive | Per-user authorization-code + PKCE flow (each user authorizes once against the IdP) |
interactive.authorizationURL | IdP authorization endpoint. Optional — omit (with tokenURL) to let LibreChat auto-discover from the server's metadata |
interactive.tokenURL | IdP token endpoint (optional, see above) |
interactive.clientSecretRef | Same-namespace Secret holding the client ID (client-id) and, for confidential clients, the client secret (client-secret). Injected via env, referenced as ${…} — never inlined. Omit for a public/PKCE client |
interactive.scopes | Scopes requested from the IdP (space-joined) |
interactive.tokenExchangeMethod | default_post (client secret in body) or basic_auth |
onBehalfOf | Silent on-behalf-of token exchange of the user's SSO session (no prompt) |
onBehalfOf.scopes | Downstream scopes to request (required, non-empty), e.g. api://<client-id>/<permission> |
Modes
catalog(licensed:bundled-mcp-catalog) — the operator deploys the bundled server as one shared, ref-counted release for the whole cluster (innavique-mcp-system) and wires every referencing ChatUI to its in-cluster Service. Unlicensed (Community) ⇒ theMCPServeris Refused (no deploy), and a ChatUI referencing it simply waits. The first bundled server iswebsearch(enterprise web search: SearXNG + scraping + PII + reranking). Footprint is tuned cluster-wide viaPlatformConfig.spec.mcp(fulldefault, orminimal).external(free / Community) — points at an MCP endpoint you run yourself. In-cluster targets are auto-detected and get LibreChat's SSRF allowlist (mcpSettings) so private addresses are reachable.
SSRF allowlist (automatic)
LibreChat blocks MCP calls to private/in-cluster addresses unless they are allowlisted. The operator handles this: when any referenced server is in-cluster it renders a top-level mcpSettings block whose allowedDomains lists every referenced server's origin (a global allowlist — public servers must be listed too, or they would be blocked) and whose allowedAddresses exempts the in-cluster hosts. You don't configure this.
Example — bundled web search
apiVersion: core.navique.com/v1alpha1
kind: MCPServer
metadata:
name: websearch
namespace: forge
spec:
mode: catalog
catalog: websearch
---
apiVersion: core.navique.com/v1alpha1
kind: ChatUI
metadata:
name: forge-ui
namespace: forge
spec:
# … gateway/mongo/meili/secrets …
mcpRefs:
- { name: websearch }Example — external (in-cluster, with auth)
apiVersion: core.navique.com/v1alpha1
kind: MCPServer
metadata:
name: internal-docs
namespace: forge
spec:
mode: external
external:
url: http://docs-mcp.team.svc.cluster.local:8080/mcp
headersSecretRef: { name: docs-mcp-auth } # keys → HTTP headersOAuth authentication (licensed)
Licensed feature: mcp-oauth. Connect ChatUIs to MCP servers that require OAuth 2.0. Two modes — pick one per server:
- Interactive (authorization-code + PKCE). Each user authorizes once against the IdP (a one-time "OAuth Required" prompt in the chat menu); tokens are stored encrypted and auto-refreshed. Works with any provider. The client credentials come from a Secret and are never written into the rendered config. Because the IdP redirects the browser back to the UI, the ChatUI must be exposed via
spec.ingressso the callback resolves. - On-behalf-of (OBO). LibreChat silently exchanges the user's existing SSO session token for a downstream token — no prompt, no client secret. The ChatUI must have
spec.ssoconfigured (the token being exchanged is the SSO login). Best for Entra/OpenID-backed servers.
Example — interactive OAuth
apiVersion: core.navique.com/v1alpha1
kind: MCPServer
metadata:
name: salesforce
namespace: forge
spec:
mode: external
external:
url: https://api.salesforce.com/platform/mcp/v1/…
oauth:
interactive:
authorizationURL: https://login.salesforce.com/services/oauth2/authorize
tokenURL: https://login.salesforce.com/services/oauth2/token
scopes: [mcp_api, refresh_token]
clientSecretRef: { name: salesforce-mcp-oauth } # keys: client-id, client-secretExample — on-behalf-of (Entra)
apiVersion: core.navique.com/v1alpha1
kind: MCPServer
metadata:
name: graph
namespace: forge
spec:
mode: external
external:
url: https://mcp.example.com
oauth:
onBehalfOf:
scopes: ["api://<client-id>/Files.Read"]
# The referencing ChatUI must have spec.sso configured.Notes
- Referencing any MCP server auto-enables LibreChat's Agents endpoint (MCP tools are usable only through Agents).
- Native Web Search and Code Interpreter are turned off by the operator, and users (admins included) cannot add or disable MCP servers from the UI — only operator config defines them.
Status
{ phase, url (resolved endpoint), transport, inCluster, serverName, conditions, observedGeneration }. Short name mcp.