Skip to content

Commit 5104062

Browse files
committed
fix(server): validate elicitation form/url sub-capabilities in check_capability
Connection.check_capability() only verified that the client declared elicitation at all, not whether specific sub-capabilities (form vs url) matched. Mirror the existing sampling sub-capability checks. Fixes #2965
1 parent 603342f commit 5104062

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/mcp/server/connection.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,13 @@ def check_capability(self, capability: ClientCapabilities) -> bool:
337337
return False
338338
if capability.sampling.tools is not None and have.sampling.tools is None:
339339
return False
340-
if capability.elicitation is not None and have.elicitation is None:
341-
return False
340+
if capability.elicitation is not None:
341+
if have.elicitation is None:
342+
return False
343+
if capability.elicitation.form is not None and have.elicitation.form is None:
344+
return False
345+
if capability.elicitation.url is not None and have.elicitation.url is None:
346+
return False
342347
if capability.experimental is not None:
343348
if have.experimental is None:
344349
return False

tests/server/test_connection.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
CreateMessageRequestParams,
2222
ElicitationCapability,
2323
EmptyResult,
24+
FormElicitationCapability,
2425
Implementation,
2526
ListRootsRequest,
2627
ListRootsResult,
@@ -31,6 +32,7 @@
3132
SamplingCapability,
3233
SamplingContextCapability,
3334
SamplingToolsCapability,
35+
UrlElicitationCapability,
3436
)
3537
from mcp_types.version import LATEST_HANDSHAKE_VERSION, LATEST_MODERN_VERSION
3638
from pydantic import BaseModel, ValidationError
@@ -364,6 +366,36 @@ def test_connection_check_capability_false_when_no_client_params_recorded():
364366
(ClientCapabilities(experimental={"a": {}}), ClientCapabilities(experimental={"b": {}}), False),
365367
(ClientCapabilities(experimental={"a": {"x": 1}}), ClientCapabilities(experimental={"a": {"x": 2}}), False),
366368
(ClientCapabilities(experimental={"a": {}}), ClientCapabilities(experimental={"a": {}}), True),
369+
(
370+
ClientCapabilities(elicitation=None),
371+
ClientCapabilities(elicitation=ElicitationCapability()),
372+
False,
373+
),
374+
(
375+
ClientCapabilities(elicitation=ElicitationCapability(url=UrlElicitationCapability())),
376+
ClientCapabilities(elicitation=ElicitationCapability(form=FormElicitationCapability())),
377+
False,
378+
),
379+
(
380+
ClientCapabilities(elicitation=ElicitationCapability(form=FormElicitationCapability())),
381+
ClientCapabilities(elicitation=ElicitationCapability(url=UrlElicitationCapability())),
382+
False,
383+
),
384+
(
385+
ClientCapabilities(elicitation=ElicitationCapability(url=UrlElicitationCapability())),
386+
ClientCapabilities(elicitation=ElicitationCapability(url=UrlElicitationCapability())),
387+
True,
388+
),
389+
(
390+
ClientCapabilities(elicitation=ElicitationCapability(form=FormElicitationCapability())),
391+
ClientCapabilities(elicitation=ElicitationCapability(form=FormElicitationCapability())),
392+
True,
393+
),
394+
(
395+
ClientCapabilities(elicitation=ElicitationCapability(url=UrlElicitationCapability())),
396+
ClientCapabilities(elicitation=ElicitationCapability()),
397+
True,
398+
),
367399
],
368400
)
369401
def test_check_capability_per_field_branches(have: ClientCapabilities, want: ClientCapabilities, expected: bool):

0 commit comments

Comments
 (0)