# Introducing MCP 7-28 for AI Application Developers: What Goes Away, and What Might Break

> Source: <https://aaif.io/blog/introducing-mcp-7-28-for-ai-application-developers-what-goes-away-and-what-might-break/>
> Published: 2026-07-16 18:25:09+00:00

*Junghwan Park ( 9bow) is an AAIF Ambassador, a PyTorch Ambassador, and the lead maintainer of the PyTorch Korea User Group (PyTorchKR). A Korean version of this post is available here.*

TL;DR: MCP 7-28 is less about new features than simplifying and hardening the protocol for production use. The release deprecates Roots, Sampling, and protocol-level Logging, moves MCP to a stateless, sessionless architecture that replaces implicit session state with explicit state handles, strengthens HTTP authorization, and standardizes tool contracts on JSON Schema 2020-12. Most lookup-style MCP servers will require only modest updates, while servers that depend on sessions, filesystem Roots, browser state, long-running workflows, or remote HTTP deployments should plan for a broader architectural review and migration.

*Disclaimer: ‘MCP 7-28’ is a working name for the MCP specification changes expected to be published around July 28, 2026. The SEPs (Specification Enhancement Proposals) cited in this post ( SEP-2577, SEP-2575, SEP-2567, SEP-1613, SEP-2106, and others) have already reached Final status, but the official specification revision that incorporates them has not yet been finalized as of this writing. It is currently published as a Release Candidate (locked May 21, 2026; see the official RC announcement); 2025-11-25 remains the latest finalized revision, and 2026-07-28 is scheduled to ship as final on July 28, 2026. Dates, exact wording, and any “planned/incorporated/finalized” phrasing in this post should therefore be re-verified against the official MCP specification, release notes, and SDK changelogs once the revision actually ships.*

## Introduction to MCP and Why It Matters

The [PyTorch Korea User Group (PyTorchKR)](https://pytorch.kr/) covers not only training and inference with PyTorch, but also everything it takes to put those models to work in real services outside the lab. Curating and sharing the latest news, open-source projects, and notable papers and research trends on the [PyTorchKR community forum](https://discuss.pytorch.kr/) comes from the same motivation. Training a model well and making that model genuinely useful inside a product are no longer things we can think about separately.

Models are increasingly used together with agents and external tools, and MCP (Model Context Protocol) is one of the standardized touchpoints in that connection layer. For a large language model (LLM) to be useful in the real world, the model alone is not enough. It needs channels to the real world: reading files, querying databases, searching the documents a user cares about, calling external APIs. MCP is an open protocol that standardizes exactly that channel: instead of building a bespoke integration for every tool, you connect models to external tools, data, and execution environments through one shared contract. This is why tools like Claude Desktop, Cursor, and VS Code all follow the same MCP client specification.

### How MCP (Model Context Protocol) Works

```
graph TB
    subgraph "MCP Host (AI application)"
        Client1["MCP Client 1"]
        Client2["MCP Client 2"]
        Client3["MCP Client 3"]
        Client4["MCP Client 4"]
    end

    ServerA["MCP Server A
(local; e.g., filesystem)"]
    ServerB["MCP Server B
(local; e.g., database)"]
    ServerC["MCP Server C
(remote; e.g., Sentry)"]

    Client1 ---|"dedicated
connection"| ServerA
    Client2 ---|"dedicated
connection"| ServerB
    Client3 ---|"dedicated
connection"| ServerC
    Client4 ---|"dedicated
connection"| ServerC
```

MCP is easiest to understand in terms of three participants: the host, the server, and the client. The LLM application the user directly interacts with, such as Claude Desktop or Cursor, is the host; the connector inside the host that maintains a 1:1 connection with a single server is the client; and the side that actually provides tools and data is the server. These three participants exchange requests and responses as [JSON-RPC 2.0](https://www.jsonrpc.org/specification) messages. As of this writing, the latest MCP specification is the [November 25, 2025 revision](https://modelcontextprotocol.io/specification/2025-11-25).

An MCP server exposes what it can do to the client. It advertises three kinds of building blocks:

- Tools: functions the model invokes to perform real actions (e.g., search, file reads, external API calls).
- Resources: data provided to the model as context (e.g., files, documents, records).
- Prompts: reusable prompt templates.

Servers and clients generally connect over one of two transports: (1) For MCP servers run locally, the host launches the server as a subprocess and exchanges messages over standard input and output (stdin/stdout), using the stdio transport.

```
sequenceDiagram
    participant Client
    participant SP as Server Process

    Client->>+SP: Launch subprocess
    loop Message Exchange
        Client->>SP: Write to stdin
        SP->>Client: Write to stdout
        SP--)Client: Optional logs on stderr
    end
    Client->>SP: Close stdin, terminate subprocess
    deactivate SP
```

(2) For MCP servers running remotely, messages are exchanged over the HTTP-based [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http) transport. Under the [currently published spec (2025-11-25)](https://modelcontextprotocol.io/specification/2025-11-25), the client and server exchange versions and capabilities in an initialization (initialize) step at the start of the connection, then continue subsequent requests and responses on top of the established session.

```
sequenceDiagram
    participant Client
    participant Server

    note over Client, Server: initialization

    Client->>+Server: POST InitializeRequest
    Server->>-Client: InitializeResponse
MCP-Session-Id: 1868a90c...

    Client->>+Server: POST InitializedNotification
MCP-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted

    note over Client, Server: client requests
    Client->>+Server: POST ... request ...
MCP-Session-Id: 1868a90c...

    alt single HTTP response
      Server->>Client: ... response ...
    else server opens SSE stream
      loop while connection remains open
          Server-)Client: ... SSE messages from server ...
      end
      Server-)Client: SSE event: ... response ...
    end
    deactivate Server

    note over Client, Server: client notifications/responses
    Client->>+Server: POST ... notification/response ...
MCP-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted

    note over Client, Server: server requests
    Client->>+Server: GET
MCP-Session-Id: 1868a90c...
    loop while connection remains open
        Server-)Client: ... SSE messages from server ...
    end
    deactivate Server
```

Much of what changes in ‘MCP 7-28’, the subject of this post, is precisely about revisiting the assumptions baked into how these connections are established (handshake) and maintained (session). If you want more background on MCP concepts and architecture, the PyTorchKR community’s [Deep Research: Model Context Protocol (MCP) study material](https://discuss.pytorch.kr/t/deep-research-model-context-protocol-mcp/6594) is a good starting point.

### Introducing the Next MCP Standard: MCP 7-28

‘MCP 7-28’ is the working name for the next MCP specification revision, expected to land around July 28, 2026. Rather than adding new features, this release is closer to a migration-focused one. The core idea is to keep MCP’s Core Protocol smaller and clearer while cleaning up state management, authorization, schemas, and the lifecycle of several existing features. So the first thing to look at in this revision is ‘what goes away, and what might break’.

Anyone who has built and operated MCP servers in production runs into questions like these:

- Which tools can the model see?
- Against which schema are tool-call arguments validated?
- Where is state stored between one tool call and the next?
- Who decides access to external resources like files, browsers, databases, and document search?
- How does an MCP server exposed over HTTP validate tokens, scopes, and audiences?
- Should observability live in protocol-level logging, or in application logs and traces?

The major changes in MCP 7-28 map directly onto these questions, and they fall into two broad groups:

- What goes away (Deprecation): Roots, Sampling, and Logging are marked deprecated in the core protocol (
[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md)). These features do not disappear immediately, but new development should stop relying on them. - What might break (Breaking Change): the protocol moves stateless-first (
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2575-stateless-mcp.md)), the protocol-level session is removed in favor of surfacing state as explicit handles ([SEP-2567](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2567-sessionless-mcp.md)), and the authorization baseline for the HTTP transport is hardened. On top of that, tool schemas are aligned with JSON Schema 2020-12, resetting the baseline for tool contracts ([SEP-1613](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md),[SEP-2106](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2106-json-schema-2020-12.md)).

This post focuses less on the upgrade steps for any particular SDK, and more on what to audit when you operate MCP servers as the tooling infrastructure of an LLM application. For the rest of the post, we walk through each change in the same order: ① what the feature originally was → ② what changes and how → ③ how it lands in your code and configuration → ④ what you gain as a result. We first sort out the concepts, then close with real MCP server case studies and a migration checklist. Operational topics such as routing headers, list caching, trace propagation, and the Tasks extension are out of scope here and will be covered separately in a [follow-up series](https://discuss.pytorch.kr/).

MCP 7-28 changes covered in this post, at a glance

| Checklist item | Direction of change | Question to ask |
| Roots | Deprecated | Do you rely on roots/list for workspace/filesystem access boundaries? |
| Sampling | Deprecated | Does your MCP server ask the client/host to generate LLM completions? |
| Logging | Deprecated | Do you depend on MCP protocol logging for operational logs and observability? |
| Stateless/sessionless | Protocol-level session state removed; state becomes explicit handles | Can each request be understood without a prior handshake/session? Is state referenced by explicit IDs? |
| HTTP authorization | Hardened security baseline for the HTTP transport | Do you validate bearer tokens, resource indicators, scopes, and audiences? |
| JSON Schema 2020-12 | Tool contract baseline cleaned up | Do inputSchema, outputSchema, and structuredContent conform to the new baseline? |

## What Goes Away (Deprecation): Roots, Sampling, Logging

[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) designates Roots, Sampling, and Logging as deprecated in the core protocol. Deprecation does not mean immediate removal. [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) explains that during the deprecation period, wire-level behavior does not change, and neither the types nor capability negotiation are removed. So the accurate reading is not ‘this breaks today’ but ‘stop using these in new MCP implementations’.

### Roots

What it originally was: Roots lets a client tell a server which local directories and file boundaries it may access. For servers that touch the local filesystem, like the [filesystem MCP server](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem), access boundaries matter, and a server could query the client-provided boundaries via roots/list.

What changes and how: [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) views Roots not as an actual access-control mechanism but as informational guidance. From that viewpoint, the MCP protocol does not confine the server to those paths, so assuming ‘this path is inside the client-sent Roots, therefore it is safe’ blurs the security boundary. The proposal instead recommends conveying access scope through more explicit means: tool parameters, resource URIs, server configuration, or environment variables.

How it lands in code/configuration: from a migration standpoint, check the following:

- Does the MCP server accept its allowed paths as launch arguments?
- Can an allowlist be set via a configuration file or environment variables?
- Is access scope made explicit in tool parameters or resource URIs?
- Is filesystem policy enforced at the host, gateway, or sandbox layer?
- Does the server only behave correctly when roots/list results change?

What you gain: you move away from the structure where, within each session, the server dynamically trusts whatever Roots the client advertised. Access policy becomes decidable from the request and the server configuration alone. As a result, the security boundary stops being a protocol-level hint and becomes a policy the MCP server itself enforces.

### Sampling

What it originally was: Sampling lets an MCP server request an LLM completion from the client or host. With it, a server could use the model connected to the client even without its own LLM integration or API key.

What changes and how: Sampling is powerful, but it blurs the boundary of responsibility. It becomes ambiguous whether the server is a simple tool provider or an orchestrator directing model invocations. Responsibility for choosing which model to call, handling the user-approval UI, managing cost and policy, and defending against prompt injection inside the tool loop can end up in a gray zone between server and client. For these reasons, [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) deprecates Sampling and suggests alternatives such as calling an LLM provider API directly when a server genuinely needs completions.

How it lands in code/configuration: the direction for reducing a server’s dependence on the model looks like this:

- The MCP server returns the necessary context, candidate prompts, and structured results.
- Model invocation happens in the MCP host, the agent runtime, or the application layer.
- Long-running workflow orchestration is managed by a separate agent runtime or job queue.
- If the server truly needs its own LLM, it integrates a provider API directly and surfaces that fact in its tool contract and operational policy.

What you gain: the default role of an MCP server shifts from ‘go invoke the model’ toward ‘reliably provide the tools and data the model reasons over’. Responsibility boundaries become clear, and risk surfaces like prompt injection and data exfiltration become easier to manage.

### Logging

What it originally was: Logging lets an MCP server deliver structured logs to the MCP client via protocol messages (notifications/message), with the client able to adjust logging verbosity.

What changes and how: deprecating Logging does not mean ‘stop logging’. It means: do not entrust operational observability to Logging, a protocol feature. [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) itself [recommends](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md#logging) leaning on mature, existing logging/observability infrastructure such as standard error (stderr) or [OpenTelemetry](https://github.com/open-telemetry).

How it lands in code/configuration: in production, apply setups like the following:

- Locally run MCP servers use a standard logger and standard error (stderr).
- Remote, HTTP-based MCP servers keep request logs, audit logs, and trace IDs.
- Tool calls, retrieval, external API calls, and model calls are tied together as OpenTelemetry traces.
- Responsibilities of protocol messages and application logs are kept separate.

What you gain: in an AI application, a single user request mixes retrieval, tool calls, model calls, and external API calls. An end-to-end trace is far more useful than protocol logging alone.

How reference MCP servers from the [official MCP repository](https://github.com/modelcontextprotocol/servers), such as [filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) and [memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory), are affected is covered later in this post.

## What Might Break (Breaking Change): Stateless/Sessionless, HTTP Authorization, JSON Schema 2020-12

### Stateless/Sessionless

What the structure originally was: the [current MCP standard](https://modelcontextprotocol.io/specification/2025-11-25) depends in places on the initialize handshake and connection/session state. The client and server exchange versions and capabilities at the start of a connection; once the server issues a session ID (MCP-Session-Id), every subsequent request must carry it in a header. Managing state on top of a pinned session like this was fine for a single local process, but became an obstacle at scale.

What changes and how: first, [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2575-stateless-mcp.md) proposes a stateless-first direction. If an HTTP-based remote MCP server sits behind a load balancer or runs across multiple nodes, a given client session gets pinned to the in-memory state of whichever server it first connected to, forcing sticky sessions, session stores, resumption, and failover. To fix this, [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2575-stateless-mcp.md) proposes:

- Requests should be as self-contained as possible.
- The protocol version and client capabilities travel as per-request metadata on every request.
- An MCP server can advertise its supported versions and capabilities via server/discover.
- Server designs that can only process the current request by remembering a previous one should be avoided.

On top of this, [SEP-2567](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2567-sessionless-mcp.md) pushes further toward a sessionless direction: it removes the protocol-level session concept entirely, and where application state is needed, it is passed around as explicit state handles in tool results and arguments.

How it lands in code/configuration: to see what stateless/sessionless means in practice, imagine an MCP server that serves search results. State like a search session is treated as an explicit handle:

```
# Create a new search, returning a state handle for it (e.g., srch_7f3a)
1. create_search(query="MCP Roots deprecation")
   -> { "search_handle": "srch_7f3a" }

# Request the next page of results, passing the earlier handle (srch_7f3a)
2. get_search_page(search_handle="srch_7f3a", page=2)
   -> { "items": [...] }

# When done, pass the handle (srch_7f3a) to close the search
3. close_search(search_handle="srch_7f3a")
   -> { "closed": true }
```

Even under the stateless/sessionless assumption, state can still live on the server. What changes is that the state is no longer bound to a prior session; it is expressed as an explicit value, search_handle. [SEP-2567](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2567-sessionless-mcp.md) describes this not as a new protocol primitive but as a tool-design pattern. Each handle is just a string inside a tool result, passed back as an argument on later calls. For good handle design, refer to the SEP’s [guidance for servers](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2567-sessionless-mcp.md#guidance-for-servers): use opaque values, validate (handle, auth_context) on every call, and make expiry/cleanup policies explicit.

What you gain: client requests can be routed to any server node. Horizontal scale-out becomes easy, state no longer vanishes with a failed node, and caching of list results such as tools/list becomes straightforward. This change has significant impact on MCP servers that must manage state across requests, including browser automation, shopping carts, payment flows, long-running jobs, and DB transactions. But lookup-style MCP servers that take search criteria on every call and return results are unlikely to conflict with it.

The precise meaning of the stateless core, handle design for search sessions / long-running jobs / browser contexts, session independence of tools/list, and the Tasks Extension of [SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md) will be covered in a follow-up post.

### HTTP Authorization

What the structure originally was: for local MCP servers, an MCP host like Claude Desktop or Cursor launches the server directly as a subprocess. In that setting, it is hard for the MCP protocol to determine who is using the server and how far they may reach. The trust boundary is already ‘whoever is using the MCP host’, so MCP had little need for its own authentication or authorization layer. In other words, when MCP servers were used to wire tools inside an LLM application, it was easy to treat authorization as something to bolt on later.

What changes and how: the [MCP authorization draft](https://modelcontextprotocol.io/specification/draft/basic/authorization) defines the authorization flow for HTTP-based transports. Authorization remains optional in MCP implementations, but if an HTTP-based transport supports authorization, following this specification is recommended. For local stdio transports, the draft advises using local credential delivery, such as environment variables, instead of this flow. Running legalize-mcp locally inside Claude Desktop or Cursor and exposing an HTTP-based remote MCP server to the internet involve different threat models.

```
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as Client
    participant M as MCP Server (Resource Server)
    participant A as Authorization Server

    C->>M: MCP request without token
    M->>C: HTTP 401 Unauthorized with WWW-Authenticate header
    Note over C: Extract resource_metadata URL from WWW-Authenticate

    C->>M: Request Protected Resource Metadata
    M->>C: Return metadata

    Note over C: Parse metadata and extract authorization server(s)
Client determines AS to use

    C->>A: GET Authorization server metadata endpoint
    Note over C,A: Try OAuth 2.0 and OpenID Connect
discovery endpoints in priority order
    A-->>C: Authorization server metadata

    alt Client ID Metadata Documents
        Note over C: Client uses HTTPS URL as client_id
        Note over A: Server detects URL-formatted client_id
        A->>C: Fetch metadata from client_id URL
        C-->>A: JSON metadata document
        Note over A: Validate metadata and redirect_uris
    else Dynamic client registration
        C->>A: POST /register
        A->>C: Client Credentials
    else Pre-registered client
        Note over C: Use existing client_id
    end

    Note over C: Generate PKCE parameters
Include resource parameter
Apply scope selection strategy
Record expected issuer
    C->>B: Open browser with authorization URL + code_challenge + resource
    B->>A: Authorization request with resource parameter
    Note over A: User authorizes
    A->>B: Redirect to callback with authorization code + iss
    B->>C: Authorization code callback
    Note over C: Validate iss against recorded issuer (RFC 9207)
    C->>A: Token request + code_verifier + resource
    A->>C: Access token (+ refresh token)
    C->>M: MCP request with access token
    M-->>C: MCP response
    Note over C,M: MCP communication continues with valid token
```

How it lands in code/configuration: for HTTP-based remote MCP servers, verify the following:

- Does every HTTP request carry an Authorization: Bearer <access-token> header?
- Are access tokens kept out of the query string?
- Do you provide OAuth 2.0 Protected Resource Metadata and authorization server discovery?
- Does the resource parameter name the MCP server as the target resource?
- Does the MCP server validate the token audience?
- Are scopes granular per operation, with an additional authorization challenge (WWW-Authenticate) returned for insufficient scopes?
- Can the client recover from 401s, 403s, invalid or expired tokens, and insufficient_scope errors?

What you gain: the moment an MCP server is exposed as an external HTTP endpoint, its tool contract and auth contract get designed together. The model can then determine, along the same request path, which tools it can see on the remote server, which scopes the user has granted, and whether it is authorized to touch a particular handle or resource.

The HTTP authorization flow itself, including OAuth 2.1, Protected Resource Metadata, token audience validation, scope challenges, and more, is covered in greater detail in upcoming posts.

### JSON Schema 2020-12, Which Defines the Contract

What the structure originally was: in an MCP server, a tool is not just a function. To the client and the LLM, the tool’s name, description, inputSchema, outputSchema, and structuredContent together form a contract. But until now, the definition was fairly loose about which JSON Schema dialect these contracts use, and how a tool with no arguments should express its schema.

What changes and how: first, [SEP-1613](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md) proposes establishing [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/json-schema-core) as the default dialect for JSON schemas embedded in MCP messages. That is: absent an explicit $schema, JSON Schema 2020-12 is assumed; inputSchema must not be null; and even a tool with no parameters must carry a valid schema. [SEP-2106](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2106-json-schema-2020-12.md) then relaxes the constraints further:

- inputSchema keeps type: “object” (tool arguments are an object), but now also allows JSON Schema 2020-12 keywords including oneOf, anyOf, allOf, if/then/else, and $ref/$defs.
- outputSchema additionally supports full JSON Schema 2020-12 schemas, since tool output can be any JSON value, including arrays and scalars as well as objects.
- structuredContent is likewise no longer restricted to objects and may be any JSON value that conforms to outputSchema.

How it lands in code/configuration: if you build MCP servers in Python on FastMCP, Pydantic, or dataclasses, check:

- Are the inputSchemas your SDK generates valid against JSON Schema 2020-12?
- Does a zero-argument tool end up with a null inputSchema?
- Can lookup-by-ID-or-name tools use composition keywords like oneOf?
- Are you wrapping a list API’s natural array response in an artificial wrapper object?
- Do structuredContent and outputSchema match what the tool actually returns?
- If internal tools must specify $schema explicitly, are those values consistent?

What you gain: when the contract an MCP server exposes is unambiguous, the model miscalls tools less, clients fail validation less, and outputs can be post-processed safely. Even a lookup-style server with no session state suffers degraded tool usability if its schemas disagree with the client, so this change deserves an audit from every kind of MCP server.

Why tools/list is the real contract, the distinction between optional and nullable, when to use oneOf vs. anyOf, and aligning outputSchema with structuredContent are covered in upcoming posts.

## Impact, Through Case Studies

So far we have surveyed the changes in the MCP 7-28 revision through its SEPs (Specification Enhancement Proposals). Now let’s see, through two brief case studies, how MCP servers should respond. The key point: not all MCP servers are affected equally. A server offering lookup-style tools may see relatively little impact, while filesystem servers, browser automation servers, and HTTP-based remote servers may need a review starting at the design level.

### Case 1: A Lookup-Style MCP Server, Legalize-KR

[Legalize-KR](https://github.com/legalize-kr/) is an open-source project that makes South Korea’s [statutes](https://github.com/legalize-kr/legalize-kr), [court precedents](https://github.com/legalize-kr/precedent-kr), [local ordinances](https://github.com/legalize-kr/ordinance-kr), and [administrative rules](https://github.com/legalize-kr/admrule-kr) data repositories available as [CLI tools and an MCP server](https://github.com/legalize-kr/cli-tools), plus agent skills. The MCP section of the Legalize-KR usage docs explains how MCP clients like Claude Desktop, Cursor, and VS Code call Legalize-KR data as tools. The agent interprets the natural-language question, and a local stdio MCP server performs the actual statute/precedent lookups. Judging by the [MCP tool descriptions published on its homepage](https://legalize.kr/usage.html#mcp), the Legalize-KR MCP server is lookup-style:

- Supported tools
- Statutes: laws_list, laws_get, laws_article
- Precedents: precedents_list, precedents_get
- Ordinances: ordinances_list, ordinances_get
- Administrative rules: admrules_list, admrules_get
- Unified search: search

- Example configuration

```
{
   "mcpServers": {
      "legalize-kr": {
         "command": "uvx",
         "args": ["--from", "legalize-cli[mcp]", "legalize-mcp"]
      }
   }
}
```

Based on the public docs and code, the Legalize-KR MCP server holds no long-lived protocol session state; on each tool call it simply takes the required arguments, looks up statute or precedent data, and returns the result. Simplified, the structure looks like this:

```
# Illustrative sketch, not the actual implementation.
mcp = FastMCP("legalize-kr")
@mcp.tool()
def laws_article(
law_name: str,
article_no: str,
date: str | None = None,
) -> str:
result = fetch_law_article(
law_name=law_name,
article_no=article_no,
date=date,
)
return json.dumps(result, ensure_ascii=False)
```

The key point is that inputs like law_name, article_no, and date arrive explicitly in the tool call, and the server can produce its result from those inputs alone. Lookup-style servers like this are likely to be relatively lightly affected by the changes above.

| Major MCP 7-28 change | Expected impact from Legalize-KR’s perspective |
| Roots deprecation | Based on Legalize-KR’s public MCP usage docs, it does not appear to be a core dependency. |
| Sampling deprecation | Low impact unless the server asks the client for LLM completions. |
| Logging deprecation | Low impact unless protocol-level logging is on the critical operational path. |
| Stateless/sessionless direction | A good fit for lookup-style tool calls, though SDK and protocol-version updates still need verification. |
| HTTP authorization | Little impact for local stdio use; separate review needed if exposed over remote HTTP. |
| JSON Schema 2020-12 | Verify that SDK-generated inputSchema/outputSchema match the new baseline. |

As the table shows, migrating to MCP 7-28 should be scoped not by ‘my whole MCP server’ but by ‘which MCP features am I actually using’.

### Case 2: The Reference Implementations in the Official modelcontextprotocol/servers Repository

The [official modelcontextprotocol/servers repository](https://github.com/modelcontextprotocol/servers), which provides MCP server examples, also deserves careful reading. It contains a small set of reference servers maintained by the MCP steering group. Keep in mind that these servers are not production-ready solutions but educational reference implementations demonstrating MCP features and SDK usage.

With that in mind, the per-feature impact for the reference MCP servers looks like this:

| Reference server | What to look at | MCP 7-28 angle |
| filesystem | File-access boundary example | After the Roots deprecation, more explicit boundaries, including allowlists, launch arguments, and resource URIs, matter more. |
| everything | Test server for feature-surface coverage | Useful for exercising combinations of prompts, resources, and tools. |
| memory | Persistent application state example | Requires distinguishing ‘has state’ from ‘implicitly bound to a protocol session’. |
| sequential-thinking | Cross-call context example | A place to examine how cross-call context surfaces in tool arguments and results. |
| git | Repository tooling example | Check where local file and Git operation permissions are constrained. |

Looking more closely at filesystem and memory at the implementation level reveals considerations quite different from the lookup-style case above.

#### filesystem: A Server That Leans on Roots for Access Boundaries

The [filesystem server](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) comprehensively provides file read/write plus directory create/list/move, search, and metadata tools (read_text_file, write_file, edit_file, list_directory, search_files, get_file_info, list_allowed_directories, and so on). All file operations are confined to ‘allowed directories’.

Among the MCP 7-28 changes, we saw one that affects how those allowed directories get set. The [filesystem server README](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem/README.md) documents two ways to specify them:

- Command-line arguments: pass allowed paths directly at server startup, for example mcp-server-filesystem /path/to/allowed/dir1 /path/to/allowed/dir2, or configure:

```
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir1", "/path/to/allowed/dir2"]
    }
  }
}
```

- MCP Roots (the recommended method): if the MCP client advertises Roots, the server fully replaces its allowed directories with them, and notifications/roots/list_changed updates them at runtime without a server restart (though if the server starts with no command-line arguments and the client does not support Roots, initialization fails).

Of these two, the recommended approach, using Roots, collides head-on with MCP 7-28: the documentation’s recommended way of conveying access boundaries relies on the very Roots feature that [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md) proposes to deprecate.

One distinction matters here, though. The actual enforcement is not the Roots feature itself; the server enforces path validation that blocks access outside the allowed directories. Roots is merely the mechanism for dynamically delivering and updating the allowed-directory list. So what the deprecation destabilizes is not file access control itself, but the specific path of ‘runtime dynamic updates via Roots’. The remedy is to expose access scope through command-line arguments and configuration files, and (as discussed earlier) explicit tool parameters or resource URIs. Since wire-level behavior is preserved for a while after deprecation, nothing breaks immediately. For newly designed MCP servers, it is safer not to treat ‘the Roots the client passed during the session’ as the primary basis for your boundary.

#### memory: A Server That Has State but Is Not Bound to Sessions

The [memory server](https://github.com/modelcontextprotocol/servers/tree/main/src/memory) persistently stores a knowledge graph of entities, relations, and observations in a local JSONL file (the MEMORY_FILE_PATH environment variable, default memory.jsonl). This lets a model remember and recall information across conversations. Its tools are create_entities, create_relations, add_observations, delete_entities, delete_observations, delete_relations, read_graph, search_nodes, and open_nodes, and it also exposes the whole graph as a memory://knowledge-graph resource. A single entity in the graph looks roughly like this:

`{ "name": "John_Smith", "entityType": "person", "observations": ["Speaks fluent Spanish"] }`

memory is unmistakably a stateful server. But its state lives not in the current MCP session; it lives in the knowledge graph persisted to a file. The identifier that points at state is not a session ID but an explicit key, name, and the whole graph is addressable via a resource URI. This is exactly why the earlier impact table lists memory as the example for separating ‘has state’ from ‘implicitly bound to a protocol session’. The flow of creating a name via create_entities and later passing that name back into open_nodes or search_nodes is close to the explicit state handle pattern described earlier (with the difference that the handle is chosen by the user or the model rather than being an opaque server-issued ID).

So for an MCP server like memory, the MCP 7-28 review should focus less on the deprecated features and more on operations and scaling:

- Horizontal scaling: the default store is a single JSONL file: process-local storage. Satisfying MCP 7-28’s ‘any request can go to any instance’ requires storage shared across instances.
- Isolation and authorization: today there is a single graph, with no multi-user or tenant isolation. Exposing it as a remote MCP server requires splitting the graph into per-user files or namespaces, and validating not just the handle value (name) but authorization as well, (name, auth_context), on each request.
- Resource subscriptions and caching: mutation tools emit notifications/resources/updated for memory://knowledge-graph. If clients depend on these notifications, verify that list/resource caching and invalidation flows stay consistent.

The reference servers in the [official modelcontextprotocol/servers repository](https://github.com/modelcontextprotocol/servers) are a starting point for building MCP servers. For production, security boundaries, authentication/authorization, observability, and deployment architecture must be redesigned and reimplemented against each service’s own threat model.

## Where Does My MCP Server Fit?

As the case studies show, migration priorities for the MCP 7-28 changes depend on the type of server. Classifying your server with the flow below makes it easier to set priorities:

``` php
flowchart TD

A["Inventory your MCP servers"] --> B["Check usage of deprecated features"]

B --> C["Roots, Sampling, Logging"]

A --> D["Check how state is managed"]

D --> E["Stateless core and explicit handles"]

A --> F["Check tool schemas"]

F --> G["JSON Schema 2020-12"]

A --> H["Check transport and auth"]

H --> I["stdio or HTTP authorization"]

C --> J["Set migration priorities"]

E --> J

G --> J

I --> J
```

Alternatively, you can gauge the impact of the MCP 7-28 changes by what your server does. The following server types are likely to see relatively little impact:

- Tool-centric servers focused on lookups
- Servers where every tool call receives all required inputs as parameters
- Servers that do not depend on protocol session state
- Servers that do not use Roots, Sampling, or Logging as core features
- Servers used only in local stdio environments
- Servers whose authentication is limited to local environment variables or client configuration

By contrast, the following MCP server types may be significantly affected and deserve a careful review:

- Servers that dynamically change their filesystem workspace via the Roots feature
- Servers that call the client/host’s sampling/createMessage
- Servers that use MCP protocol-level logging as their operational logs
- Servers that bind browser contexts, shopping carts, payments, DB transactions, or long-running jobs to sessions
- Servers whose tools/list, resources/list, or prompts/list results differ per session
- Servers exposed externally over HTTP with weak token audience, scope, or discovery handling

If you fall into these categories, treat MCP 7-28 not as a simple compatibility update but as an opportunity for a design review.

## Migration Checklist

You will want to re-verify against the final MCP 7-28 specification and SDK release notes, but as of this writing you can audit in this order:

- Inventory the MCP features your server uses:
- Check usage of Tools, Resources, Prompts, Roots, Sampling, Logging, Tasks, Elicitation, and any custom extensions.

- Check usage of and dependence on deprecated features:
- If you do not use Roots, Sampling, or Logging, impact may be limited.
- If you use or depend on one or more, schedule replacement designs or removal.

- Find session state:
- Check whether per-client state is held and used in server memory.
- If state management is genuinely needed, see whether it can be surfaced as explicit handles instead of sessions.

- Check whether list endpoints vary by session:
- If tools/list, resources/list, or prompts/list results change with connection or session state, a redesign may be needed.

- Review your state-handle design:
- Audit opaque handles, expiry, cleanup, authorization checks, error messages, and recovery tools.

- Audit authentication on HTTP transports:
- Check bearer tokens, resource indicators, Protected Resource Metadata, authorization server discovery, scope challenges, and audience validation.

- Dump and validate your tool schemas:
- Verify inputSchema, outputSchema, and structuredContent against
[JSON Schema 2020-12](https://json-schema.org/draft/2020-12/json-schema-core).

- Verify inputSchema, outputSchema, and structuredContent against
- Consult the official reference servers:
- Use reference servers like filesystem, everything, memory, sequential-thinking, and git as per-feature impact samples.

- Prepare smoke tests:
- Keep a minimal test set covering representative tool calls, schema listing, auth success/failure, handle expiry, and error messages.

## Closing

What matters most when reading the MCP 7-28 changes is not ‘what new features arrived’ but ‘which features does my MCP server actually use’. A lookup-style tool server like the Legalize-KR example is likely to fit the stateless/sessionless direction well. Conversely, MCP servers that depend on Roots, Sampling, Logging, session-scoped state management, or HTTP authorization should review their design and operations together.

## Further Reading

[The 2026-07-28 MCP Specification Release Candidate (official MCP blog)](https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/)[SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2577-deprecate-roots-sampling-and-logging.md):[Deprecate Roots, Sampling, and Logging](https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging)[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2575-stateless-mcp.md):[Make MCP Stateless](https://modelcontextprotocol.io/seps/2575-stateless-mcp)[SEP-2567](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2567-sessionless-mcp.md):[Sessionless MCP via Explicit State Handles](https://modelcontextprotocol.io/seps/2567-sessionless-mcp)[SEP-1613](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md):[Establish JSON Schema 2020-12 as Default Dialect for MCP](https://modelcontextprotocol.io/seps/1613-establish-json-schema-2020-12-as-default-dialect-f)[SEP-2106](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2106-json-schema-2020-12.md):[Tools inputSchema & outputSchema Conform to JSON Schema 2020-12](https://modelcontextprotocol.io/seps/2106-json-schema-2020-12)[Legalize-KR MCP usage](https://legalize.kr/usage.html#mcp)[Official MCP reference servers repository](https://github.com/modelcontextprotocol/servers)
