Put a third-party MCP server behind the platform
mcp-server-adapter is a sidecar for an MCP server whose code you do not control, such as an open source or vendor server. It reads the tool list of that server, serves it to the gateway as a manifest and forwards each call with the credential of the user who made it. One adapter serves one third-party server and one system.
The adapter does not turn a REST API into tools. It has no configuration file that describes endpoints. If your system has only a REST API, write a server from the template, see Write a server from the template.
What to expect
Section titled “What to expect”- Only tools classified
READ_ONLYwork. A tool that changes data stays hidden, because the tools of a third-party server name no resource that a write could be scoped to. The portal accepts only riskREAD_ONLYand actionreadfor an adapter. - The third-party server gets the credential of the calling user, never a shared one. Keep it on a network that only the adapter shares with it.
- Tools whose input schema cannot be bounded are skipped: open maps, unions of two types, recursion, lists without
items, depth above 8. The log lineevent=foreign_tool_skippedgives the reason. - Every error of the third-party server reaches the model as
not_found_or_denied, exceptcredential_required(HTTP 401) andupstream_unavailable. An error that the server returns as ordinary text reaches the model unchanged, so check how it reports errors. - The tool list is read at start. After a change, restart the adapter. The gateway pulls the new manifest within a minute and changed tools wait for approval again.
- There are no policies and no scope mapping for an adapter. Access is by the group
mcp-<system>-read.
Install the adapter
Section titled “Install the adapter”You need Docker Engine with Compose v2.20 or newer and 1 GiB of memory. The platform must reach this host on port 8443, and this host must reach https://<platform> on port 443.
-
In
deploy/mcp-adapter.env, fill in the four required values:Terminal window MCP_SERVER_ID=mcp-<system>MCP_GATEWAY_JWKS_URI=https://<platform>/.well-known/mcp-jwks.jsonMCP_CONNECT_URL=https://<platform>/connections?system={system}MCP_FOREIGN_URL=https://<third-party server><system>is the id the system has in the broker: 2 to 31 lower case letters and digits, starting with a letter. -
If the third-party server is not on the default Docker network, add its network under
mcp-adapterand undernetworks:incompose.yaml. No other server may reach it. -
Start the adapter:
Terminal window docker compose up -dThe adapter waits up to 90 seconds for the third-party server to answer
tools/listand exits when it does not. -
Read the certificate fingerprint:
Terminal window docker compose logs mcp-adapter | grep event=tls_certificateExpected:
event=tls_certificate source=generated fingerprint=sha256:... -
Give the platform administrator the address
https://<this host>:8443/mcpand the fingerprint. They add the system and the server, see Servers and Systems. For a product that takes the user’s own token, the system uses the broker adaptergeneric-rest, typeuser-secret, schemeBearer.
The adapter generates its certificate on first start and keeps it in the state volume. A new volume means a new fingerprint and a new approval; docker compose down -v deletes it.
Settings
Section titled “Settings”| Variable | Required | Description |
|---|---|---|
MCP_SERVER_ID |
yes | mcp-<system> |
MCP_GATEWAY_JWKS_URI |
yes | Key set of the gateway |
MCP_CONNECT_URL |
yes | Portal page where a user connects an account |
MCP_FOREIGN_URL |
yes | Address of the third-party server, https |
MCP_FOREIGN_PATH |
no | MCP path of the server, default /mcp |
MCP_FOREIGN_AUTHORIZATION_FORMAT |
no | How the credential becomes a header. Default Token {credential}; {credential} must appear exactly once |
MCP_FOREIGN_DISCOVERY_AUTHORIZATION |
no | Header for the startup tools/list, for servers that refuse a request without one |
MCP_ADAPTER_TOOLS_INCLUDE |
no | Tools to publish, comma-separated. Empty means all that can be bounded |
MCP_ADAPTER_STRIP_PREFIX |
no | Prefix to remove from tool names |
Own certificate, Redis for several instances and limits are in the same file and in src/main/resources/application.yml.
Example: mcp-atlassian in front of Jira
Section titled “Example: mcp-atlassian in front of Jira”The repository’s example puts sooperset/mcp-atlassian 0.23.1 (MIT) in front of Jira with four read tools. It runs on a test stack: the third-party server speaks plain http, which the adapter accepts only with the devstack profile. deploy/docker-compose.demo.yml has all settings.
-
Pull the image, pinned by digest:
Terminal window docker pull ghcr.io/sooperset/mcp-atlassian@sha256:5b7c9b64d4eb3210cab74be8bf3e6aeea9ed14f3042dc59ba5c5287bd4dbe466 -
Merge
deploy/docker-compose.demo.ymlinto your test stack and setADAPTER_IMAGEandMCP_GATEWAY_JWKS_URI. If the stack already runs a nativemcp-jira, stop it: the adapter takes its server id. -
Keep these settings of the third-party server:
ENABLED_TOOLS: jira_get_issue,jira_search,jira_get_all_projects,jira_get_transitionsJIRA_PERSONAL_TOKEN: placeholder-never-usedALLOW_GLOBAL_CRED_FALLBACK: "false"ENABLED_TOOLSlists read tools only. The token is a filler: without it the server does not list the Jira tools. With the fallback off, a call without a credential ends with 401. -
Keep these settings of the adapter:
MCP_FOREIGN_URL: http://mcp-atlassian:8000MCP_FOREIGN_ALLOW_PLAIN_HTTP: "true"MCP_FOREIGN_AUTHORIZATION_FORMAT: "Token {credential}"MCP_FOREIGN_DISCOVERY_AUTHORIZATION: "Token discovery-only"MCP_ADAPTER_STRIP_PREFIX: jira_ -
Start the stack with
docker compose up -d. -
In the portal, add the server
http://mcp-jira.internal:8443/mcpwith “allow plain http”, approve the connection and approve the four tools:get_issue,search,get_all_projectsandget_transitions.
The third-party container is the least trusted one in the stack. The fragment runs it read-only, without capabilities and with memory limits, on two internal networks (one shared with the adapter, one with Jira).
Common problems
Section titled “Common problems”| Symptom | Cause | Fix |
|---|---|---|
| The adapter exits right after start | The third-party server did not answer tools/list within 90 s, or it refuses requests without Authorization |
Check MCP_FOREIGN_URL and the network; in the second case set MCP_FOREIGN_DISCOVERY_AUTHORIZATION |
Server status certificate_changed |
The state volume was recreated |
Approve the new fingerprint in the portal |
| A tool is missing from the list | It is not approved, not READ_ONLY, or its schema cannot be bounded |
Check the log for event=foreign_tool_skipped |
| A tool changed after a new image of the third-party server | The tool list is read at start | Restart the adapter; the changed tools wait for approval again |
