Wrap any local stdio MCP server with an OAuth 2.1 front end so it can be added as a claude.ai custom connector (web, mobile, desktop).
claude.ai's custom connectors speak remote MCP over HTTPS and authenticate with OAuth 2.1 (Dynamic Client Registration + PKCE) — there is no static bearer-token field. This proxy supplies that OAuth layer and bridges to a stdio backend.
Usable. See deploy/README.md for the full deployment guide (Caddy, Tailscale, headless Obsidian). Design details: docs/superpowers/specs/2026-07-06-mcp-oauth-proxy-design.md.
Expose mcp-obsidian — make an Obsidian vault available to Claude everywhere. Backend is configurable, so the proxy works for any stdio MCP server.
claude.ai → Caddy (TLS) → mcp-oauth-proxy (OAuth 2.1 + FastMCP proxy) → stdio backend → (tailscale) → Obsidian REST API
The proxy is backend-agnostic. To expose a different single stdio MCP server:
- Set
MCP_BACKEND_COMMANDandMCP_BACKEND_ARGSto invoke your server (defaults:uvxandmcp-obsidian). - Use
MCP_BACKEND_ENV_*to forward environment variables to the backend (e.g.,MCP_BACKEND_ENV_API_KEY=secretbecomesAPI_KEY=secretin the child process).
Example: to wrap mcp-github:
MCP_BACKEND_COMMAND=uvx
MCP_BACKEND_ARGS=mcp-github
MCP_BACKEND_ENV_GITHUB_TOKEN=ghp_...Set MCP_SERVERS_CONFIG to a mounted JSON file (the Claude-desktop mcpServers
shape) to expose several servers through the same connector and login. When set,
it overrides the single MCP_BACKEND_* vars. With more than one server, each
backend's tools are namespaced by its config key (e.g. obsidian_...,
github_...); a single-server file stays unprefixed. See
deploy/servers.example.json.
{
"mcpServers": {
"obsidian": { "command": "uvx", "args": ["mcp-obsidian"], "env": { "OBSIDIAN_API_KEY": "..." } },
"github": { "command": "uvx", "args": ["mcp-github"], "env": { "GITHUB_TOKEN": "..." } }
}
}Each stdio server's child process receives only a host env allowlist (PATH,
etc.) plus its own env block — the proxy's secret env is never forwarded.