{"slug": "turn-any-mcp-server-into-a-remote-https-endpoint", "title": "Turn any MCP server into a remote HTTPS endpoint", "summary": "Rmcp, a new open-source control plane, lets developers turn any MCP server into a remote HTTPS endpoint deployable to AWS Lambda or a local gateway, with support for Streamable HTTP, bearer or OAuth auth, and generated client snippets for VS Code, Cursor, Claude, and Notion. The tool, requiring Node >= 22 and pnpm, handles packaging, credentials, and transport, and verifies deployments with a real MCP initialize handshake.", "body_md": "**Turn any MCP server into a remote HTTPS endpoint your AI clients can reach.**\n\nMost MCP servers are npm packages that run as a local subprocess over stdio.\nThat works on one machine, for one client. The moment you want the same server\nin Claude Desktop *and* VS Code *and* on your phone, you need it to be a remote\nserver speaking Streamable HTTP — with TLS, authentication, and somewhere to\nkeep the API keys.\n\nrmcp is the small control plane that does that. You paste an mcp.json-style definition into a web UI, click Deploy, and get back a URL and a config snippet for your client. It handles the packaging, the credentials, and the transport.\n\n``` php\nflowchart LR\n    UI[\"Web UI<br/>(define + deploy)\"] --> API[\"Control plane<br/>Hono + SQLite\"]\n    API -->|\"target: local\"| GW[\"Local gateway<br/>:8788\"]\n    API -->|\"target: lambda\"| LAM[\"AWS Lambda<br/>+ Function URL\"]\n    GW --> B1[\"bridge\"]\n    LAM --> B2[\"bridge\"]\n    B1 --> S1[\"stdio subprocess<br/><i>or</i> upstream HTTP\"]\n    B2 --> S2[\"stdio subprocess<br/><i>or</i> upstream HTTP\"]\n    C[\"VS Code · Cursor · Claude\"] -.->|\"Streamable HTTP<br/>+ bearer or OAuth\"| GW\n    C -.-> LAM\n```\n\n**Two server types.** A **stdio** server is any npm-published MCP server — the\nkind you'd normally run with `npx`\n\n. rmcp installs it and runs it behind a\nStreamable HTTP bridge. An **http** server is one that's already remote; rmcp\nproxies it and injects the auth headers server-side, so your clients never hold\nthe upstream credential.\n\n**Two deploy targets**, chosen per server at deploy time:\n\nlocal |\nlambda |\n|\n|---|---|---|\n| Runs on | your machine or your own box | AWS Lambda behind a Function URL |\n| Reachable at | `http://<host>:8788/<id>` (LAN), or a public HTTPS URL if you front it with a reverse proxy |\nthe Function URL |\n| Auth | bearer token or OAuth |\nbearer token |\n| Needs AWS | no | yes |\n| Cold start | none — kept warm while rmcp runs | yes |\n| Secrets live in | local SQLite | SSM Parameter Store |\n\nA fully local flow needs no AWS account at all.\n\n**Client snippets, generated.** Every deployed server has an Export view with\nready-to-paste config for VS Code, Cursor, the Claude CLI, Claude Desktop, and\nNotion custom agents — with the right auth already filled in.\n\n- Node >= 22 and pnpm (\n`corepack enable`\n\n) - macOS or Linux\n**Only for the Lambda target:** AWS credentials in`~/.aws`\n\n, with permissions for Lambda, IAM (role creation), SSM Parameter Store, and S3 (packages over 45 MB are staged through an`rmcp-deploy-<account>-<region>`\n\nbucket).\n\n```\npnpm install\npnpm --filter @rmcp/bridge build   # bundle the bridge — required before first run\npnpm dev                           # API on :8787, UI on :5173\n```\n\nOpen [http://localhost:5173](http://localhost:5173).\n\n-\n**Create a server.** Give it a name (`[a-z0-9-]`\n\n, up to 40 chars) and either an npm package + version (stdio) or an upstream URL (http). Declare each env var or header, marking the sensitive ones as`secret`\n\n. -\n**Set the secrets** on the server's page. Values go into rmcp's local SQLite database, and are pushed to SSM Parameter Store only when you deploy to Lambda. -\n**Deploy**— locally or to Lambda. Either way rmcp finishes by running a real MCP`initialize`\n\nhandshake against the new endpoint, so a green deploy means the server actually answered. -\n**Connect**— open Export and copy the snippet for your client.\n\nUndeploy removes the compute but keeps your secrets. Deleting a server purges\nits secrets, and for servers with an AWS footprint, everything under\n`/rmcp/<id>/`\n\nin SSM.\n\n**VS Code** — merge into `.vscode/mcp.json`\n\n:\n\n```\n{ \"servers\": { \"my-server\": { \"type\": \"http\", \"url\": \"https://…/<id>\",\n  \"headers\": { \"Authorization\": \"Bearer <token>\" } } } }\n```\n\n**Claude CLI** — one command:\n\n```\nclaude mcp add --transport http my-server https://…/<id> \\\n  --header \"Authorization: Bearer <token>\"\n```\n\n**Claude Desktop** — depends on the target. Local servers front an OAuth\nauthorization server that Claude Desktop speaks natively: add a custom\nconnector, paste the client ID and secret from the Export view, and click\nConnect. A browser tab opens and closes by itself — there's nothing to approve.\nLambda servers have no authorization server, so they go through the `mcp-remote`\n\nstdio bridge instead (the Export view generates that config too).\n\n**Cursor** and **Notion custom agents** are also covered in the Export view.\n\nEndpoints are keyed by the server's UUID, not its name — renaming a server never changes its URL. Every endpoint is protected by a per-server bearer token, enforced identically on both targets. Local endpoints additionally accept OAuth access tokens, which resolve to the same bearer internally.\n\nThe local gateway listens on all interfaces, so other devices on your LAN can\nreach it. To expose it to the internet, put a reverse proxy in front — see\n[self-hosting](/datascope-romania/rmcp/blob/main/docs/self-hosting.md), which covers exactly that with Caddy and\nautomatic TLS.\n\nThe UI follows your system theme, with a manual light/dark/auto toggle in the header.\n\n— how the control plane, gateway, bridge, and deployer fit together, and what a request actually does.[Architecture](/datascope-romania/rmcp/blob/main/docs/architecture.md)— authentication, the OAuth server, where secrets live, and what this tool explicitly does not defend against.[Security model](/datascope-romania/rmcp/blob/main/docs/security.md)— settings, environment variables, and the HTTP API.[Configuration](/datascope-romania/rmcp/blob/main/docs/configuration.md)— running it on a Linux box behind Caddy with public HTTPS endpoints.[Self-hosting](/datascope-romania/rmcp/blob/main/docs/self-hosting.md)\n\n```\napps/api          control plane (Hono), local gateway, OAuth server\napps/web          React + Vite UI\npackages/bridge   Streamable HTTP → stdio / http-proxy; runs in Lambda and in-process\npackages/deployer AWS pipeline: stage, zip, IAM role, SSM params, function, healthcheck\npackages/shared   zod schemas shared across the workspace\npnpm test        # vitest across the workspace\npnpm typecheck   # tsc --noEmit across the workspace\npnpm e2e         # end-to-end deploy against real AWS (needs credentials)\n```\n\nThe bridge is the piece worth understanding first: the same `makeHandler`\n\nruns\ninside the Lambda and in-process behind the local gateway, which is why both\ntargets behave identically down to the auth check.\n\nMIT — see [LICENSE](/datascope-romania/rmcp/blob/main/LICENSE).", "url": "https://wpnews.pro/news/turn-any-mcp-server-into-a-remote-https-endpoint", "canonical_source": "https://github.com/datascope-romania/rmcp/", "published_at": "2026-08-27 20:04:27+00:00", "updated_at": "2026-08-27 20:18:19.315063+00:00", "lang": "en", "topics": ["developer-tools", "ai-infrastructure", "ai-tools"], "entities": ["rmcp", "AWS Lambda", "VS Code", "Cursor", "Claude", "Notion", "SSM Parameter Store", "SQLite"], "alternates": {"html": "https://wpnews.pro/news/turn-any-mcp-server-into-a-remote-https-endpoint", "markdown": "https://wpnews.pro/news/turn-any-mcp-server-into-a-remote-https-endpoint.md", "text": "https://wpnews.pro/news/turn-any-mcp-server-into-a-remote-https-endpoint.txt", "jsonld": "https://wpnews.pro/news/turn-any-mcp-server-into-a-remote-https-endpoint.jsonld"}}