MCP Server Development
A spec-current guide to MCP server development after the 2026-07-28 revision, covering the stateless protocol change, the modern-vs-legacy split, server primitives, transports, authorization and the named security failure modes, plus what a server actually costs to build and maintain.
Key takeaways 5
Five things to know before scoping an MCP server build against the current 2026-07-28 spec revision.
- Handshake removed, replaced by per-request negotiation The initialize and notifications/initialized handshake is gone. Every request now carries protocolVersion and capabilities in _meta instead. Most existing MCP guides still describe the retired handshake era as current, which is the main source of outdated advice.
- server/discover is server-mandatory, client-optional Servers MUST implement server/discover to advertise supported versions, capabilities and identity, but calling it stays optional for clients. It does not replace the removed handshake as a required client step. Per-request _meta negotiation does that.
- Deprecated is not removed Sampling, Roots and Logging stay fully functional and normative through the deprecation window, with earliest removal eligibility no sooner than 2027-07-28. Treat migration off them as deliberate planning, not an urgent fix.
- RFC 9207 validation: client MUST, server SHOULD Issuer validation is not symmetric: MCP clients MUST validate a present iss value before redeeming an authorization code, while authorization servers including iss remain only a SHOULD, expected to strengthen to MUST in a future revision.
- An ongoing commitment, not a one-time build Scope drivers such as primitive count, authorization and transport choice set the initial build cost, but tracking each new spec revision's deprecations is a recurring cost. Weigh that against buying an existing server first.
In short: An MCP server exposes Resources, Tools and Prompts to an AI model over a stateless, per-request-negotiated protocol. The current revision, dated 2026-07-28, removed the old connection-scoped initialize handshake and replaced it with per-request _meta version and capability fields carried on every call. The revision before this one, 2025-11-25, still used that handshake, so any guidance written against 2025-11-25 or earlier describes an initialize step the current revision no longer has.
What an MCP server is and what it actually exposes
An MCP server is a program that offers a defined set of capabilities to an AI model over the Model Context Protocol, in a client-host-server architecture where a host "creates and manages multiple clients, with each client having a 1:1 relationship with a particular server" (MCP architecture page). Servers offer any of the following features to clients: "Resources: Context and data, for the user or the AI model to use; Prompts: Templated messages and workflows for users; Tools: Functions for the AI model to execute" (MCP specification), plus optional extensions beyond the core protocol for functionality the three primitives do not cover. A server exposing one read-only Resource and nothing else is a complete, conformant server at the primitive level, and so is one exposing forty Tools; every server still owes the protocol its own baseline obligations regardless of primitive count, among them implementing server/discover (covered below). The binding is also deliberate isolation, since a server "receive[s] only necessary contextual information" and full conversation history "stays with the host" (MCP architecture page). The difference between an AI agent and a bare LLM is largely this tool and context layer, and an MCP server is where it lives.
The modern vs legacy split - which era you are building for
The single most consequential fact for anyone starting a build today is that MCP now splits into two eras. The MCP versioning guide confirms "the current protocol version is 2026-07-28". The MCP versioning page defines the terms this article uses for the split, under its Terminology heading: Modern (protocol versions that convey version, identity and capabilities as per-request metadata, revision 2026-07-28 and later), Legacy (protocol versions that establish a session with an initialize handshake, 2025-11-25 and earlier), and Dual-era (an implementation that supports both). Any guidance dated to 2025-11-25 or earlier is describing that legacy initialize step, since the current revision does not have it.
What "stateless" actually removed - the handshake, not the protocol
The MCP changelog states: "Make MCP stateless: remove the initialize/notifications/initialized handshake. Every request now carries its protocol version and client capabilities in _meta (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities)." A version mismatch returns an UnsupportedProtocolVersionError rather than failing a connection-level handshake. This matters for AI agent architecture patterns that lean on MCP: the protocol no longer has a connection lifecycle to reason about, only a request lifecycle.
server/discover is server-mandatory, optional for the client
The changelog: "Add server/discover: servers MUST implement this RPC to advertise their supported protocol versions, capabilities, and identity. Clients MAY call it before any other request for up-front version selection, or use it as a backward-compatibility probe on STDIO" (MCP changelog). Calling server/discover is optional for a client, with a named use beyond up-front version selection: a backward-compatibility probe on stdio. What replaced the removed handshake as the thing every request must carry is per-request _meta, not server/discover. The server-side obligation is unambiguous regardless: implement server/discover even if no expected client ever calls it.
Migration checklist: 2025-11-25 to 2026-07-28
Server and client migrations are different work. The server list below is the article's core artifact for anyone building a server; the client list after it is shorter, for a team that also owns the client side and needs to know which obligations are theirs.
Server migration, 17 items
- Stop minting and reading the Mcp-Session-Id header and drop protocol-level sessions; tools/list, resources/list and prompts/list must no longer vary per connection. Move any cross-call state to explicit, server-minted handles passed as ordinary tool arguments.
- Remove the initialize/notifications/initialized handshake. Read protocol version and client capabilities from _meta on every request (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities), and SHOULD emit io.modelcontextprotocol/serverInfo in each result's _meta. Return UnsupportedProtocolVersionError on a mismatch.
- Implement server/discover.
- Remove the HTTP GET endpoint and resources/subscribe/resources/unsubscribe. Implement subscriptions/listen as a single long-lived POST-response stream, acknowledge the client's opt-in types, and tag notifications with io.modelcontextprotocol/subscriptionId. Keep request-scoped notifications on the response stream of their own request.
- Remove ping and logging/setLevel, and stop handling notifications/roots/list_changed. Read log level per request from io.modelcontextprotocol/logLevel in _meta, and MUST NOT emit notifications/message for a request that omits that field.
- If tasks were used, move them to the io.modelcontextprotocol/tasks extension, replace blocking tasks/result with tasks/get polling, accept tasks/update, drop tasks/list, and note that a server may now return task handles unsolicited.
- Stop sending server-initiated roots/list, sampling/createMessage and elicitation/create. Return InputRequiredResult with resultType: input_required and an inputRequests field, and accept inputResponses on the client's retry.
- Add the required resultType field to every result: complete normally, input_required for MRTR interim results.
- Remove SSE stream resumability and message redelivery; stop emitting SSE event IDs and stop honouring Last-Event-ID.
- Optionally advertise an extensions map in ServerCapabilities.
- SHOULD return tools from tools/list in a deterministic order.
- Validate the required Mcp-Method and Mcp-Name headers on Streamable HTTP POST requests and reject a request that lacks them with 400 Bad Request. Support custom headers from tool parameters via x-mcp-header.
- Return ttlMs and cacheScope on results from tools/list, prompts/list, resources/list, resources/read and resources/templates/list, via the new CacheableResult interface.
- Change the resource-not-found error code from -32002 to -32602.
- Renumber HeaderMismatch from -32001 to -32020, MissingRequiredClientCapability from -32003 to -32021 and UnsupportedProtocolVersion from -32004 to -32022, and keep any new MCP codes inside -32020 to -32099.
- May publish inputSchema and outputSchema using any JSON Schema 2020-12 keywords, and any JSON value in structuredContent, subject to the new $ref resolution requirements and composition-keyword resource bounds.
- Stop emitting notifications/elicitation/complete and stop setting elicitationId on URL-mode elicitation requests; encode a correlation identifier in requestState instead.
Client migration, 19 items
- Stop sending Mcp-Session-Id and stop assuming list endpoints vary per connection.
- Stop calling initialize and sending notifications/initialized. Put protocolVersion and clientCapabilities in _meta on every request, SHOULD send clientInfo, and handle UnsupportedProtocolVersionError.
- Calling server/discover stays optional: MAY use it for up-front version selection, or as a backward-compatibility probe on stdio.
- Stop using the HTTP GET endpoint and resources/subscribe/resources/unsubscribe. Open subscriptions/listen, opt in to the relevant change types, and read subscriptionId tags.
- Stop calling ping and logging/setLevel and stop sending notifications/roots/list_changed. Set log level per request via _meta, and expect no notifications/message on a request that omits it.
- If tasks were used, negotiate the tasks extension, poll tasks/get instead of blocking on tasks/result, send tasks/update, stop calling tasks/list, and handle unsolicited task handles.
- Stop expecting server-initiated requests; handle InputRequiredResult and retry the original request with inputResponses.
- MUST treat results from earlier-protocol servers that omit resultType as complete.
- MUST re-issue a broken in-flight request as a new request with a new request ID; stop relying on Last-Event-ID for redelivery.
- Optionally advertise an extensions map in ClientCapabilities.
- Send the required Mcp-Method and Mcp-Name headers on every Streamable HTTP POST, or the server rejects the request.
- Consume ttlMs and cacheScope to cache list and read results, and respect public versus private scope.
- Recognise resource-not-found as -32602 rather than -32002.
- MUST validate a present iss against the recorded issuer before redeeming the authorization code.
- MUST specify an appropriate application_type during Dynamic Client Registration.
- MUST key persisted credentials by the issuer identifier, MUST NOT reuse them with a different authorization server, and MUST re-register when the authorization server changes.
- Accept any JSON Schema 2020-12 keywords in inputSchema and outputSchema and any JSON value in structuredContent.
- Stop relying on notifications/elicitation/complete and elicitationId; learn the outcome of an out-of-band interaction by retrying the original request.
- Recognise the renumbered error codes -32020, -32021 and -32022.
Why a server may still need to speak both eras at once
If a server has to serve clients built against 2025-11-25 or earlier, the spec does not pretend that problem away: a client that needs to interoperate with both kinds of servers detects the server's era using transport-specific mechanics, and a dual-era server in turn selects its behavior from how the client opens the connection, against a documented compatibility matrix (MCP versioning page). A server for a closed client population can target the modern era only; one for an open ecosystem should plan for dual-era support until the legacy population ages out.
Transports in the 2026-07-28 revision
A transport is deliberately a thin layer: "Protocol semantics are identical on every transport. A transport is a binding: it defines how messages are framed and delivered, how request metadata is carried, and how cancellation and termination are signaled. It does not define what the messages mean" (MCP transports page).
stdio and Streamable HTTP, the two standard bindings
Two bindings are standard. stdio is "newline-delimited messages over the standard streams of a client-launched subprocess"; Streamable HTTP means "each message is an HTTP POST to a single MCP endpoint" with replies arriving "as a JSON object or a request-scoped SSE stream" (MCP transports page). Custom transports are permitted if they preserve the JSON-RPC message format, the message patterns and the per-request metadata model.
Choosing stdio or Streamable HTTP
The two bindings fit different deployment shapes. stdio suits a server the client itself launches as a subprocess on the same machine, with no network exposure; Streamable HTTP suits a server reached over a network, possibly by more than one client. The choice also decides how the server gets credentials: an authorization-supporting server on stdio "SHOULD NOT" follow the MCP authorization specification and should retrieve credentials from the environment instead, while an HTTP-based server that supports authorization "SHOULD conform" to it (MCP authorization page). A server with no reason to be reached over a network is usually simpler to ship on stdio; a server that multiple remote clients need to reach needs Streamable HTTP and, if it handles real credentials, the full authorization mechanism.
What Streamable HTTP lost this revision - session IDs and SSE resumability
The changelog records removal of "protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport", so list endpoints such as tools/list "no longer vary per-connection"; servers needing cross-call state instead use "explicit, server-minted handles passed as ordinary tool arguments" (MCP changelog). The revision also removes "SSE stream resumability and message redelivery (the Last-Event-ID header and SSE event IDs)". A broken response stream now loses the in-flight request, and the client "MUST re-issue it as a new request with a new request ID". Server code that persists a session ID, or expects a dropped stream to resume, needs rewriting against this revision.
HTTP+SSE is deprecated, not gone
HTTP+SSE, the older separate transport, has been on a deprecation path since revision 2025-03-26 and was formally reclassified in 2026-07-28: "reclassify the HTTP+SSE transport (deprecated since protocol version 2025-03-26) as Deprecated under the feature lifecycle policy... Migrate to Streamable HTTP" (MCP changelog). Existing servers running it are not broken, but sit on the same twelve-month deprecation clock described below.
Server primitives, and where sampling, roots and elicitation live now
The published client-feature list in the current revision names only one client capability: "Elicitation: Server-initiated requests for additional information from users" (MCP specification). Sampling and Roots are no longer on that index list, which is where a lot of confusion starts.
Deprecated features versus removed RPCs - two different clocks
Being off the index list is not the same as being removed from the spec, and "deprecated" and "removed" describe different things here. The features Sampling, Roots and Logging are deprecated, not removed: the changelog's deprecations section states they "remain fully functional during the deprecation window but new implementations should not add support for them", with stated migration paths: directories or files via tool parameters, resource URIs, or server configuration instead of Roots, integrate directly with LLM provider APIs instead of Sampling, log to stderr or use OpenTelemetry instead of Logging (MCP changelog). Separately, this same revision removed named RPCs and notifications outright: ping, logging/setLevel and notifications/roots/list_changed are gone, replaced by per-request log-level metadata in _meta and by the MRTR pattern (MCP changelog). A feature can lose one of its RPCs to outright removal while the feature itself is only deprecated.
The MCP versioning guide sets the deprecation clock: deprecated features "remain in the specification for at least twelve months, or at least ninety days under the policy's expedited-removal exception, before they become eligible for removal". Earliest removal for Sampling, Roots and Logging is the first spec revision released on or after 2027-07-28. The expedited-removal exception requires a vulnerability with a published security advisory or documented in-the-wild exploitation for which no in-place mitigation exists (MCP feature lifecycle policy); the published rationale for these three deprecations is an ordinary migration note, not a security rationale, so on the rationale published today the exception does not apply. A server already implementing Sampling or Roots keeps working through that window; a new server has no reason to add either, and no server, new or existing, should call ping or logging/setLevel or expect notifications/roots/list_changed, since those are removed regardless of the feature-level clock.
A fourth, easily missed deprecation entry sits inside Sampling: the changelog also reclassifies the includeContext values "thisServer" and "allServers" as Deprecated. Unlike the three features above, these values were already soft-deprecated back in protocol version 2025-11-25, not 2026-07-28, and their earliest removal is not a fixed date: they will be removed no later than the Sampling feature itself (MCP changelog). Omit the field, or use "none".
MRTR replaces server-initiated requests
What changed mechanically is how a server asks a client for more input. The old model let servers send requests such as roots/list, sampling/createMessage or elicitation/create. Multi Round-Trip Requests replaces that: "Servers return an InputRequiredResult (resultType: "input_required") whose inputRequests field carries the requests for the additional information needed to process the request. Clients respond with inputResponses on a retry of the original request providing the requested information" (MCP changelog). A server needing a Sampling call, an Elicitation answer or a Roots listing requests it inside its own reply, via InputRequiredResult, rather than opening a new server-to-client request.
Authorization - OAuth 2.1, RFC 9728 and RFC 9207
Authorization in MCP is a layer a server opts into, not a mandatory feature of every server.
Authorization is optional, and stdio should not use the HTTP flow
The authorization page states plainly: "Authorization is OPTIONAL for MCP implementations." Where it is supported, the split by transport is normative: "Implementations using an HTTP-based transport SHOULD conform to this specification. Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment" (MCP authorization page). Alternative transports "MUST follow established security best practices for their protocol". A stdio server pulling credentials from the environment is conformant, not corner-cutting; layering OAuth on top of stdio is not. Anyone securing AI agents in production needs this split to be a deliberate design decision.
Resource Indicators and audience validation - the no-passthrough rule
The overview requirements anchoring HTTP-based authorization include unconditional MUSTs: "MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC9728). MCP clients MUST use OAuth 2.0 Protected Resource Metadata for authorization server discovery" (MCP authorization page). Clients also "MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707 to explicitly specify the target resource for which the token is being requested", binding every request to the server's canonical URI, sent "regardless of whether authorization servers support it" (MCP authorization page). The mirror rule on the server side is equally unconditional: servers "MUST validate that access tokens were issued specifically for them as the intended audience".
RFC 9207 issuer validation splits by party, and depends on the authorization server acting honestly
This detail is not symmetric, and the asymmetry runs in both directions rather than favoring one side. On the authorization-server side, including the iss parameter is currently only a SHOULD: "MCP authorization servers SHOULD include the iss parameter in authorization responses, including error responses" (MCP authorization page). A future revision "is expected to upgrade authorization server inclusion of iss from SHOULD to MUST"; implementers are encouraged to emit and validate iss now to ease that transition (MCP authorization page). On the client side, clients "MUST validate a present iss against the recorded issuer before redeeming the authorization code" (MCP changelog), but that MUST only bites once an iss value is actually present. The security best practices page states the limit directly, for the mix-up attack this validation mitigates: the mitigation "depends on honest authorization servers emitting iss; it provides no protection against an honest server that does not" (MCP security best practices page). Neither side of this pair is simply the stronger one; the client-side check only closes the gap once the authorization server actually sends iss.
One deprecation worth flagging while planning client registration: the OAuth 2.0 Dynamic Client Registration Protocol is deprecated as a client registration mechanism in favor of Client ID Metadata Documents, a change tracked as GitHub PR #2858. Dynamic Client Registration "remains available for backwards compatibility with authorization servers that do not support Client ID Metadata Documents" (MCP changelog).
The security failure modes named in the spec
The security best practices page lists eleven named attack classes in published order: Confused Deputy Problem, Token Passthrough, Server-Side Request Forgery, State Handle Hijacking, Local MCP Server Compromise, OAuth Authorization URL Validation, stdio Transport Security in Proxy Scenarios, Mix-Up Attacks, Localhost Redirect URI Impersonation, CIMD Trust Policies and Scope Minimization (MCP security best practices page). Not all eleven are MCP-server obligations: several, Mix-Up Attacks among them, place their normative mitigation on the MCP client or on the OAuth authorization server rather than on the MCP server, so this is not a uniform server build checklist. Mapping the four below against the OWASP Agentic AI Top 10 is a reasonable way to prioritize the rest, checking which party each mitigation actually binds as you go.
Confused deputy and token passthrough
A confused deputy vulnerability arises in MCP proxy servers connecting to third-party APIs: it "allows malicious clients to obtain authorization codes without proper user consent by exploiting the combination of static client IDs, dynamic client registration, and consent cookies" (MCP security best practices page). Token passthrough is the related anti-pattern where a server accepts a token without verifying it was issued for that server and forwards it downstream unmodified. The mitigation is one unconditional line: "MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server". Forwarding such a token downstream can let an attacker "use the server as a proxy for data exfiltration".
SSRF during OAuth metadata discovery
Server-Side Request Forgery here is about the URLs an MCP client fetches while discovering OAuth metadata, since a malicious server controls several of them: "the resource_metadata URL from the WWW-Authenticate header", the authorization_servers URLs from Protected Resource Metadata, and the token and authorization endpoints from Authorization Server Metadata (MCP security best practices page). The recommended defense blocks private and reserved IP ranges by default rather than hand-rolled validation, because "attackers exploit encoding tricks (octal, hex, IPv4-mapped IPv6) that custom parsers often miss".
State handle hijacking, the stateless-era replacement for session hijacking
Because MCP has no protocol-level sessions, the old Session Hijacking section has a direct replacement. Servers needing state spanning multiple requests "mint an explicit handle, such as a shopping cart ID or a workflow ID, and receive it back as an ordinary tool argument on each request"; hijacking means an attacker obtains or guesses that handle and reuses it (MCP security best practices page). The mitigation is unconditional for authorizing servers: "MCP servers that implement authorization MUST verify all inbound requests. MCP servers MUST NOT treat possession of a state handle as authentication." Recommended practice adds non-deterministic, expiring handles bound server-side to the authenticated user.
What building and maintaining an MCP server actually costs
A production MCP server needs more than a Tool that echoes a string back: authorization where the use case calls for it, input validation, rate limiting and a plan for tracking the spec's rolling deprecation clock all belong in scope for an internal or customer-facing server before it ships.
Scope drivers - primitive count, authorization, transport choice, security hardening
Four variables move the cost of a build. First, primitive count: a single read-only Resource is a small, contained build; a dozen Tools that mutate state, each needing input validation, access control and output sanitization, is a materially larger one, because the tools page requires servers to "validate all tool inputs", "implement proper access controls", "rate limit tool invocations" and "sanitize tool outputs" for every one of them (MCP tools page). Second, whether authorization is in scope, and whether it sits behind an existing identity provider or needs one built. Third, transport choice: stdio for a local subprocess is a smaller surface than a network-facing Streamable HTTP endpoint. Fourth, the security hardening implied by the eleven attack classes above, not all of which bind the MCP server itself, none optional once a server touches real credentials or user data.
Language and SDK choice is a smaller, fifth lever. The official SDKs span ten languages across three tiers: "All SDKs support: Creating MCP servers that expose tools, resources, and prompts" over local and remote transports (MCP official SDKs page):
| Tier | Languages |
|---|---|
| Tier 1 | TypeScript, Python, C#, Go |
| Tier 2 | Java, Rust, Ruby |
| Tier 3 | Swift, PHP, Kotlin |
When not to build a server at all
Two situations argue against a bespoke build. If the integration is a thin wrapper around a single existing API with no need for Tools that mutate state, an existing community or vendor server may already cover it, and a second one only adds maintenance burden. If the actual bottleneck is reasoning quality rather than tool access, an MCP server does not fix it; a build cost breakdown for AI agents generally is the right place to start that comparison first. The cost easy to underweight going in is spec currency, since the next revision will ship its own deprecations on the same rolling clock this one did.
How Pharos Production supports MCP server builds
We build MCP servers as part of larger agent and LLM-integration engagements. Our approach is to scope a server against the current spec revision, design in authorization when the use case needs it, and work through the eleven attack classes above, checking which party each one binds, as a build checklist rather than a cleanup list after launch. If a bespoke server is not yet the obvious answer, our build vs buy guide for AI agents is a useful first read.
Our AI agent development team builds the agent side of an integration, our AI integration services team handles the server and surrounding infrastructure, and our LLM integration team covers the model-facing side. Get in touch to scope an MCP server build against the current spec revision.
This article is engineering guidance based on the Model Context Protocol specification as published at modelcontextprotocol.io, current revision 2026-07-28, and the related IETF RFCs cited throughout. It is not legal or compliance advice. Primary sources: MCP versioning guide, MCP versioning page, MCP changelog, MCP specification, MCP architecture page, MCP transports page, MCP authorization page, MCP security best practices page, MCP tools page, MCP official SDKs page, MCP feature lifecycle policy and GitHub PR #2858.
FAQ
Quick answers to common questions about custom software development, pricing, process and technology.
Type to filter questions and answers. Use Topic to narrow the list.
Showing all 7
No matches
Try a different keyword, change the topic or clear filters
-
An MCP server is a program that exposes Resources, Tools and Prompts to an AI model over the Model Context Protocol, in a client-host-server architecture where each client keeps a one-to-one relationship with a single server. Resources supply context and data, Prompts offer templated messages and workflows and Tools give the model functions it can execute.
A server exposing just one primitive is a complete, conformant server. Every server also owes the protocol its own baseline obligations, among them implementing server/discover.
-
The 2026-07-28 revision removed the initialize/notifications/initialized handshake and made MCP a stateless protocol, with every request carrying its protocol version and capabilities in per-request _meta fields instead. It also added a server-mandatory server/discover RPC, replaced server-initiated requests such as sampling/createMessage and elicitation/create with the Multi Round-Trip Requests pattern and deprecated Sampling, Roots, Logging and the older HTTP+SSE transport.
Streamable HTTP also lost protocol-level session IDs and SSE stream resumability in this same revision.
-
No, a server built against the current 2026-07-28 revision does not use the initialize handshake at all, since that handshake was removed and replaced with per-request _meta negotiation. A server only needs legacy-era handling if it must also serve clients still built against 2025-11-25 or earlier, in which case it becomes a dual-era server that detects each client's era and behaves accordingly.
A server with a closed, modern-only client population can skip legacy support entirely.
-
Yes for the server, but not for the client: the 2026-07-28 revision requires every server to implement server/discover so it can advertise its supported protocol versions, capabilities and identity, while calling it stays optional for clients. Server/discover did not replace the removed initialize handshake as a required client step.
Per-request _meta negotiation did that instead. A client may still call server/discover for up-front version selection or as a backward-compatibility probe on stdio.
-
Yes, Sampling and Roots are deprecated but not removed, and both stay fully functional and normative through the deprecation window. Along with Logging, they remain part of the specification with an earliest removal eligibility of the first revision released on or after 2027-07-28, and the actual removal decision comes later still.
New servers should avoid adding either feature and plan a deliberate migration, but an existing server implementing Sampling or Roots keeps working.
-
No, authorization is optional for MCP servers overall, and the requirement depends on the transport when it is used at all. HTTP-based implementations that support authorization should conform to the MCP authorization specification built on OAuth 2.1, RFC 9728 and RFC 9207, while stdio implementations should not use that flow and should retrieve credentials from the environment instead.
A stdio server skipping OAuth is conformant, not a shortcut.
-
Cost depends on four main drivers: how many primitives the server exposes, whether authorization is in scope, which transport it uses and how much security hardening its use case demands. A single read-only Resource on stdio is a small build.
A dozen state-mutating Tools behind Streamable HTTP with full OAuth and access controls is materially larger. Maintenance is ongoing rather than one-time, since each new spec revision ships its own deprecations on the same rolling clock.
I work with startup founders who need a dedicated software development team but don’t want to gamble on hiring, random outsourcing, or opaque delivery.
Most founders face the same problem sooner or later.
Early technical and team decisions lock the product into tech debt, slow delivery, missed milestones and constant re-hiring. By the time this becomes visible, fixing it is already expensive.As a CTO and software architect, I help founders design, build and run dedicated development teams that work as a true extension of the startup. Not as a black-box vendor.
My focus is on complex products where mistakes are costly:
- Web3 and blockchain platforms
- FinTech and regulated products
- High-load startup systems
- MVP → scale transitions
We don’t do body-shopping.
We don’t sell generic outsourcing.Instead, we help founders:
- build the right team structure from day one
- keep technical ownership and transparency
- scale delivery without losing control
- avoid vendor lock-in and hidden risks
Teams are aligned with the product roadmap, business goals and long-term architecture. Not just short-term velocity.