feat: support legacy streamable-http config entries
This commit is contained in:
parent
18d94d8913
commit
2708a6ff5f
|
|
@ -1,11 +1,14 @@
|
||||||
# Example NGINX front-end for MCP Browser
|
# Example NGINX front-end for MCP Browser
|
||||||
#
|
#
|
||||||
# Replace the placeholder values (domain, certificate paths, slug, upstream
|
# This template follows the MCP specification (2025-03-26) section 2.4 on dynamic
|
||||||
# ports) with values that match your deployment. This configuration exposes:
|
# client registration:
|
||||||
# * OAuth metadata + token endpoints implemented via an njs helper
|
# https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#2-4-dynamic-client-registration
|
||||||
# * An authenticated Streamable HTTP MCP endpoint
|
#
|
||||||
# * An unauthenticated debug endpoint (optional) that forwards to the
|
# Replace the placeholder values (domain, certificate paths, hash slug, upstream
|
||||||
# mcp-browser SSE bridge
|
# ports) with values that match your deployment. The configuration provides:
|
||||||
|
# * OAuth metadata + register/token endpoints backed by an njs helper
|
||||||
|
# * A protected Streamable HTTP MCP endpoint (auth_request + OAuth)
|
||||||
|
# * An optional unauthenticated SSE bridge for local debugging
|
||||||
#
|
#
|
||||||
# The example assumes that:
|
# The example assumes that:
|
||||||
# * An njs script lives at /etc/nginx/njs/mcp_oauth.js providing handlers
|
# * An njs script lives at /etc/nginx/njs/mcp_oauth.js providing handlers
|
||||||
|
|
@ -45,14 +48,17 @@ server {
|
||||||
|
|
||||||
add_header X-Robots-Tag "noindex, nofollow, noarchive" always;
|
add_header X-Robots-Tag "noindex, nofollow, noarchive" always;
|
||||||
|
|
||||||
# --- OAuth discovery + token endpoints (served by njs helper) -------------
|
# Resource identifiers MUST match what your metadata document returns.
|
||||||
# Replace __MCP_SLUG__ with the slug you publish in OAuth metadata.
|
# Use the same hash/digest in mcp_oauth.metadata().
|
||||||
location = /.well-known/oauth-authorization-server/__MCP_SLUG__/mcp {
|
set $mcp_resource "__MCP_RESOURCE_HASH__";
|
||||||
|
|
||||||
|
# --- OAuth discovery + token/register endpoints per §2.4 ------------------
|
||||||
|
location = /.well-known/oauth-authorization-server/$mcp_resource/mcp {
|
||||||
default_type application/json;
|
default_type application/json;
|
||||||
js_content mcp_oauth.metadata;
|
js_content mcp_oauth.metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
location = /.well-known/oauth-protected-resource/__MCP_SLUG__/mcp {
|
location = /.well-known/oauth-protected-resource/$mcp_resource/mcp {
|
||||||
default_type application/json;
|
default_type application/json;
|
||||||
js_content mcp_oauth.metadata;
|
js_content mcp_oauth.metadata;
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +83,16 @@ server {
|
||||||
js_content mcp_oauth.token;
|
js_content mcp_oauth.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The metadata served above should advertise this /authorize endpoint.
|
||||||
|
# Update the upstream target to whatever Authorization Server you use.
|
||||||
|
location = /authorize {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_pass https://idp.example.com/oauth2/authorize;
|
||||||
|
}
|
||||||
|
|
||||||
# Internal auth_request hook used by the protected MCP endpoint.
|
# Internal auth_request hook used by the protected MCP endpoint.
|
||||||
location = /_oauth_check {
|
location = /_oauth_check {
|
||||||
internal;
|
internal;
|
||||||
|
|
@ -85,7 +101,7 @@ server {
|
||||||
|
|
||||||
# --- Protected Streamable HTTP MCP endpoint --------------------------------
|
# --- Protected Streamable HTTP MCP endpoint --------------------------------
|
||||||
# Requires successful OAuth check before proxying to the upstream server.
|
# Requires successful OAuth check before proxying to the upstream server.
|
||||||
location ^~ /__MCP_SLUG__/mcp/ {
|
location ^~ /$mcp_resource/mcp/ {
|
||||||
auth_request /_oauth_check;
|
auth_request /_oauth_check;
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|
@ -109,7 +125,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Optional unauthenticated SSE bridge for local debugging ---------------
|
# --- Optional unauthenticated SSE bridge for local debugging ---------------
|
||||||
location ^~ /__MCP_SLUG__/mcp-browser/ {
|
location ^~ /$mcp_resource/mcp-browser/ {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Connection "";
|
proxy_set_header Connection "";
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,23 @@ class ConfigLoader:
|
||||||
servers = {}
|
servers = {}
|
||||||
for name, server_config in config_data.get("servers", {}).items():
|
for name, server_config in config_data.get("servers", {}).items():
|
||||||
transport_data = server_config.get("transport", {}) or {}
|
transport_data = server_config.get("transport", {}) or {}
|
||||||
|
|
||||||
|
# Merge transport metadata from legacy locations
|
||||||
|
raw_transport_type = (
|
||||||
|
transport_data.get("type")
|
||||||
|
or server_config.get("transportType")
|
||||||
|
or server_config.get("type")
|
||||||
|
)
|
||||||
|
normalized_type = "stdio"
|
||||||
|
if isinstance(raw_transport_type, str):
|
||||||
|
lowered = raw_transport_type.replace("_", "-").lower()
|
||||||
|
if lowered in {"streamable-http", "streamablehttp"}:
|
||||||
|
normalized_type = "streamable-http"
|
||||||
|
elif lowered in {"stdio", "standard"}:
|
||||||
|
normalized_type = "stdio"
|
||||||
|
else:
|
||||||
|
normalized_type = lowered
|
||||||
|
|
||||||
oauth_data = transport_data.get("oauth") or {}
|
oauth_data = transport_data.get("oauth") or {}
|
||||||
oauth_config = None
|
oauth_config = None
|
||||||
if oauth_data:
|
if oauth_data:
|
||||||
|
|
@ -121,12 +138,43 @@ class ConfigLoader:
|
||||||
extra_params=oauth_data.get("extra_params") or oauth_data.get("extraParams", {}),
|
extra_params=oauth_data.get("extra_params") or oauth_data.get("extraParams", {}),
|
||||||
access_token=oauth_data.get("access_token") or oauth_data.get("accessToken"),
|
access_token=oauth_data.get("access_token") or oauth_data.get("accessToken"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
transport_url = transport_data.get("url") or server_config.get("url")
|
||||||
|
headers = transport_data.get("headers") or server_config.get("headers") or {}
|
||||||
|
timeout = (
|
||||||
|
transport_data.get("timeout")
|
||||||
|
or server_config.get("timeout")
|
||||||
|
or 30.0
|
||||||
|
)
|
||||||
|
sse_timeout = (
|
||||||
|
transport_data.get("sse_timeout")
|
||||||
|
or transport_data.get("sseTimeout")
|
||||||
|
or server_config.get("sse_timeout")
|
||||||
|
or server_config.get("sseTimeout")
|
||||||
|
or 300.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Legacy args: ["url", "http://..."] or ["--url=http://..."]
|
||||||
|
args = server_config.get("args", [])
|
||||||
|
if not transport_url and isinstance(args, list):
|
||||||
|
for idx, arg in enumerate(args):
|
||||||
|
if not isinstance(arg, str):
|
||||||
|
continue
|
||||||
|
stripped = arg.strip()
|
||||||
|
if stripped in {"url", "--url", "--transport-url"}:
|
||||||
|
if idx + 1 < len(args):
|
||||||
|
transport_url = args[idx + 1]
|
||||||
|
break
|
||||||
|
elif stripped.startswith(("url=", "--url=", "--transport-url=")):
|
||||||
|
transport_url = stripped.split("=", 1)[1]
|
||||||
|
break
|
||||||
|
|
||||||
transport_config = TransportConfig(
|
transport_config = TransportConfig(
|
||||||
type=transport_data.get("type", "stdio"),
|
type=normalized_type,
|
||||||
url=transport_data.get("url"),
|
url=transport_url,
|
||||||
headers=transport_data.get("headers", {}),
|
headers=headers,
|
||||||
timeout=transport_data.get("timeout", 30.0),
|
timeout=timeout,
|
||||||
sse_timeout=transport_data.get("sse_timeout") or transport_data.get("sseTimeout", 300.0),
|
sse_timeout=sse_timeout,
|
||||||
oauth=oauth_config
|
oauth=oauth_config
|
||||||
)
|
)
|
||||||
servers[name] = MCPServerConfig(
|
servers[name] = MCPServerConfig(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Expose MCP Browser via HTTP bridge
|
Description=Run mcp-browser in MCP server mode
|
||||||
Documentation=https://github.com/Xilope0/mcp-browser
|
Documentation=https://github.com/Xilope0/mcp-browser
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
@ -7,20 +7,33 @@ Wants=network-online.target
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
Environment="PYTHONUNBUFFERED=1"
|
Environment="PYTHONUNBUFFERED=1"
|
||||||
Environment="MCP_PROXY_BIN=%h/.local/bin/mcp-proxy"
|
Environment="MCP_BROWSER_BIN=%h/.local/bin/mcp-browser"
|
||||||
Environment="MCP_PROXY_ALLOW_ORIGIN=https://platform.openai.com"
|
Environment="MCP_BROWSER_CONFIG=%h/.config/mcp-browser/config.yaml"
|
||||||
Environment="MCP_PROXY_PORT=14001"
|
Environment="MCP_BROWSER_SERVER=default"
|
||||||
Environment="MCP_PROXY_CONFIG=%h/.config/mcp-browser/proxy.yaml"
|
Environment="MCP_BROWSER_MODE=server"
|
||||||
Environment="MCP_PROXY_EXTRA_ARGS="
|
Environment="MCP_BROWSER_NO_BUILTIN=false"
|
||||||
EnvironmentFile=-%h/.config/mcp-browser/proxy.env
|
Environment="MCP_BROWSER_TRANSPORT="
|
||||||
|
Environment="MCP_BROWSER_TRANSPORT_URL="
|
||||||
|
Environment="MCP_BROWSER_EXTRA_ARGS="
|
||||||
|
EnvironmentFile=-%h/.config/mcp-browser/browser.env
|
||||||
|
|
||||||
ExecStart=/usr/bin/env sh -c '\
|
ExecStart=/usr/bin/env bash -lc 'set -eu
|
||||||
set -eu; \
|
ARGS=()
|
||||||
exec "$MCP_PROXY_BIN" \
|
if [[ "$MCP_BROWSER_NO_BUILTIN" == "true" ]]; then
|
||||||
--allow-origin "$MCP_PROXY_ALLOW_ORIGIN" \
|
ARGS+=(--no-builtin)
|
||||||
--port "$MCP_PROXY_PORT" \
|
fi
|
||||||
--named-server-config "$MCP_PROXY_CONFIG" \
|
if [[ -n "$MCP_BROWSER_TRANSPORT" ]]; then
|
||||||
$MCP_PROXY_EXTRA_ARGS'
|
ARGS+=(--transport "$MCP_BROWSER_TRANSPORT")
|
||||||
|
fi
|
||||||
|
if [[ -n "$MCP_BROWSER_TRANSPORT_URL" ]]; then
|
||||||
|
ARGS+=(--transport-url "$MCP_BROWSER_TRANSPORT_URL")
|
||||||
|
fi
|
||||||
|
exec "$MCP_BROWSER_BIN" \
|
||||||
|
--mode "$MCP_BROWSER_MODE" \
|
||||||
|
--config "$MCP_BROWSER_CONFIG" \
|
||||||
|
--server "$MCP_BROWSER_SERVER" \
|
||||||
|
"${ARGS[@]}" \
|
||||||
|
$MCP_BROWSER_EXTRA_ARGS'
|
||||||
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue