Here's what Daniel wrote us — and it's a good one. "We are seeing the hub-and-spoke model become increasingly prevalent in MCP, and I personally think it is the architecture that makes the most sense. The basic idea is that you create an MCP gateway, connect all the MCP servers and tools that an AI agent may need, and then expose a single MCP connection to the client. The gateway can be self-hosted on a VPS, a home server, or almost anywhere else. Authentication to the individual MCP services lives on the gateway, while the connecting client only needs to authenticate once to that central endpoint." He gives the example of connecting Claude Code to an MCP gateway on a VPS, where Claude then gets access to everything through that single point. In a solo-developer environment, he says, this works extremely well. Then he hits the hard part. "The difficulty appears when moving beyond computer-bound tools such as Claude Code. Suppose I have a Home Assistant MCP integration and want to use a conversational interface such as ChatGPT to say, turn on the lights in the office. The missing link is a secure connection between the conversational chat interface and my MCP gateway. The gateway must be protected for obvious reasons, but the client also needs to support the gateway's authentication method and the relevant form of MCP transport. This part of the ecosystem still feels immature." And then the actual question. "If you were designing an MCP gateway primarily for your own use, with the goal of securely connecting conversational AI clients to it, what protocol and authentication posture would you choose? Let's focus specifically on a home-hosted MCP gateway rather than a cloud-hosted one. Some MCP integrations, particularly Home Assistant, naturally fit a local-first architecture. How would you securely expose that gateway to external AI clients without undermining the advantages of keeping it hosted at home?"
So he's asking us to design the thing. Not in the abstract — he wants a concrete stack. Protocol, auth posture, the whole wiring diagram, for a box sitting in someone's house that ChatGPT can talk to without becoming a security disaster.
And he's right that the hub-and-spoke model makes sense. It's basically the API gateway pattern that the web figured out a decade ago, now arriving for tool-using AI agents. But the web's API gateways had the benefit of clients that understood OAuth and could do a browser redirect. A conversational AI client in a chat window... not so much.
That's exactly the tension. Let's define the architecture first. The hub-and-spoke model means you run one MCP gateway process — the hub — exposing a single MCP endpoint to the outside world. Behind it, connected as spokes, are all your individual MCP servers: Home Assistant, filesystem, GitHub, maybe a calendar connector. The client — whether Claude Code on your laptop or ChatGPT in the cloud — only ever talks to the hub. It never sees the spokes directly.
And the wins are real. Single authentication point, centralized tool management — add a new spoke, the hub picks it up, the client discovers it without touching its own config. And there's a context-window argument too. A well-designed hub can do progressive tool discovery, only surfacing relevant tools when the model actually needs them, instead of dumping every Home Assistant entity into the context window at startup.
Which we've talked about before — the token bloat problem. But here's where it gets interesting for Daniel's question. All those wins assume the client is something like Claude Code — a local process on a trusted network, where you can get away with a simple bearer token or even no auth on localhost. The moment your client is ChatGPT, sitting in some OpenAI data center, every assumption changes.
So let's start with transport. What actually carries the MCP messages between a cloud-hosted conversational client and a Raspberry Pi in someone's closet?
The MCP spec's current standard transport is Streamable HTTP. This replaced the older HTTP plus SSE transport, and it's what the spec recommends as the baseline for remote MCP servers. The basic idea: the client makes an HTTP request, the server responds. It works fine for tool invocation where the client says "call this tool" and the server says "here's the result."
And the problem?
Conversational AI clients sometimes need the server to initiate — tool completion notifications, streaming progress updates, maybe a long-running tool that finishes after the initial HTTP response has been sent. Streamable HTTP can handle some of this with chunked transfer encoding, but it's not a natural fit for bidirectional streaming. That pushes us toward WebSocket or SSE as alternatives.
So we're already at a fork. Do we go with the spec-recommended transport that most MCP clients will implement first, or do we optimize for the bidirectional case that conversational AI actually needs?
I think the answer is Streamable HTTP. It's where the ecosystem is standardizing. If you want your gateway to work with the widest range of clients over the next year or two, you implement Streamable HTTP. The bidirectional streaming case can be handled with a thin WebSocket side channel if you really need it. But honestly, for the "turn on the office lights" use case Daniel described, the tool invocation is near-instant. The HTTP response comes back in maybe two hundred milliseconds and the model processes it. Streamable HTTP is sufficient for the vast majority of home automation tool calls.
So Streamable HTTP as the primary transport. That was the easy part. Now auth — and this is where it gets textured.
Textured is a generous word for it. The MCP specification's authorization chapter — relatively new, landing in the twenty twenty-five to twenty twenty-six spec revisions — now mandates OAuth two point one with PKCE for remote MCP servers. That's the official answer.
Which assumes a browser.
Which assumes a browser. The PKCE flow works like this: the client redirects the user to an authorization server in a browser, the user logs in and grants consent, the authorization server redirects back with an authorization code, the client exchanges that code for tokens. Every step assumes there's a browser window somewhere in the loop. ChatGPT doesn't have a browser. It's an API client. It can make HTTP requests. It cannot pop open a Chrome tab and wait for a redirect.
So the spec's official answer is effectively useless for the exact use case Daniel is asking about.
For now, yes. And this is the immaturity he's sensing. The spec authors clearly had traditional web applications and local desktop clients in mind when they wrote the authorization chapter. The conversational AI use case — a cloud-hosted agent that needs to talk to your personal MCP gateway — that's still an edge case from the spec's perspective, even though it's arguably the most interesting one.
So what actually works?
Two paths, serving different threat models. Path one is the device authorization grant — RFC eight six two eight. This is the OAuth flow designed for devices that don't have a browser: smart TVs, game consoles, IoT gadgets. Here's how it maps to Daniel's scenario. He opens a setup page on his phone — a one-time thing — and tells the gateway "authorize a new client." The gateway returns a device code and a URL. He visits that URL in his phone's browser, enters the device code, and authenticates. Meanwhile, ChatGPT is polling the gateway's token endpoint with that same device code. Once Daniel approves the authorization on his phone, the gateway issues an access token and a refresh token to the client. From that point forward, the client uses the access token for API calls and the refresh token to get new access tokens when the old one expires. No browser needed on the client side. The user does the browser part once, on whatever device is handy, and the client gets a long-lived credential.
That's clever. And it's how Home Assistant's own cloud integration works already, more or less.
The device code flow is battle-tested in exactly this kind of home automation scenario. The only thing missing is conversational AI clients actually implementing the client side of it. Right now, if you try to connect ChatGPT to an OAuth-protected MCP gateway, ChatGPT doesn't know how to do the device code dance. It expects a bearer token you've already generated and pasted into a config field somewhere.
Which brings us to path two.
Path two is mutual TLS — mTLS. This is the dark horse, and I genuinely think it's underrated for personal-use gateways. Instead of any OAuth flow at all, you issue a client certificate to each client that needs to talk to your gateway. The gateway is configured to require client certificates — so when a connection comes in, the TLS handshake itself proves the client's identity. No tokens, no refresh dance, no browser redirects. The cryptography does the authentication at the transport layer before any MCP messages are even exchanged.
And the catch?
The catch is that almost no commercial conversational AI client supports presenting a client certificate. ChatGPT doesn't. Claude dot ai doesn't. This only works for clients you control — a self-hosted LLM frontend, a custom plugin you wrote yourself, maybe a Home Assistant automation that calls out to an LLM. If you're building your own tooling, mTLS is the cleanest, most secure option available. If you're trying to use a commercial chat interface, it's a non-starter.
So we have three auth options on the table. OAuth two point one with PKCE, which the spec mandates but no conversational client supports. Device code flow, which is the pragmatic OAuth path but still requires client support that doesn't exist yet. And mTLS, which is cryptographically beautiful and completely unsupported by commercial clients. This is what Daniel means by "immature."
It's not that the solutions don't exist. It's that the clients haven't caught up. And this is a coordination problem, not a technical one. The MCP spec authors can write the perfect authorization chapter, but until OpenAI and Anthropic and Google implement the client side of OAuth two point one with device code flow in their conversational products, we're stuck with... well, with what we're stuck with.
So what do you actually do? Today. August twenty twenty-six. You have a Raspberry Pi running an MCP gateway with Home Assistant behind it, and you want to say "turn on the lights" to ChatGPT on your phone.
You run a Cloudflare Tunnel or a Tailscale Funnel. Let me explain why this is step one, before we even talk about application auth. Your MCP gateway is sitting on your home network behind a NAT. You could port-forward — punch a hole in your router's firewall, map an external port to the gateway's internal IP. That works, technically. It also exposes your home IP address to every probing bot on the internet, and now you're personally responsible for TLS termination and DDoS mitigation on whatever consumer-grade router your ISP gave you. Don't do that.
So the tunnel handles the network exposure.
Cloudflare Tunnel runs a small daemon on your gateway machine — cloudflared — that establishes an outbound connection to Cloudflare's edge. No inbound ports need to be open. Cloudflare terminates TLS at their edge, handles DDoS, and forwards clean traffic to your gateway over that persistent tunnel. External clients see a Cloudflare-managed hostname with a valid certificate. Your home IP is never exposed. Tailscale Funnel does something similar but with a WireGuard-based overlay network. Same principle: outbound-only connection from your gateway, TLS at the edge, no port forwarding. Thousands of people are running Home Assistant behind Cloudflare Tunnels right now. It's the standard recommendation for exposing Home Assistant remotely without opening ports.
And this is not theoretical. People are running Home Assistant behind Cloudflare Tunnels right now.
So that's layer one of our architecture — the network layer. Cloudflare Tunnel in front of the gateway. Now, the tunnel gives you transport security and hides your IP, but it does not give you application-level authentication. If someone discovers your tunnel's hostname, they can still try to talk to your MCP gateway. The tunnel is not a substitute for auth — it's a complement.
Which is the misconception you want to head off.
Yes. I've seen people say "I'm behind Cloudflare, I'm secure." You're not. You've solved the network exposure problem. You haven't solved the authentication problem. A reverse tunnel is a perimeter defense, not an identity system. You still need the gateway to authenticate every request.
So the tunnel gets us a public endpoint. What sits behind it for auth, given that none of the ideal options work with commercial clients yet?
The pragmatic answer for mid-twenty-twenty-six is a pre-issued long-lived bearer token, with every mitigation we can stack around it to limit the damage if it leaks. This is not ideal. I want to be clear about that. A bearer token is a static secret — whoever has it can call every tool on your gateway. If it leaks, you're compromised. But right now, if you want ChatGPT to talk to your MCP gateway, you generate a token, you paste it into whatever configuration mechanism the client provides, and that's your auth. It's the reality of the ecosystem today.
So we mitigate.
We mitigate aggressively. First, rate limiting on the gateway. No conversational client needs to call your Home Assistant tools a thousand times per second. Set a per-token rate limit — maybe ten requests per second — and anything above that gets dropped. Second, IP allowlisting where possible. OpenAI and Anthropic publish their egress IP ranges. If your gateway only accepts requests from those known ranges plus your own LAN, you've shrunk the attack surface enormously. A leaked token is useless from any other IP. Third, and this is the one I think people underinvest in — per-tool authorization scoping on the gateway itself.
This is the capability scoping problem. Explain that.
When you connect a Home Assistant MCP server to your gateway, the raw integration exposes every entity in your home. Lights, locks, thermostats, cameras, garage doors, everything. If your gateway passes that entire surface area through to ChatGPT, and your bearer token leaks, someone can unlock your front door. The gateway needs a semantic layer — a curated set of higher-level tools that expose only what the conversational client actually needs. "Turn on the office lights" maps to a specific tool that can only control lights in specific rooms. The gateway translates between the coarse conversational intent and the specific Home Assistant entity IDs. The raw entities are never exposed to the external client.
So the gateway becomes a security boundary, not just a routing layer. It's not a dumb proxy — it's actively restricting what each client can do.
This is where the hub-and-spoke model earns its keep. If you had ChatGPT talking directly to six different MCP servers, you'd have to implement that scoping six times, in six different config formats, with six different auth mechanisms. With the hub, you do it once. The gateway is the choke point, and you use it. Every tool that passes through gets scoped. Home Assistant can control lights and read temperature sensors, but cannot touch locks or cameras. The calendar tool can read your availability but cannot create or delete events. The filesystem tool is restricted to a specific directory and cannot traverse upward.
What about the local clients? You mentioned dual-stack earlier.
This is how we preserve the local-first advantage Daniel asked about. The gateway runs two listeners. One listener is bound to the LAN interface — localhost or the internal network IP — and it accepts connections from trusted local clients. Home Assistant itself, a local LLM frontend, Claude Code on your laptop. This listener can use simpler auth or no auth at all, because it's only reachable from inside your network. The second listener is the external-facing one, bound to the Cloudflare Tunnel interface, and it enforces the full auth stack — token validation, rate limiting, IP allowlisting, tool scoping. Local clients never touch the external auth path. They get the full richness of direct tool access without the security overhead. External clients get the curated, scoped tool set with every security control enabled.
That's elegant. One gateway process, two personalities, depending on where the request came from.
It's not hard to implement. Most MCP gateway implementations — there are open-source ones in Python and TypeScript now — can bind to multiple interfaces and apply middleware per-listener. You configure the LAN listener with a no-op auth middleware and the WAN listener with the full stack. Same tools behind both, different access patterns.
Let's walk through the actual flow. I'm on my phone, I open ChatGPT, I say "turn on the office lights." What happens, step by step?
ChatGPT receives your message and decides it needs to call a tool. It looks at its registered MCP tools and finds one called something like "control_lights" with parameters for room and state. It constructs an MCP tool invocation request and sends it as an HTTP POST to your gateway's public hostname — the one Cloudflare is fronting. The request includes your bearer token in the authorization header. Cloudflare's edge terminates TLS, inspects the request, and forwards it through the tunnel to your gateway's external listener. The gateway validates the token, checks the IP against the allowlist, confirms the rate limit hasn't been exceeded, and verifies that this specific token is authorized to call the "control_lights" tool. Then it translates the request — "office" becomes "light dot office underscore ceiling" in Home Assistant's entity naming — and forwards it to the Home Assistant MCP spoke. Home Assistant turns on the light. The response flows back up through the gateway, through the tunnel, to ChatGPT. ChatGPT says "Done, the office lights are on." Total elapsed time: maybe three hundred milliseconds.
If someone steals that bearer token from a log file somewhere?
They can call "control_lights" from whatever IP they're on. But if we've done the IP allowlisting, the gateway drops the request before it reaches any tool — the token alone isn't enough, you also need to be calling from an allowed IP range. If they somehow spoof that, they can turn lights on and off. Annoying, but not catastrophic. They cannot unlock doors, because the gateway's tool scoping doesn't expose lock control to that token. They cannot read calendars or access files, because those tools are scoped to different tokens or not exposed at all. The blast radius is contained.
That's the defense-in-depth argument. No single control is sufficient, but stacked together they make exploitation impractical for a home user threat model.
Right. The threat model here is not a nation-state actor. It's opportunistic scanning, leaked tokens in public git repos, maybe a compromised Cloudflare account. For that threat model, the stack we're describing — tunnel plus token plus IP allowlisting plus rate limiting plus tool scoping — is robust.
You mentioned earlier that the ecosystem is moving. What should someone building this actually watch for?
The single biggest signal will be when a major conversational AI client ships OAuth two point one device code flow support for MCP connections. The moment ChatGPT or Claude can do the device authorization dance natively — you scan a QR code on your phone, approve the client, and it gets a proper short-lived access token with a refresh token — that's when we can retire the long-lived bearer token approach. The infrastructure exists. The spec exists. The clients just haven't implemented it yet.
And mTLS?
mTLS is the long game for your own tooling. If you're building a custom frontend or a Home Assistant dashboard that talks to an LLM, issue it a client certificate and configure the gateway to require mTLS on a separate listener. You get cryptographic client identity with no tokens at all. It's cleaner, it's faster, and it eliminates whole categories of token-management problems. But it'll never be the answer for commercial chat interfaces — their security models just don't work that way.
If I'm Daniel, and I want to build this on a weekend, what's the concrete stack?
You run the MCP gateway on a Raspberry Pi or an old Intel NUC on your home network. Behind it, you connect your Home Assistant MCP server, maybe a filesystem server, maybe a calendar connector. You install cloudflared and configure a Cloudflare Tunnel to a hostname you control. You configure the gateway with two listeners — one on the LAN interface with no auth for local clients, one on the tunnel interface with bearer token auth, IP allowlisting for known AI provider egress ranges, per-tool scoping, and rate limiting. You generate a bearer token, store it somewhere safe, and configure your conversational client to use it. For your own custom clients, you add a third listener with mTLS and issue client certificates. That's the architecture. It's deployable today with open-source tools. It's not perfect — the bearer token is a compromise — but it's the best available posture given where the ecosystem is.
The alternative is waiting for the ecosystem to mature, which could be six months or could be two years. In the meantime, your lights are dumb.
Your lights are dumb, and you're not learning anything about running a gateway. I'd rather deploy the pragmatic stack now and swap out the auth layer when OAuth support lands than wait for perfection. The gateway architecture — the dual listeners, the tool scoping, the tunnel setup — none of that changes when the auth mechanism improves. You're building the foundation either way.
Let's steelman the objection. Someone listening says: you're recommending a bearer token for a home gateway that controls physical devices, and your mitigations are IP allowlisting and rate limiting — both of which can be bypassed by a sufficiently motivated attacker. A leaked token from a compromised OpenAI server, or a misconfigured allowlist, and someone has access to your home. Why is this acceptable?
The objection is fair. A bearer token is a single point of failure, and IP allowlisting is not cryptographic security — IPs can be spoofed at the BGP level, though that's well beyond opportunistic attackers. The honest answer is that it's acceptable because the alternative is no remote access at all, which defeats the purpose, or waiting indefinitely for client support that may not arrive on Daniel's timeline. The mitigations don't make the system invulnerable — they make it expensive to attack. For a home user whose threat model is automated scanning and token scraping, not targeted attacks, that's the right tradeoff. If your threat model includes sophisticated targeted attacks, don't expose your home gateway to the internet at all. Keep it LAN-only and use a VPN to reach it remotely. That's the higher-assurance posture, and it's always available.
That's honest. The architecture scales down to LAN-only trivially — you just don't configure the tunnel or the external listener. And it scales up to mTLS for your own clients. The bearer token period is a transitional phase, not a permanent design choice.
One more thing I want to flag, because it connects to where this is all heading. As conversational AI clients become more capable, the gateway's role shifts. Right now we think of it as a tool aggregator — one endpoint for many tools. But the real value over time is going to be the semantic translation layer. The gateway doesn't just pass tool calls through. It translates between how a conversational model thinks about actions — "turn on the office lights" — and how the underlying systems actually work — "call service light dot turn on with entity ID light dot office underscore ceiling." That translation layer, plus the security scoping, is where the gateway stops being infrastructure and starts being a product.
The hub-and-spoke model isn't just a convenience. It's the architecture that makes that translation layer possible at all, because you need a single point of control to do the mapping.
Right. If every AI client talks to every MCP server directly, you have no place to put the translation logic. It has to live somewhere. The gateway is that somewhere.
To pull it together. Streamable HTTP as the transport, because that's where the spec is standardizing and it's sufficient for home automation tool calls. OAuth two point one with device code flow as the target auth posture, but a long-lived bearer token with aggressive mitigations as the pragmatic interim choice. Cloudflare Tunnel or Tailscale Funnel for network exposure without port forwarding. Dual-stack listeners to keep local clients fast and trusted. Per-tool scoping on the gateway so a compromised token can't unlock your front door. And mTLS waiting in the wings for any client you control yourself.
That's the stack. Deployable this weekend on hardware you probably already own. The ecosystem will catch up — the spec is solid, the client support is just lagging. When it does, you swap the auth layer and keep everything else.
The open question I keep coming back to is whether the MCP ecosystem converges on a standard auth flow for conversational clients at all, or whether we end up with fragmentation — each AI provider issuing its own token format, each gateway having to support a different auth dialect per client. That would be a worse outcome than the current immaturity, because at least right now the direction is clear even if the implementation isn't.
I think the spec authors are aware of this. The authorization chapter is explicitly designed to be the single standard — OAuth two point one with PKCE for browser-capable clients, device code flow for browserless ones. The question is whether the commercial providers implement it or decide their own token systems are good enough. Given that both OpenAI and Anthropic have shown willingness to adopt MCP as a standard for tool integration, I'm cautiously optimistic. But cautious is the operative word.
If you're building a home-hosted MCP gateway, we want to hear what auth setup you landed on. The website's the best way to reach us — my weird prompts dot com. This space is moving fast and the real-world deployment stories are more useful than any spec document.
Thanks to Hilbert Flumingtop for producing. This has been My Weird Prompts. We'll be back soon.
Go build something.