-
Notifications
You must be signed in to change notification settings - Fork 4.7k
local vs remote mcp server
The specification is unusually direct about this: protocol semantics are identical on every transport. A transport is a binding that defines how messages are framed and delivered, not what they mean. Two are standard today: stdio, newline-delimited JSON-RPC over the standard streams of a subprocess the client launches, and Streamable HTTP, where each message is an HTTP POST to one endpoint and replies come back as JSON or as a request-scoped SSE stream.
So the decision is not about capability. Every tool works the same either way. It is about three other things, and one of them will bite you.
Who owns the process. On stdio the client launches your server and the server dies with it. Nothing to deploy, nothing to authenticate, nothing left running. On HTTP the server outlives every client and somebody has to be responsible for it.
Who can reach it. A stdio server serves exactly the one client that spawned it. An HTTP server can serve several, including several at once, which is the real reason to want it.
Where the work happens, which does not move. This is the part people get wrong. A remote MCP server does not put your work somewhere else; it puts the server somewhere else. If the server drives a browser, the browser runs wherever the server runs, on the server's network, with the server's files. For a browser server that is usually the argument against remote rather than for it: the profile you are logged into and the proxy you route through are on your machine, and moving the server away from them is moving the work away from its inputs. Playwright MCP with a proxy is the same point from the network side.
Here is ours, because it is the failure we actually hit rather than one we imagine somebody might.
Our server closes its browsers when the SDK's lifespan context exits. Over stdio the SDK enters that lifespan once per process, so its exit is the last moment the event loop that opened the browsers is still alive, which is exactly the right time to close them. Over Streamable HTTP the SDK enters it once per client. The same line of code, unchanged, therefore means "close everything when the process ends" on one transport and "close everything when anybody disconnects" on the other.
Measured on this server: with a client attached the machine held 7 firefox processes, and one second after that client detached it held 1. The browsers a second client was still using would have gone with them.
Nothing in the protocol is wrong here, and nothing in the SDK is wrong either. Per-client is the correct scope for an HTTP session. The bug is entirely in the assumption that a lifecycle hook means the same thing on both bindings because the tools do. When you move a server to HTTP, audit every piece of state whose lifetime you tied to a connection, and expect the audit to find something.
The other half is less dramatic and worth knowing: over stdio the shutdown path is the client closing stdin, and that path can hang. Measured on Linux, 2026-09-06: a client that closed stdin with a page still open waited 180 seconds for the process and gave up; with no page open the same shutdown took 0.2 seconds.
- One user, one client, work that lives on your machine: stdio. This is most servers, and it is the default for a reason.
- Several clients that must share one live thing: HTTP. That is the case stdio cannot express at all.
- A team, or a server you want to deploy once: HTTP, and now you own authentication, lifetime and the state audit above.
-
A browser server: stdio unless you can say why the browser should not be
where your profile is. Ours takes
STEALTHFOX_MCP_TRANSPORT=httpif you can, and defaults to stdio because usually you cannot.
If the thing pushing you toward remote is "I want it always available", check that the always-available part is the server rather than the data. Often it is the data, and then the answer is a resource or a plain API rather than a relocated process. MCP alternatives has that argument in full.
What is the difference between a local and a remote MCP server? Where the process runs and who owns its lifetime. The tools and their behaviour are identical, by specification.
Is SSE still a transport? Not as a separate one in the current revision. Streamable HTTP uses SSE for request-scoped reply streams; the standalone SSE transport belongs to an earlier revision, and interoperating with those is described in the spec's backward-compatibility rules.
Can I run one MCP server for my whole team? Over HTTP, yes. You then own authentication and the question of what happens when two people drive the same stateful thing at once, which for a browser server is a real question and not a formality.
Which is faster? Neither, meaningfully. Both are local IPC or one HTTP round trip, and in an agent session every cost is dominated by the model.
Does remote mean my data leaves my machine? It means the server's work happens on the server's machine. Whether that is your data depends entirely on what the server does.
See also: How to build an MCP server, writing an MCP client in Python, and the MCP server for this server's settings.
- The MCP transports overview, retrieved 2026-09-13, for the two standard bindings, the wording on bindings versus semantics, and backward compatibility with earlier revisions.
- This project's own server: the per-client lifespan behaviour and the 7-to-1 process measurement are recorded beside the code that handles it in
src/aihawk/mcp/server.py; the 180-second stdin measurement was taken on Linux on 2026-09-06.
Written while maintaining a server that supports both and ships stdio. The recommendation is the one that makes our own remote mode the exception, because for a browser the inputs are where the person is.
- OpenAI Operator alternatives
- Open-source Operator-style agents
- Is OpenAI Operator still available?
- OpenAI Operator vs Claude computer use
- browser-use alternatives
- Choosing an AI browser agent
- Open-source AI browser agents
- Open-source computer-use agents
- What is an AI web agent?
- AI browser agents vs traditional scraping
- Cloud browser infrastructure for AI agents, explained
- Browserbase alternatives
- Firecrawl vs an AI browser agent
- Skyvern alternatives
- Stagehand vs browser-use
- Project Mariner is gone: what replaced it
- Manus alternatives
- Gemini computer use vs Claude computer use
- AIHawk, reviewed honestly by its own wiki
- AI browser vs AI browser agent: which one do you want?
- AI browser agent vs RPA: which one fits the job
- AI browser agent vs n8n, Zapier and Make
- Vercel agent-browser alternatives, compared honestly
- What is an agentic browser? Definition and the two kinds
- Open-source agentic browsers: the three layers, compared
- Choosing an MCP server for browser automation: four axes
- Stealth MCP servers compared: Camoufox, nodriver, Patchright
- Playwright MCP alternatives, and the three you don't need
- Autonomous browser agents: the four rungs of autonomy
- What is actually free in the AI browser agent stack
- browser-use on GitHub: what the repo actually gives you
- Playwright MCP vs Chrome DevTools MCP: different jobs
- How to choose among MCP servers: a map by category
- Which MCP servers are worth adding to Claude Code
- MCP on GitHub: finding servers and judging them fast
- MCP vs an API: the decision, and what the wrapper costs
- MCP alternatives: when the protocol is the wrong shape
- Why does my AI agent get blocked?
- The timing signal AI agents give off
- Agent retry loops trip rate limits, not fingerprints
- Claude computer use detected as a bot
- browser-use getting blocked: what you can and cannot change
- Playwright MCP session blocked: four causes, four fixes
- Playwright MCP and captchas: what actually gets you past
- Cloudflare and a browser MCP server: what is being read
- Can an AI agent solve a captcha? The honest answer
- Getting an AI agent to fill out forms
- Which model to use with AIHawk
- Browser problem or model problem?
- Running AIHawk's browser from Claude Code
- Extracting data to a CSV with an AI agent
- Monitoring a page for changes with an AI agent
- Running AIHawk's browser from Claude Desktop
- Running AIHawk's browser from Cursor
- Using an AI agent to hunt for apartments
- Getting website data into Google Sheets with an AI agent
- Using an AI agent to download invoices from portals
- AI agents for web research
- Using an AI agent to test your own website
- Running AIHawk's browser from Cline
- Posting to social media with an AI agent
- Posting to Facebook with an AI agent
- Posting to Instagram with an AI agent
- Posting to X with an AI agent
- Automating LinkedIn posts: read this first
- Appointment bots: what they are and what an agent can legitimately do
- Track prices across sites with an AI agent
- Build a lead list with an AI browser agent
- Run an AI browser agent on a schedule
- AI browser agent with a local LLM: what changes
- Should you log your AI agent into your accounts?
- How to write a task an AI browser agent can follow
- Move data between two web apps with an AI agent
- The MCP server
- How the tools are shaped, and why
- Playwright MCP vs the Playwright CLI: which fits when
- Playwright MCP: browser is already in use, and the fix
- Playwright MCP best practices: four decisions that matter
- Playwright MCP with a proxy, and the three leaks it leaves
- A browser MCP server in GitHub Copilot: setup and limits
- Using a browser MCP server for web scraping: the pattern
- Which LLM for browser automation: the four properties
- How to build a browser agent, and what to take instead
- Getting an AI agent to log into a website: three routes
- MCP tools, resources and prompts: who controls each
- How many MCP tools is too many? The context arithmetic
- How to build an MCP server: the decisions, not the scaffold
- Local or remote MCP server: what changes, and what does not
- Writing an MCP client in Python: the thirty-line version