Tapan Chugh tapanc commited on
Commit
9d7c3c2
·
unverified ·
1 Parent(s): dbeb5a4

Skip repeated type conversion and validation in proxy client elicitation handler (#1222)

Browse files
src/fastmcp/server/proxy.py CHANGED
@@ -566,11 +566,12 @@ class ProxyClient(Client[ClientTransportT]):
566
  A handler that forwards the elicitation request from the remote server to the proxy's connected clients and relays the response back to the remote server.
567
  """
568
  ctx = get_context()
569
- result = await ctx.elicit(message, response_type)
570
- if result.action == "accept":
571
- return result.data
572
- else:
573
- return ElicitResult(action=result.action)
 
574
 
575
  @classmethod
576
  async def default_log_handler(cls, message: LogMessage) -> None:
 
566
  A handler that forwards the elicitation request from the remote server to the proxy's connected clients and relays the response back to the remote server.
567
  """
568
  ctx = get_context()
569
+ result = await ctx.session.elicit(
570
+ message=message,
571
+ requestedSchema=params.requestedSchema,
572
+ related_request_id=ctx.request_id,
573
+ )
574
+ return ElicitResult(action=result.action, content=result.content)
575
 
576
  @classmethod
577
  async def default_log_handler(cls, message: LogMessage) -> None:
tests/server/proxy/test_proxy_client.py CHANGED
@@ -4,6 +4,7 @@ from typing import cast
4
  import pytest
5
  from anyio import create_task_group
6
  from mcp.types import LoggingLevel, ModelHint, ModelPreferences, TextContent
 
7
 
8
  from fastmcp import Client, Context, FastMCP
9
  from fastmcp.client.elicitation import ElicitRequestParams, ElicitResult
@@ -330,6 +331,50 @@ class TestProxyClient:
330
  assert results["elicitation_a"] == "Hello, Alice!"
331
  assert results["elicitation_b"] == "Hello, Bob!"
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  async def test_client_factory_creates_fresh_sessions(self, fastmcp_server: FastMCP):
334
  """Test that the client factory pattern creates fresh sessions for each request."""
335
  from fastmcp.server.proxy import FastMCPProxy
 
4
  import pytest
5
  from anyio import create_task_group
6
  from mcp.types import LoggingLevel, ModelHint, ModelPreferences, TextContent
7
+ from pydantic import BaseModel, Field
8
 
9
  from fastmcp import Client, Context, FastMCP
10
  from fastmcp.client.elicitation import ElicitRequestParams, ElicitResult
 
331
  assert results["elicitation_a"] == "Hello, Alice!"
332
  assert results["elicitation_b"] == "Hello, Bob!"
333
 
334
+ async def test_elicit_with_default_values(self, fastmcp_server: FastMCP):
335
+ """
336
+ Test that the proxy client correctly handles elicitation with default values (fixes #1167).
337
+ """
338
+
339
+ @fastmcp_server.tool
340
+ async def elicit_with_defaults(context: Context) -> str:
341
+ class TestModel(BaseModel):
342
+ content: str = Field(description="Your reply content")
343
+ acknowledge: bool = Field(
344
+ default=False, description="Send immediately or save as draft"
345
+ )
346
+
347
+ result = await context.elicit(
348
+ "Please provide input:", response_type=TestModel
349
+ )
350
+
351
+ if result.action == "accept":
352
+ return f"Content: {result.data.content}, Acknowledge: {result.data.acknowledge}"
353
+ else:
354
+ return f"Elicitation {result.action}"
355
+
356
+ proxy_server = FastMCP.as_proxy(ProxyClient(fastmcp_server))
357
+
358
+ # Test that elicitation works correctly through the proxy
359
+ async def elicitation_handler(
360
+ message: str,
361
+ response_type: type,
362
+ params: ElicitRequestParams,
363
+ ctx: RequestContext,
364
+ ):
365
+ # Verify the schema is correct - acknowledge should have default=False, not be nullable
366
+ schema = params.requestedSchema
367
+ assert schema["properties"]["acknowledge"]["type"] == "boolean"
368
+ assert schema["properties"]["acknowledge"]["default"] is False
369
+
370
+ return {"content": "Test content", "acknowledge": True}
371
+
372
+ async with Client(
373
+ proxy_server, elicitation_handler=elicitation_handler
374
+ ) as client:
375
+ result = await client.call_tool("elicit_with_defaults", {})
376
+ assert result.data == "Content: Test content, Acknowledge: True"
377
+
378
  async def test_client_factory_creates_fresh_sessions(self, fastmcp_server: FastMCP):
379
  """Test that the client factory pattern creates fresh sessions for each request."""
380
  from fastmcp.server.proxy import FastMCPProxy