Fix elicitation graceful degradation when client lacks protocol support
ctx.elicit() throws an exception (not CancelledElicitation) when the MCP client doesn't implement the elicitation/create JSON-RPC method. Wrap the call in try/except to treat protocol-level rejection the same as CancelledElicitation. Found during live testing with Claude Code CLI which doesn't support MCP elicitation yet.
This commit is contained in:
parent
5fa1eb36ef
commit
89419a36c2
@ -25,13 +25,19 @@ from mcdbus._state import mcp
|
||||
|
||||
async def _confirm_or_abort(ctx: Context, message: str, operation: str) -> None:
|
||||
"""Elicit user confirmation; raise ToolError or return silently to proceed."""
|
||||
result = await ctx.elicit(
|
||||
message,
|
||||
{
|
||||
"confirm": {"title": "Yes, proceed"},
|
||||
"deny": {"title": "No, cancel"},
|
||||
},
|
||||
)
|
||||
try:
|
||||
result = await ctx.elicit(
|
||||
message,
|
||||
{
|
||||
"confirm": {"title": "Yes, proceed"},
|
||||
"deny": {"title": "No, cancel"},
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
# Client doesn't implement elicitation at the protocol level —
|
||||
# ctx.elicit() throws instead of returning CancelledElicitation.
|
||||
result = CancelledElicitation()
|
||||
|
||||
if isinstance(result, AcceptedElicitation) and result.data == "confirm":
|
||||
return
|
||||
if isinstance(result, CancelledElicitation):
|
||||
|
||||
@ -48,6 +48,21 @@ class TestConfirmOrAbort:
|
||||
with pytest.raises(ToolError, match="Elicitation required"):
|
||||
await _confirm_or_abort(ctx, "Test message", "test_op")
|
||||
|
||||
async def test_elicit_exception_treated_as_cancelled(self):
|
||||
"""When ctx.elicit() throws (client lacks protocol support), proceed."""
|
||||
ctx = AsyncMock()
|
||||
ctx.elicit = AsyncMock(side_effect=Exception("Method not found"))
|
||||
# Should not raise — exception is treated as CancelledElicitation
|
||||
await _confirm_or_abort(ctx, "Test message", "test_op")
|
||||
|
||||
async def test_elicit_exception_hard_fails_when_required(self):
|
||||
"""When ctx.elicit() throws and MCDBUS_REQUIRE_ELICITATION is set, fail."""
|
||||
ctx = AsyncMock()
|
||||
ctx.elicit = AsyncMock(side_effect=Exception("Method not found"))
|
||||
with patch.dict(os.environ, {"MCDBUS_REQUIRE_ELICITATION": "1"}):
|
||||
with pytest.raises(ToolError, match="Elicitation required"):
|
||||
await _confirm_or_abort(ctx, "Test message", "test_op")
|
||||
|
||||
|
||||
class TestCallMethodElicitation:
|
||||
"""Verify call_method triggers elicitation on system bus but not session bus."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user