MCP client: the app that hands your files to the model
Searching for an MCP client usually turns up two kinds of page: a definition that explains the client is the counterpart to the server, and a list of applications with checkmarks next to feature names. Neither answers the question that brought most people there, which is what actually differs between them and what that difference costs.
The awkward part is that a client is not a thing anyone downloads. The specification is precise about this: the host is the application a person interacts with, and a client is a protocol-level component that the host creates, one per server it connects to. Connecting three servers means three clients inside one application. So the decision is never which client to use. It is which host to run, and the host settles the things the protocol leaves optional.
What the host actually decides
The protocol defines two layers. The data layer is JSON-RPC 2.0 carrying the messages, and the transport layer covers connection establishment, message framing and authorization. Two transports are defined: stdio, for a server running as a local process, and Streamable HTTP, which uses HTTP POST with optional Server-Sent Events for remote servers.
Almost everything that varies between hosts sits in a layer the specification deliberately leaves open. The host decides where configuration lives, whether a server starts automatically or on request, whether a tool call pauses for confirmation, whether credentials are stored per project or per account, and whether hundreds of tool definitions get loaded into the model's context or searched on demand.
None of those are server-side choices. A server that works in one host works in another; how much it can do, and how much it can do without being asked, is the host's decision.
Three that document their behaviour
The differences are easiest to see in hosts that publish the specifics. All three of the following support stdio and an HTTP transport, and diverge on configuration scope and confirmation.
| Host | Configuration files | Transports documented | Confirmation before a tool runs |
|---|---|---|---|
| Visual Studio Code | .vscode/mcp.json, .mcp.json, and an mcp.json in the user profile |
stdio, http |
Prompts, unless the server is marked sandboxEnabled |
| Cursor | .cursor/mcp.json per project, ~/.cursor/mcp.json globally |
stdio, SSE, Streamable HTTP |
"Cursor asks for approval before using MCP tools by default" |
| Claude Code | ~/.claude.json for local and user scope, .mcp.json for project scope |
stdio, HTTP, SSE, WebSocket |
Prompts in interactive sessions before using project-scoped servers |
Two details in that table are worth more attention than the rest.
The first is the split between project-level and user-level configuration. A project file is shareable, which is the point: a repository can carry the servers a contributor needs. It also means a file in a checkout can ask the host to run a command. Claude Code documents its answer to that directly, stating that "for security reasons, Claude Code prompts for approval in interactive sessions before using project-scoped servers from .mcp.json files", and provides claude mcp reset-project-choices to clear those decisions. It also notes that non-interactive runs load without prompting, which is the case worth thinking about before putting a server in a shared file.
The second is that the confirmation prompt is a host policy rather than a protocol rule. Sandboxing changes it in Visual Studio Code, where a server marked as sandboxed gets automatic approval on the grounds that execution is already restricted. That is a defensible trade, and it is a trade, so it is worth knowing which side a given host has picked before trusting it with a server that can write files.
The capability checklist most pages are using is out of date
This is the part that makes older comparisons misleading, and it is easy to verify.
Client features are things a host offers back to a server. Roots let a client tell a server which directories to focus on. Sampling lets a server ask the client for a model completion instead of carrying a model SDK of its own. Elicitation lets a server ask the user for specific information mid-request.
As of protocol version 2026-07-28, two of those three are deprecated. The documentation marks roots as "deprecated as of protocol version 2026-07-28 and scheduled for removal", advising that "new implementations should pass directories or files via tool parameters, resource URIs, or server configuration instead". Sampling carries the same status, with the guidance that "new implementations should integrate directly with LLM provider APIs instead". Logging is deprecated too, with stderr or OpenTelemetry named as the replacement.
So a comparison table that grades hosts on roots and sampling support is grading them on features being removed. The client feature that matters going forward is elicitation, and it has two modes worth distinguishing. Form mode sends a schema the client renders as an input form. URL mode hands over a URL for the user to open, and the documentation is explicit that its data "never passes through the client, which makes this mode suitable for sensitive flows such as credential entry or third-party OAuth authorization". It also states the boundary plainly: servers "must not use form mode to request sensitive information such as passwords, API keys, access tokens, or payment credentials".
For URL mode, the client's obligation is spelled out: clients "show the full URL and gather explicit consent before opening it, and never fetch the URL automatically". A host that opens such a URL silently is not implementing the feature, it is bypassing it.
What happens once there are more than a few servers
The failure mode nobody anticipates when adding the first server is arithmetic. Tool definitions occupy context, and the official guidance on client behaviour is blunt about where that ends: when a host reaches dozens of servers with hundreds of tools, "those definitions alone can consume the majority of the context window before the model has even read the user's message".
The documented answer is progressive discovery. The host fetches definitions with tools/list as usual but defers injecting them, exposes a lightweight search_tools meta-tool, and loads full definitions only when needed. The recommendation includes a concrete trigger: implement a threshold as a percentage of the context window, "for example, 1%-5%", and switch once tool definitions pass it.
There is a second pattern for a different cost. With direct tool calling, every intermediate result passes through the model even when it has nothing to do with them. Programmatic tool calling, also called code mode, has the model write a script against generated typed functions, executes it in a sandbox, and returns only the final output. The guidance notes it "requires clients to implement a sandbox environment", which is why few hosts have it.
One caution in that guidance is easy to miss and expensive to learn the hard way. Most providers cache the prompt prefix including the tools array, so "adding or removing tool definitions mid-conversation invalidates that cache, and the resulting miss can cost more tokens than the definitions you removed". A host that connects and disconnects servers per turn can cost more than one that loads everything once.
None of this is visible in a feature matrix. It shows up as a host that stays responsive with twenty servers connected, and one that does not.
The security obligations that belong to the client
The specification assigns a specific list of duties to the client, and they make a usable set of questions to ask of any host.
On configuring a local server, if a host supports one-click setup it "MUST implement proper consent mechanisms prior to executing commands", and the consent dialog must "show the exact command that will be executed, without truncation". A host that shows a truncated command, or a friendly server name in place of the command, is not meeting that bar. The recommended extras include highlighting patterns such as sudo and rm -rf, warning that servers run with the same privileges as the client, and running servers sandboxed with minimal default privileges.
On opening authorization URLs, clients "MUST only allow http:// and https:// schemes", must reject javascript:, data:, file: and vbscript:, and "MUST NOT use shell commands (e.g., cmd.exe, sh, PowerShell) to open URLs". Those requirements exist because a malicious server supplies that URL, and the documented consequence of getting it wrong runs from cross-site scripting to remote code execution.
On fetching OAuth metadata, clients should require HTTPS outside loopback development, and should block private and reserved address ranges including 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 and 169.254.0.0/16. That last range is the cloud metadata endpoint, and the documentation adds a warning worth repeating: "Avoid implementing IP validation manually. Attackers exploit encoding tricks (octal, hex, IPv4-mapped IPv6) that custom parsers often miss."
Where the client stops being the protection
One sentence in the documentation settles more arguments than any feature comparison. On roots, it states that "while roots communicate intended boundaries, they do not enforce security restrictions" and that "actual security must be enforced at the operating system level, via file permissions and/or sandboxing".
The design philosophy section is equally direct about why: the specification says servers "SHOULD respect root boundaries", not that they "MUST enforce" them, "because servers run code the client cannot control".
That is the practical ceiling. A host can ask before each call, show the command it is about to run, and keep credentials out of generated code. It cannot stop a server that has been started from reading whatever the user account can read. Deciding what a server may reach is a filesystem question, answered by where the server is pointed and what permissions the account running it has, not by a checkbox in a client.
Choosing on the work rather than the matrix
Reduced to decisions that actually differ: whether configuration can be scoped per project without being trusted automatically, whether a confirmation prompt exists and can be tuned per tool rather than per server, whether the host degrades gracefully past a dozen servers, and whether the local-server consent dialog shows the whole command.
The remaining cost is the one no host removes, which is that this work happens across windows. A path gets picked in a file listing, a server gets pointed at it in a configuration file, the result is checked in a terminal. That layout question is what a file manager with a built-in terminal addresses, by keeping the folder, the shell and the model in the same place. What that looks like is in Features, how it sits against the other options on the Mac is in Compared with other file managers, and picking up a paused run from a phone is covered in From iPhone and iPad.
What to change first
Before adding another server, open the host's configuration and check which scope each existing one sits in, and whether any project-scoped entry was trusted without being read. Then find the confirmation setting and confirm it is on for anything that writes. Keeping the folder, the shell and the model in one window, which is the problem Atriens is built around, is what removes the switching this work otherwise needs.
Frequently asked questions
Is an MCP client something you download separately?
No. A client is a protocol-level component that a host application creates, one per server it connects to, so connecting three servers means three clients inside one application. What gets chosen is the host: an editor, a terminal agent or a desktop chat application. The specification separates the two because the host owns the user experience while each client owns one connection.
Does a client still need to support roots and sampling?
Both are deprecated as of protocol version 2026-07-28 and scheduled for removal. The documentation directs new implementations to pass directories through tool parameters, resource URIs or server configuration instead of roots, and to integrate with model provider APIs directly instead of using sampling. Elicitation is the client feature that remains.
What should a client do before running a local server for the first time?
Show the exact command, untruncated, and get explicit approval. The security guidance requires that consent step for one-click local server configuration, and recommends flagging patterns such as sudo and rm -rf, warning that the server runs with the same privileges as the client, and launching it with restricted filesystem and network access.
Why does adding more servers make the model worse rather than better?
Tool definitions take up context. Once dozens of servers expose hundreds of tools, the definitions can fill most of the context window before the model reads the request. The documented fix is progressive discovery, where definitions are fetched but not injected and a search tool loads them on demand, with a switching threshold suggested at one to five percent of the context window.
Can a client stop a server from reading files outside a folder?
Not by itself. The documentation states that roots communicate intended boundaries but do not enforce security restrictions, and that actual security must be enforced at the operating system level through file permissions or sandboxing. A server runs code the client cannot control, so limiting reach is a filesystem and account question.