|
32 | 32 | _CLAIM_METHODS: Final[frozenset[str]] = frozenset({"tools/call"}) |
33 | 33 | """The closed set of verbs a claim may attach to; widen together with the `method` Literal.""" |
34 | 34 |
|
| 35 | +_RESERVED_WIRE_ALIASES: Final[frozenset[str]] = frozenset({"requestState", "inputRequests"}) |
| 36 | +"""Typed optional fields of the core result surface that pre-validates every inbound result.""" |
| 37 | + |
35 | 38 | ClaimedT = TypeVar("ClaimedT", bound=Result) |
36 | 39 | NotifyParamsT = TypeVar("NotifyParamsT", bound=BaseModel) |
37 | 40 |
|
@@ -66,8 +69,17 @@ def __post_init__(self) -> None: |
66 | 69 | raise ValueError(f"claims attach to {sorted(_CLAIM_METHODS)} only; got method {self.method!r}") |
67 | 70 | if self.result_type in CORE_RESULT_TYPES: |
68 | 71 | raise ValueError(f"resultType {self.result_type!r} is core protocol vocabulary") |
| 72 | + if Result not in self.model.__mro__: # runtime guard; the ClaimedT bound only constrains checked callers |
| 73 | + raise ValueError(f"{self.model.__name__} must subclass mcp_types.Result") |
69 | 74 | if issubclass(self.model, CallToolResult | InputRequiredResult): |
70 | 75 | raise ValueError("claim models must not subclass core result types") |
| 76 | + for name, model_field in self.model.model_fields.items(): |
| 77 | + if (model_field.alias or name) in _RESERVED_WIRE_ALIASES: |
| 78 | + raise ValueError( |
| 79 | + f"{self.model.__name__}.{name} aliases {model_field.alias or name!r}, a typed field " |
| 80 | + "of the core result surface; a colliding value would fail core validation before " |
| 81 | + "the claim adapter runs" |
| 82 | + ) |
71 | 83 | field = self.model.model_fields.get("result_type") |
72 | 84 | if field is None or get_args(field.annotation) != (self.result_type,): |
73 | 85 | raise ValueError(f"{self.model.__name__}.result_type must be Literal[{self.result_type!r}]") |
@@ -101,9 +113,11 @@ def __init__(self, result: Result) -> None: |
101 | 113 | class NotificationBinding(Generic[NotifyParamsT]): |
102 | 114 | """Deliver server notifications for `method` (the bare wire name) to `handler`. |
103 | 115 |
|
104 | | - Observation-only: validated params arrive in order through a bounded queue, |
105 | | - dropping the oldest with a warning on overflow. Methods the negotiated |
106 | | - version's core tables handle are never delivered to bindings. |
| 116 | + Observation-only: validated params arrive one at a time per binding, in |
| 117 | + dispatch order, through a bounded queue that drops the oldest with a warning |
| 118 | + on overflow. Stream transports dispatch each notification independently, so |
| 119 | + near-simultaneous notifications may be dispatched out of wire order. Methods |
| 120 | + the negotiated version's core tables handle are never delivered to bindings. |
107 | 121 | """ |
108 | 122 |
|
109 | 123 | method: str |
|
0 commit comments