What MCP solves
An AI application often needs information and actions outside the model: read a project file, query a catalog, inspect an issue, or call an internal service. Building each integration directly into every AI host creates repeated connection code, tool schemas, discovery logic, and authentication work.
The Model Context Protocol (MCP) defines a standard way for an AI host to connect to servers that expose context and capabilities. A compatible server can publish tools, resources, and prompts. A compatible host can discover those features and decide how to present or use them.
MCP does not make a model more intelligent. It does not grant access by itself, and it is not an authorization shortcut. It standardizes the conversation between an AI application and an integration.
This guide explains:
- the host–client–server architecture;
- connection lifecycle and capability discovery;
- stdio and Streamable HTTP transports;
- tools, resources, and prompts;
- the concept behind local and remote setup;
- authorization and security boundaries;
- a practical troubleshooting order;
- when a direct API is simpler.
The details below follow the official MCP documentation and the versioned 2026-07-28 specification current on this article’s publication date. Protocol revisions can change message names or negotiation details, so pin and check the version your client and server support.
MCP in one sentence
MCP is a JSON-RPC-based protocol that lets an AI host create isolated client connections to servers that offer discoverable context and actions.
Think of it as an adapter contract:
AI host
├─ MCP client connection ── server: project files
├─ MCP client connection ── server: issue tracker
└─ MCP client connection ── server: internal catalog
The host owns the user experience, model integration, permissions policy, and consent. Each client communicates with one server. Each server focuses on a particular data source or capability.
Host, client, and server
These terms describe protocol roles, not necessarily separate computers.
Host
The host is the AI application: an editor, desktop assistant, research product, or custom agent service. It:
- creates and manages MCP clients;
- decides which servers may connect;
- keeps security boundaries between servers;
- coordinates the model and context;
- presents consent and authorization UI;
- controls what data can flow to each server.
One host may connect to many servers. It should not casually combine private output from one server into a call to another.
Client
An MCP client is the host-side protocol component for one server connection. It:
- negotiates protocol version and capabilities;
- sends requests and receives responses;
- routes notifications;
- manages subscriptions and connection state;
- preserves the security boundary for that server.
When a desktop app lists five configured MCP servers, it generally manages five client connections.
Server
An MCP server exposes a focused set of features. It can run as a local child process or a remote network service. It may wrap a filesystem, SaaS API, database, knowledge base, or business service.
A server:
- advertises supported protocol capabilities;
- lists and executes tools;
- lists and reads resources;
- lists and renders prompt templates;
- validates requests and enforces its own authorization;
- returns results and errors.
The server should not trust the host merely because it speaks MCP. It must still authenticate and authorize network requests, validate arguments, protect downstream services, and rate-limit expensive work.
The two protocol layers
Data layer
The data layer defines JSON-RPC messages and protocol meaning: requests, responses, errors, notifications, discovery, tools, resources, prompts, and related client capabilities.
JSON-RPC provides envelopes and request IDs. MCP adds methods, schemas, capability rules, and lifecycle behavior.
Transport layer
The transport layer defines how those messages move: process streams or HTTP requests and responses, including framing, connection behavior, and transport-level authorization.
Protocol semantics should remain the same across transports. Transport choice changes deployment and security, not what a tool means.
Connection lifecycle
Older MCP explanations often describe a one-time initialization handshake. The 2026-07-28 specification introduces per-request metadata and capability discovery details. Do not copy message sequences from an old tutorial into a new implementation without checking your negotiated protocol revision.
Conceptually, the lifecycle remains:
1. Establish transport
For stdio, the client launches the server process and connects its standard input and output. For remote MCP, the client contacts the configured HTTPS endpoint.
2. Discover compatibility
The client and server establish supported protocol versions and capabilities. In the current specification, clients attach protocol version and client capability metadata to requests, and servers expose discovery information.
Both sides must honor negotiated capabilities. A server must not assume the client supports elicitation or model sampling. A client must not call a feature the server did not advertise.
3. Discover features
The client can list tools, resources, prompt templates, and other supported features. Discovery lets a host update UI and model-visible schemas without hard-coding every operation.
4. Exchange requests
The host reads resources, retrieves prompts, or allows the model to request tools. Long operations may report progress; resources may support subscriptions and update notifications.
5. Cancel, disconnect, or terminate
Clients need timeout and cancellation behavior. A local server process must be cleaned up. Remote sessions and streams must close according to their transport rules. A cancelled request should not leave an unknown write running without a way to reconcile state.
Standard transports
stdio: local child process
With stdio, the host starts a command and exchanges newline-delimited JSON-RPC over the process’s standard input and output.
Use stdio when:
- the server should run on the same machine;
- it needs controlled access to local files or developer tools;
- process lifetime should follow the host connection;
- network deployment would add needless work.
The server must reserve stdout for protocol messages. Send logs to stderr. One accidental console.log or print statement on stdout can corrupt message framing.
Pass secrets through a protected environment or another host-supported secret mechanism, not command arguments that appear in process lists and config screenshots. Restrict filesystem roots and run the process as a low-privilege operating-system user.
Streamable HTTP: remote service
With Streamable HTTP, the client sends messages with HTTP POST to one MCP endpoint. Responses may be JSON or a request-scoped Server-Sent Events stream. The transport supports remote deployment and standard HTTP infrastructure.
Use it when:
- many users or hosts share a service;
- the integration lives behind a network boundary;
- central updates and monitoring matter;
- OAuth-based delegated authorization is required.
Require HTTPS. Validate Origin where the specification requires it, bind development servers safely, enforce request-size and rate limits, and do not pass bearer tokens to an unintended upstream.
Custom transports
The protocol permits custom transports if they preserve JSON-RPC message format, protocol message patterns, per-request metadata, and bidirectional behavior. A custom transport increases interoperability work. Choose one only for a concrete deployment constraint.
Tools, resources, and prompts
These primitives are easy to blur. They have different control and risk profiles.
Tools: perform an operation
A tool is a schema-defined function an AI model can request. Examples:
search_issues(query, project);get_order_status(order_id);create_draft_comment(issue_id, body);run_test_suite(target).
Tools are model-controlled in the sense that the model may choose one, but the host and server still decide whether to allow and execute it.
A tool definition needs a precise description and JSON Schema inputs. The server validates those inputs and returns typed content or an error. It must enforce access control and side-effect policy.
Prefer narrow tools. delete_record with an arbitrary collection name is riskier than a business operation that targets one allowed resource type and supports a preview.
Resources: expose context
A resource is identifiable data that a client can list and read, commonly through a URI. Examples:
- a file;
- a database schema;
- a product manual;
- a repository document;
- a generated status report.
Resources are a good fit for context that users or applications select. Resource templates can describe parameterized URIs. Servers may support subscriptions so clients receive change notifications.
“Read-only” does not mean harmless. A resource can contain personal data, secrets, proprietary text, or prompt injection. The host must control what enters model context and where it may be sent.
Prompts: reusable interaction templates
A prompt is a server-provided message template or workflow entry point. It can accept arguments and return structured messages for the host to use.
Prompts are generally user-selected rather than automatically invoked by the model. They can provide tasks such as “review this change,” “summarize this incident,” or “prepare a release note” with consistent inputs.
Treat prompt text from a server as untrusted integration content. The host decides how it fits with higher-priority policy.
A practical distinction
Ask:
- Does it do something? It is probably a tool.
- Does it supply data identified by a URI? It is probably a resource.
- Does it shape an interaction the user chooses? It is probably a prompt.
Do not expose every API endpoint as a tool and every database row as a resource. Design for tasks, permissions, and usable context.
Other client and utility capabilities
MCP can support server requests for client-side behavior such as sampling through the host’s model, eliciting information from a user, or discovering allowed filesystem roots. It also includes utilities such as progress, cancellation, logging, and argument completion depending on protocol version and negotiated capabilities.
These reverse-direction features deserve special care. A server requesting model sampling should not gain invisible access to all host context. Elicitation must present clear UI and must not trick users into disclosing credentials. Roots describe allowed boundaries; they are not permission to escape them.
Implement only the features the product needs. Capability negotiation is not a request to enable everything.
Local setup: the concept
A local MCP setup has four parts:
- an installed server and its runtime;
- an exact command that starts it;
- environment variables and arguments;
- a host configuration that points to that command.
A conceptual configuration looks like:
{
"mcpServers": {
"project-files": {
"command": "server-command",
"args": ["--root", "/absolute/path/to/project"],
"env": {
"SERVICE_TOKEN": "${SERVICE_TOKEN}"
}
}
}
}
The exact file name and interpolation support depend on the host. Some hosts do not expand ${SERVICE_TOKEN}; others have their own secret store. Follow that host’s documentation.
Local setup checklist
- Install a server from a source you trust.
- Read its README and review requested access.
- Use absolute executable and filesystem paths.
- Start it manually once and check stderr.
- Limit roots to the smallest needed directories.
- Provide a scoped token, not a personal admin token.
- Test the server with MCP Inspector.
- Add it to the host and fully restart if required.
- Review the listed tools before allowing model use.
On Windows, path quoting, executable extensions, and inherited environment variables are frequent sources of failure. Verify the same command under the same user account as the host.
Remote setup: the concept
A remote MCP setup points the host at an HTTPS endpoint and completes any required authorization.
Host → https://service.example.com/mcp
├─ TLS
├─ OAuth discovery and authorization
├─ scoped access token
└─ Streamable HTTP messages
Confirm:
- the endpoint is the official MCP URL, not a marketing page;
- TLS validation is enabled;
- redirects do not leak authorization headers;
- OAuth scopes match required tools and resources;
- tokens are stored by the host’s protected credential facility;
- tenant and resource authorization is checked server-side;
- egress policy allows the endpoint;
- the server’s privacy and retention terms fit your data.
Remote MCP is not safe simply because OAuth succeeded. OAuth identifies delegated access; tool input and output still require validation and policy.
Remote authorization
For HTTP transports, the current authorization specification builds on OAuth 2.1.
At a high level:
- the client contacts the MCP resource server;
- an unauthenticated response points to Protected Resource Metadata;
- the client discovers the authorization server and supported details;
- the user authenticates and grants appropriate scopes;
- the client uses PKCE and a resource indicator in the authorization flow;
- the authorization server issues a token bound for the intended resource;
- the MCP server validates issuer, audience, expiry, scopes, and other claims on every request.
The resource server must not accept a token meant for another service. Scope requests should follow least privilege. Clients must protect authorization codes, redirect URIs, and tokens.
For stdio, the HTTP authorization flow normally does not apply. The specification recommends obtaining credentials from the environment. The local server still needs least-privilege credentials and operating-system isolation.
Authentication answers who is involved. Authorization must still answer whether this identity may use this tool against this exact project, account, file, or record.
The confused-deputy and token-passthrough problems
An MCP server often sits between a host and another API. That creates two common risks.
Confused deputy
A server has powerful downstream access and is tricked into using it for a caller who lacks that permission. Prevent this by binding operations to the authenticated subject and tenant, checking resource-level rights, and refusing caller-controlled destination changes.
Token passthrough
A server accepts a token without validating that the token was issued for that server, then forwards it to an upstream API. This can bypass audience boundaries and leak credentials.
Validate tokens for your own resource. Use a proper delegated downstream flow or server-held scoped credentials where appropriate. Do not treat any bearer token as universal proof.
Security model: four boundaries
1. User to host
Authenticate users. Make server connection and tool approval understandable. Show the operation and target, not only a server name.
2. Host to server
Use approved server identities, TLS for remote connections, version negotiation, capability limits, and per-server context isolation. Do not let one server read another server’s output unless the product intentionally shares it.
3. Model to tool
Treat the proposed call as untrusted. Validate schema, authorize the resource, rate-limit it, and require approval for risky side effects. Tool annotations and descriptions can be false.
4. Server to downstream system
Use scoped credentials, parameterized queries, allowlisted destinations, output sanitization, timeouts, audit logs, and idempotency for writes.
Prompt injection crosses these boundaries through ordinary text. A repository file, issue comment, web page, or resource can tell the model to exfiltrate data. Labeling it “context” does not make it trustworthy.
Designing a safe MCP server
Start from tasks, not from your entire API surface.
Define the audience and identity
Will the server run for one local developer, employees in one tenant, or third-party customers? Map MCP caller identity to downstream identity explicitly.
Inventory operations by risk
Classify each candidate as read-only, reversible write, irreversible write, financial, privileged, or data-exporting. Begin with selected reads.
Write narrow schemas
Use enums, length limits, format checks, bounded arrays, and explicit resource IDs. Reject unknown fields when possible. Never concatenate tool input into shell commands or SQL.
Return small, useful results
Support filters and pagination. Remove secrets and unnecessary personal data. Include stable IDs and version information so an agent can cite and reconcile results.
Make writes safe to retry
Accept idempotency keys. Return operation IDs. Provide status lookup. If a timeout leaves the result unknown, let the client reconcile before repeating.
Expose honest errors
Distinguish invalid input, unauthorized, forbidden, not found, rate limited, downstream unavailable, and internal failure. Do not return a successful-looking text blob when execution failed.
Log decisions without collecting everything
Record caller, tool, target, outcome, latency, approval reference, and trace ID. Redact tokens and sensitive content. Apply a documented retention period.
Testing with MCP Inspector
The official MCP Inspector is the first diagnostic tool for servers. It provides web, command-line, and terminal interfaces.
For a local stdio server, the pattern is:
npx @modelcontextprotocol/inspector server-command --arg value
For remote Streamable HTTP:
npx @modelcontextprotocol/inspector --server-url https://service.example.com/mcp --transport http
The current Inspector documentation requires Node.js 22.19.0 or newer. Check the live page before installation because tooling requirements change.
Test more than a successful tool call:
- discovery and supported versions;
- expected tools, resources, and prompts;
- invalid and missing arguments;
- unauthorized and forbidden requests;
- not-found resources;
- concurrent calls;
- cancellation and timeouts;
- duplicate write requests;
- large outputs;
- hostile text in resource and tool results.
Turn stable checks into CI with the Inspector CLI or direct protocol tests.
Troubleshooting in the right order
1. Confirm the process or endpoint
For stdio, run the exact command manually under the same user. Verify the executable, working directory, absolute paths, runtime version, and environment.
For HTTP, check DNS, TLS, proxy, endpoint path, status code, and whether authentication is required.
2. Inspect logs without breaking framing
Local server diagnostics belong on stderr. If stdout contains banners or debug prints, JSON-RPC parsing will fail.
For remote servers, correlate request IDs and traces. Never log bearer tokens.
3. Use Inspector before blaming the host
If Inspector cannot initialize, list capabilities, or call a basic tool, the problem is likely in server startup, transport, auth, or protocol behavior. Fix that before editing an editor’s config repeatedly.
4. Check protocol version and capabilities
Client and server may implement different revisions. Inspect discovery and request metadata. A feature cannot be used unless both sides support the needed capability.
5. Validate configuration ownership
Host config formats differ. Confirm command quoting, arrays vs strings, environment handling, server name, transport, URL, headers, and whether the host read the expected file.
6. Restart the host
Many hosts load server configuration only at startup. Fully exit and reopen after changes.
7. Separate auth from authorization
A 401 usually means authentication or token validation. A 403 means the identity is known but not allowed. A tool-level “not found” may intentionally hide forbidden resources. Inspect server logs and OAuth metadata.
8. Reproduce one method
Test discovery, then listing, then one read-only call. Do not debug sampling, subscriptions, and a write tool at once.
Frequent local failures
- relative path resolved from an unexpected working directory;
- runtime not on the host’s PATH;
- missing environment variable;
- logs written to stdout;
- server exits after startup;
- filesystem root excludes the requested path;
- Windows quoting or slash differences.
Frequent remote failures
- wrong endpoint or old SSE transport setting;
- TLS or corporate-proxy issue;
- OAuth redirect mismatch;
- token audience or scope mismatch;
Originrejection;- request timeout during a long tool call;
- server available publicly but downstream private service unavailable.
MCP vs a direct API
MCP and APIs are not rivals at the same layer. An MCP server often wraps one or more APIs.
Use a direct API integration when
- one application calls one known service;
- the workflow is deterministic;
- you need the service’s full domain model;
- strict typed contracts and generated clients matter;
- you do not need AI-host discovery;
- fewer moving parts are a priority.
Your application can call the API, validate the response, and present selected data to a model. This is often the right first implementation.
Use MCP when
- the same capability should work across compatible AI hosts;
- tools and resources need runtime discovery;
- users choose among integrations;
- an AI application needs a standard connection and consent model;
- you are building an integration product for multiple hosts.
Use both
A common design is:
AI host → MCP server → existing typed service client → business API
The MCP server translates protocol concepts into domain operations. The business API remains the source of authorization and records.
Do not mechanically mirror hundreds of endpoints as hundreds of model tools. Curate task-level operations with smaller inputs and clear risk.
When not to use MCP
Skip MCP when a model does not need the integration, when one fixed call is enough, or when the host cannot provide safe consent and credential storage.
Also pause when:
- a server asks for broad admin credentials for a narrow task;
- sensitive data would cross unapproved processors or regions;
- tool side effects cannot be previewed or reconciled;
- the server is unmaintained or opaque;
- a direct library already provides a smaller trusted boundary;
- your protocol versions cannot interoperate;
- operating another long-lived service has no product benefit.
Standards reduce connection friction. They do not remove deployment, security, privacy, or maintenance cost.
A practical review checklist
- [ ] Host, client, and server responsibilities are documented.
- [ ] Protocol revision is pinned and compatibility tested.
- [ ] Transport matches local or remote needs.
- [ ] Server source and dependencies are reviewed.
- [ ] Tools are narrow, typed, and risk-rated.
- [ ] Resources exclude unnecessary sensitive fields.
- [ ] Prompts cannot override host policy.
- [ ] Per-user and per-resource authorization is enforced server-side.
- [ ] OAuth tokens are audience-bound and scoped.
- [ ] stdio credentials are protected and least-privilege.
- [ ] Remote TLS, Origin handling, timeouts, and rate limits are configured.
- [ ] Risky writes require informed approval and idempotency.
- [ ] Logs avoid secrets and have a retention policy.
- [ ] Inspector tests cover failure and attack cases.
- [ ] Users can disconnect a server and revoke credentials.
FAQ
Is MCP only for desktop apps?
No. Hosts and servers can be local or cloud-based. Transport and authorization design determine the deployment.
Does MCP send my entire conversation to every server?
It should not. The host controls what each request contains. A well-designed host isolates server connections and shares only the data required for the chosen operation.
Is an MCP tool automatically safe because its schema is valid?
No. Schema validation checks shape, not permission or intent. The server must authorize the target and the host may need human approval.
Can MCP replace OAuth?
No. Remote MCP defines how OAuth-based authorization fits the transport. It does not eliminate identity providers, token validation, scopes, or resource authorization.
Why does a local stdio server fail with a JSON parse error?
Check stdout first. Protocol messages must not be mixed with log lines. Send diagnostics to stderr, then verify command paths and runtime versions.
Should I expose resources or tools for read operations?
Use resources for identifiable context that clients or users read and tools for model-selected operations with arguments. A search operation often fits a tool; a known document fits a resource.
Does MCP include the AI model?
No. The host chooses and operates the model. MCP connects the host to external context and actions.
Related reading on Learn
- Browse the AI learning hub.
- Compare provider integration choices in OpenAI vs Anthropic APIs.
- Improve instruction design with prompt engineering for code.
- See a coding host workflow in the Cursor AI guide.
Takeaways
MCP separates an AI host from integration servers through one client connection per server. The data layer defines JSON-RPC features; transports carry them locally through stdio or remotely through Streamable HTTP. Tools act, resources supply context, and prompts package user-selected interaction patterns.
The protocol creates interoperability, not automatic trust. Hosts must preserve server boundaries and user consent. Servers must authenticate, authorize, validate, limit, and audit. Models must never become the permission layer.
Use MCP when a capability should be discoverable and reusable across AI hosts. Use a direct API when one known application-to-service call is the simpler contract.
Continue learning
- AI agents explained ? understand the loop MCP serves
- Agent Skills guide ? reusable instructions, not external tools
- Agent Plugins guide ? package Skills and MCP together
- RAG vs agents vs MCP vs A2A ? choose the right layer