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
|
||||
#
|
||||
# Replace the placeholder values (domain, certificate paths, slug, upstream
|
||||
# ports) with values that match your deployment. This configuration exposes:
|
||||
# * OAuth metadata + token endpoints implemented via an njs helper
|
||||
# * An authenticated Streamable HTTP MCP endpoint
|
||||
# * An unauthenticated debug endpoint (optional) that forwards to the
|
||||
# mcp-browser SSE bridge
|
||||
# This template follows the MCP specification (2025-03-26) section 2.4 on dynamic
|
||||
# client registration:
|
||||
# https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#2-4-dynamic-client-registration
|
||||
#
|
||||
# Replace the placeholder values (domain, certificate paths, hash slug, upstream
|
||||
# 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:
|
||||
# * 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;
|
||||
|
||||
# --- OAuth discovery + token endpoints (served by njs helper) -------------
|
||||
# Replace __MCP_SLUG__ with the slug you publish in OAuth metadata.
|
||||
location = /.well-known/oauth-authorization-server/__MCP_SLUG__/mcp {
|
||||
# Resource identifiers MUST match what your metadata document returns.
|
||||
# Use the same hash/digest in mcp_oauth.metadata().
|
||||
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;
|
||||
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;
|
||||
js_content mcp_oauth.metadata;
|
||||
}
|
||||
|
|
@ -77,6 +83,16 @@ server {
|
|||
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.
|
||||
location = /_oauth_check {
|
||||
internal;
|
||||
|
|
@ -85,7 +101,7 @@ server {
|
|||
|
||||
# --- Protected Streamable HTTP MCP endpoint --------------------------------
|
||||
# Requires successful OAuth check before proxying to the upstream server.
|
||||
location ^~ /__MCP_SLUG__/mcp/ {
|
||||
location ^~ /$mcp_resource/mcp/ {
|
||||
auth_request /_oauth_check;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
|
@ -109,7 +125,7 @@ server {
|
|||
}
|
||||
|
||||
# --- Optional unauthenticated SSE bridge for local debugging ---------------
|
||||
location ^~ /__MCP_SLUG__/mcp-browser/ {
|
||||
location ^~ /$mcp_resource/mcp-browser/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header Host $host;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,23 @@ class ConfigLoader:
|
|||
servers = {}
|
||||
for name, server_config in config_data.get("servers", {}).items():
|
||||
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_config = None
|
||||
if oauth_data:
|
||||
|
|
@ -121,12 +138,43 @@ class ConfigLoader:
|
|||
extra_params=oauth_data.get("extra_params") or oauth_data.get("extraParams", {}),
|
||||
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(
|
||||
type=transport_data.get("type", "stdio"),
|
||||
url=transport_data.get("url"),
|
||||
headers=transport_data.get("headers", {}),
|
||||
timeout=transport_data.get("timeout", 30.0),
|
||||
sse_timeout=transport_data.get("sse_timeout") or transport_data.get("sseTimeout", 300.0),
|
||||
type=normalized_type,
|
||||
url=transport_url,
|
||||
headers=headers,
|
||||
timeout=timeout,
|
||||
sse_timeout=sse_timeout,
|
||||
oauth=oauth_config
|
||||
)
|
||||
servers[name] = MCPServerConfig(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[Unit]
|
||||
Description=Expose MCP Browser via HTTP bridge
|
||||
Description=Run mcp-browser in MCP server mode
|
||||
Documentation=https://github.com/Xilope0/mcp-browser
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
|
@ -7,20 +7,33 @@ Wants=network-online.target
|
|||
[Service]
|
||||
Type=simple
|
||||
Environment="PYTHONUNBUFFERED=1"
|
||||
Environment="MCP_PROXY_BIN=%h/.local/bin/mcp-proxy"
|
||||
Environment="MCP_PROXY_ALLOW_ORIGIN=https://platform.openai.com"
|
||||
Environment="MCP_PROXY_PORT=14001"
|
||||
Environment="MCP_PROXY_CONFIG=%h/.config/mcp-browser/proxy.yaml"
|
||||
Environment="MCP_PROXY_EXTRA_ARGS="
|
||||
EnvironmentFile=-%h/.config/mcp-browser/proxy.env
|
||||
Environment="MCP_BROWSER_BIN=%h/.local/bin/mcp-browser"
|
||||
Environment="MCP_BROWSER_CONFIG=%h/.config/mcp-browser/config.yaml"
|
||||
Environment="MCP_BROWSER_SERVER=default"
|
||||
Environment="MCP_BROWSER_MODE=server"
|
||||
Environment="MCP_BROWSER_NO_BUILTIN=false"
|
||||
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 '\
|
||||
set -eu; \
|
||||
exec "$MCP_PROXY_BIN" \
|
||||
--allow-origin "$MCP_PROXY_ALLOW_ORIGIN" \
|
||||
--port "$MCP_PROXY_PORT" \
|
||||
--named-server-config "$MCP_PROXY_CONFIG" \
|
||||
$MCP_PROXY_EXTRA_ARGS'
|
||||
ExecStart=/usr/bin/env bash -lc 'set -eu
|
||||
ARGS=()
|
||||
if [[ "$MCP_BROWSER_NO_BUILTIN" == "true" ]]; then
|
||||
ARGS+=(--no-builtin)
|
||||
fi
|
||||
if [[ -n "$MCP_BROWSER_TRANSPORT" ]]; then
|
||||
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
|
||||
RestartSec=5
|
||||
|
|
|
|||
Loading…
Reference in New Issue