Skip to content

Commit e942d00

Browse files
authored
Re-vendor 2026-07-28 schema at spec ead35b59 (SubscriptionsListenResult) (#3006)
1 parent 3b78f86 commit e942d00

10 files changed

Lines changed: 124 additions & 15 deletions

File tree

schema/2026-07-28.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3220,6 +3220,9 @@
32203220
{
32213221
"$ref": "#/$defs/ReadResourceResult"
32223222
},
3223+
{
3224+
"$ref": "#/$defs/SubscriptionsListenResult"
3225+
},
32233226
{
32243227
"$ref": "#/$defs/ListPromptsResult"
32253228
},
@@ -3389,6 +3392,36 @@
33893392
],
33903393
"type": "object"
33913394
},
3395+
"SubscriptionsListenResult": {
3396+
"description": "The response to a {@link SubscriptionsListenRequestsubscriptions/listen}\nrequest, signalling that the subscription has ended gracefully (for example,\nduring server shutdown). Because the listen stream is long-lived, this result\nis sent only when the server tears the subscription down; an abrupt transport\nclose carries no response. The result body is otherwise empty.",
3397+
"properties": {
3398+
"_meta": {
3399+
"$ref": "#/$defs/SubscriptionsListenResultMeta"
3400+
},
3401+
"resultType": {
3402+
"description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.",
3403+
"type": "string"
3404+
}
3405+
},
3406+
"required": [
3407+
"_meta",
3408+
"resultType"
3409+
],
3410+
"type": "object"
3411+
},
3412+
"SubscriptionsListenResultMeta": {
3413+
"description": "Extends {@link MetaObject} with the subscription-stream identifier carried by a\n{@link SubscriptionsListenResult}. All key naming rules from `MetaObject` apply.",
3414+
"properties": {
3415+
"io.modelcontextprotocol/subscriptionId": {
3416+
"$ref": "#/$defs/RequestId",
3417+
"description": "Identifies the subscription stream this response closes, so the client can\ncorrelate it with the originating subscription — mirroring the same key on\nthe stream's notifications. The value is the JSON-RPC ID of the\n`subscriptions/listen` request that opened the stream (and equals this\nresponse's `id`)."
3418+
}
3419+
},
3420+
"required": [
3421+
"io.modelcontextprotocol/subscriptionId"
3422+
],
3423+
"type": "object"
3424+
},
33923425
"TextContent": {
33933426
"description": "Text provided to or from an LLM.",
33943427
"properties": {

schema/PINNED.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{
99
"protocol_version": "2026-07-28",
1010
"source_path_in_spec_repo": "schema/draft/schema.json",
11-
"spec_commit": "2852f30e26ca5fb779565741ec042094cb110abd",
12-
"sha256": "ed1ad4ba94aaeb2068b78969ef901b1150f7b2f06cf86472b3032abee1380b6a"
11+
"spec_commit": "ead35b59b4fda8b32e276810025d8f92bdcec1b6",
12+
"sha256": "e00f675287e8cf078688c26c8a89d283ff2613da3b76d5cd15aff9d189df639c"
1313
}
1414
]

scripts/gen_surface_types.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,15 @@
8585
OPEN_CLASSES: dict[str, frozenset[str]] = {
8686
"2025-11-25": frozenset({"Meta", "InputSchema", "OutputSchema", "Result", "GetTaskPayloadResult", "Data"}),
8787
"2026-07-28": frozenset(
88-
{"MetaObject", "NotificationMetaObject", "RequestMetaObject", "InputSchema", "OutputSchema", "Result"}
88+
{
89+
"MetaObject",
90+
"NotificationMetaObject",
91+
"RequestMetaObject",
92+
"SubscriptionsListenResultMeta",
93+
"InputSchema",
94+
"OutputSchema",
95+
"Result",
96+
}
8997
),
9098
}
9199

src/mcp-types/mcp_types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
SubscriptionsAcknowledgedNotificationParams,
161161
SubscriptionsListenRequest,
162162
SubscriptionsListenRequestParams,
163+
SubscriptionsListenResult,
163164
Task,
164165
TaskMetadata,
165166
TasksCallCapability,
@@ -385,6 +386,7 @@
385386
"ListTasksResult",
386387
"ListToolsResult",
387388
"ReadResourceResult",
389+
"SubscriptionsListenResult",
388390
# Error data payloads
389391
"MissingRequiredClientCapabilityErrorData",
390392
"UnsupportedProtocolVersionErrorData",

src/mcp-types/mcp_types/_types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,21 @@ class SubscriptionsAcknowledgedNotification(
10631063
params: SubscriptionsAcknowledgedNotificationParams
10641064

10651065

1066+
class SubscriptionsListenResult(Result):
1067+
"""Signals that a `subscriptions/listen` stream has ended gracefully (2026-07-28).
1068+
1069+
Because the listen stream is long-lived, this result is sent only when the
1070+
server tears the subscription down (for example during shutdown); an abrupt
1071+
transport close carries no response. The body is otherwise empty: the
1072+
`_meta["io.modelcontextprotocol/subscriptionId"]` key is required on the
1073+
wire and equals the JSON-RPC id of the originating `subscriptions/listen`
1074+
request.
1075+
"""
1076+
1077+
result_type: ResultType = "complete"
1078+
"""See `ResultType`. Always serialized; older peers ignore it."""
1079+
1080+
10661081
class ListPromptsRequest(PaginatedRequest[Literal["prompts/list"]]):
10671082
"""Sent from the client to request a list of prompts and prompt templates the server has."""
10681083

@@ -2156,6 +2171,7 @@ def _require_one_field(self) -> Self:
21562171
| ReadResourceResult
21572172
| CallToolResult
21582173
| ListToolsResult
2174+
| SubscriptionsListenResult
21592175
| InputRequiredResult
21602176
)
21612177
"""Union of every result payload a server can return for a client request.

src/mcp-types/mcp_types/methods.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@
292292
("resources/read", "2026-07-28"): v2026.AnyReadResourceResult,
293293
("resources/templates/list", "2026-07-28"): v2026.ListResourceTemplatesResult,
294294
("server/discover", "2026-07-28"): v2026.DiscoverResult,
295-
("subscriptions/listen", "2026-07-28"): v2026.EmptyResult,
295+
("subscriptions/listen", "2026-07-28"): v2026.SubscriptionsListenResult,
296296
("tools/call", "2026-07-28"): v2026.AnyCallToolResult,
297297
("tools/list", "2026-07-28"): v2026.ListToolsResult,
298298
}
@@ -396,7 +396,7 @@
396396
# smart-union ties resolve leftmost. Pinned by tests/types/test_methods.py.
397397
"sampling/createMessage": types.CreateMessageResult | types.CreateMessageResultWithTools,
398398
"server/discover": types.DiscoverResult,
399-
"subscriptions/listen": types.EmptyResult,
399+
"subscriptions/listen": types.SubscriptionsListenResult,
400400
"tools/call": types.CallToolResult | types.InputRequiredResult,
401401
"tools/list": types.ListToolsResult,
402402
}

src/mcp-types/mcp_types/v2026_07_28/__init__.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Internal wire-shape models for protocol 2026-07-28. Generated; do not edit.
22
33
Regenerate with `scripts/gen_surface_types.py` from `schema/2026-07-28.json`
4-
(sha256 `ed1ad4ba94aaeb2068b78969ef901b1150f7b2f06cf86472b3032abee1380b6a`)."""
4+
(sha256 `e00f675287e8cf078688c26c8a89d283ff2613da3b76d5cd15aff9d189df639c`)."""
55
# pyright: reportIncompatibleVariableOverride=false, reportGeneralTypeIssues=false
66

77
from __future__ import annotations
@@ -909,6 +909,25 @@ class SubscriptionFilter(WireModel):
909909
"""
910910

911911

912+
class SubscriptionsListenResultMeta(WireModel):
913+
"""
914+
Extends {@link MetaObject} with the subscription-stream identifier carried by a
915+
{@link SubscriptionsListenResult}. All key naming rules from `MetaObject` apply.
916+
"""
917+
918+
model_config = ConfigDict(
919+
extra="allow",
920+
)
921+
io_modelcontextprotocol_subscription_id: Annotated[RequestId, Field(alias="io.modelcontextprotocol/subscriptionId")]
922+
"""
923+
Identifies the subscription stream this response closes, so the client can
924+
correlate it with the originating subscription — mirroring the same key on
925+
the stream's notifications. The value is the JSON-RPC ID of the
926+
`subscriptions/listen` request that opened the stream (and equals this
927+
response's `id`).
928+
"""
929+
930+
912931
class TextResourceContents(WireModel):
913932
model_config = ConfigDict(
914933
extra="ignore",
@@ -2056,6 +2075,31 @@ class SubscriptionsAcknowledgedNotificationParams(WireModel):
20562075
"""
20572076

20582077

2078+
class SubscriptionsListenResult(WireModel):
2079+
"""
2080+
The response to a {@link SubscriptionsListenRequestsubscriptions/listen}
2081+
request, signalling that the subscription has ended gracefully (for example,
2082+
during server shutdown). Because the listen stream is long-lived, this result
2083+
is sent only when the server tears the subscription down; an abrupt transport
2084+
close carries no response. The result body is otherwise empty.
2085+
"""
2086+
2087+
model_config = ConfigDict(
2088+
extra="ignore",
2089+
)
2090+
meta: Annotated[SubscriptionsListenResultMeta, Field(alias="_meta")]
2091+
result_type: Annotated[str, Field(alias="resultType")]
2092+
"""
2093+
Indicates the type of the result, which allows the client to determine
2094+
how to parse the result object.
2095+
2096+
Servers implementing this protocol version MUST include this field.
2097+
For backward compatibility, when a client receives a result from a
2098+
server implementing an earlier protocol version (which does not include
2099+
`resultType`), the client MUST treat the absent field as `"complete"`.
2100+
"""
2101+
2102+
20592103
class TextContent(WireModel):
20602104
"""
20612105
Text provided to or from an LLM.
@@ -3544,6 +3588,7 @@ class ServerResult(
35443588
| ListResourcesResult
35453589
| ListResourceTemplatesResult
35463590
| ReadResourceResult
3591+
| SubscriptionsListenResult
35473592
| ListPromptsResult
35483593
| GetPromptResult
35493594
| ListToolsResult
@@ -3558,6 +3603,7 @@ class ServerResult(
35583603
| ListResourcesResult
35593604
| ListResourceTemplatesResult
35603605
| ReadResourceResult
3606+
| SubscriptionsListenResult
35613607
| ListPromptsResult
35623608
| GetPromptResult
35633609
| ListToolsResult

src/mcp/server/lowlevel/server.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def __init__(
182182
| None = None,
183183
on_subscriptions_listen: Callable[
184184
[ServerRequestContext[LifespanResultT], types.SubscriptionsListenRequestParams],
185-
Awaitable[types.EmptyResult],
185+
Awaitable[types.SubscriptionsListenResult],
186186
]
187187
| None = None,
188188
on_list_prompts: Callable[
@@ -264,7 +264,7 @@ def __init__(
264264
| None = None,
265265
on_subscriptions_listen: Callable[
266266
[ServerRequestContext[LifespanResultT], types.SubscriptionsListenRequestParams],
267-
Awaitable[types.EmptyResult],
267+
Awaitable[types.SubscriptionsListenResult],
268268
]
269269
| None = None,
270270
on_list_prompts: Callable[
@@ -355,7 +355,7 @@ def __init__(
355355
| None = None,
356356
on_subscriptions_listen: Callable[
357357
[ServerRequestContext[LifespanResultT], types.SubscriptionsListenRequestParams],
358-
Awaitable[types.EmptyResult],
358+
Awaitable[types.SubscriptionsListenResult],
359359
]
360360
| None = None,
361361
on_list_prompts: Callable[

tests/types/test_methods.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@
268268
("resources/read", "2026-07-28"): (v2026.ReadResourceResult, v2026.InputRequiredResult),
269269
("resources/templates/list", "2026-07-28"): v2026.ListResourceTemplatesResult,
270270
("server/discover", "2026-07-28"): v2026.DiscoverResult,
271-
("subscriptions/listen", "2026-07-28"): v2026.EmptyResult,
271+
("subscriptions/listen", "2026-07-28"): v2026.SubscriptionsListenResult,
272272
("tools/call", "2026-07-28"): (v2026.CallToolResult, v2026.InputRequiredResult),
273273
("tools/list", "2026-07-28"): v2026.ListToolsResult,
274274
}
@@ -290,9 +290,7 @@
290290
("sampling/createMessage", "2025-11-25"): v2025.CreateMessageResult,
291291
}
292292

293-
EMPTY_SERVER_RESPONSE_METHODS = frozenset(
294-
{"logging/setLevel", "ping", "resources/subscribe", "resources/unsubscribe", "subscriptions/listen"}
295-
)
293+
EMPTY_SERVER_RESPONSE_METHODS = frozenset({"logging/setLevel", "ping", "resources/subscribe", "resources/unsubscribe"})
296294
EMPTY_CLIENT_RESPONSE_METHODS = frozenset({"ping"})
297295

298296
# Pre-2026 versions share the 2025-11-25 surface package.
@@ -404,7 +402,10 @@
404402
"ttlMs": 0,
405403
"cacheScope": "private",
406404
},
407-
v2026.EmptyResult: {"resultType": "complete"},
405+
v2026.SubscriptionsListenResult: {
406+
"resultType": "complete",
407+
"_meta": {"io.modelcontextprotocol/subscriptionId": 1},
408+
},
408409
v2026.ListPromptsResult: {"prompts": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"},
409410
v2026.ListResourcesResult: {"resources": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"},
410411
v2026.ListResourceTemplatesResult: {
@@ -844,7 +845,9 @@ def test_validate_functions_accept_reject_and_gate_like_their_parse_siblings():
844845
ttl_ms=0,
845846
cache_scope="private",
846847
),
847-
"subscriptions/listen": types.EmptyResult(result_type="complete"),
848+
"subscriptions/listen": types.SubscriptionsListenResult.model_validate(
849+
{"_meta": {"io.modelcontextprotocol/subscriptionId": 1}}
850+
),
848851
"tools/call": types.CallToolResult(content=[]),
849852
"tools/list": types.ListToolsResult(tools=[], ttl_ms=0, cache_scope="private"),
850853
}

tests/types/test_parity.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
"v2026_07_28.RequestedSchema",
123123
"v2026_07_28.ResourceRequestParams",
124124
"v2026_07_28.StringSchema",
125+
"v2026_07_28.SubscriptionsListenResultMeta",
125126
"v2026_07_28.TitledMultiSelectEnumSchema",
126127
"v2026_07_28.TitledSingleSelectEnumSchema",
127128
"v2026_07_28.UnsupportedProtocolVersionError",

0 commit comments

Comments
 (0)