-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Implement SEP-1577 - Sampling With Tools #1594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add support for tool calling during sampling requests, enabling MCP servers to execute agentic workflows using client LLM capabilities. Key changes: - Add ToolUseContent type for assistant tool invocation requests - Add ToolResultContent type for tool execution results - Add ToolChoice type to control tool usage behavior - Add UserMessage and AssistantMessage types for role-specific messages - Extend SamplingMessage to support tool content (backward compatible) - Add SamplingToolsCapability for capability negotiation - Update CreateMessageRequestParams with tools and toolChoice fields - Update CreateMessageResult to support tool use content - Update StopReason to include "toolUse" value - Add comprehensive unit tests for all new types The implementation maintains backward compatibility by keeping SamplingMessage as a flexible BaseModel while adding more specific UserMessage and AssistantMessage types for type-safe tool interactions. All new types follow existing patterns: - Use Pydantic V2 BaseModel - Allow extra fields with ConfigDict(extra="allow") - Include proper docstrings and field descriptions - Support optional fields where appropriate Github-Issue: #1577
Rename SamplingCapabilityNested to SamplingCapability and the old SamplingCapability to SamplingContextCapability for better clarity. - SamplingCapability is now the main structured type with context and tools fields - SamplingContextCapability represents the deprecated context capability - Updates all exports and tests to use the new names All tests pass and type checking passes.
- Replace UserMessage/AssistantMessage with unified SamplingMessage - Add SamplingMessageContentBlock type alias for content blocks - Update CreateMessageResult to use SamplingMessageContentBlock - Remove disable_parallel_tool_use from ToolChoice (not in spec) - Add ResourceLink to ToolResultContent.content for consistency This aligns with the draft spec where SamplingMessage uses a single content type union rather than separate UserMessage/AssistantMessage classes. The CreateMessageResult now extends SamplingMessage's pattern and supports both single content blocks and arrays.
The PR changed CreateMessageResult.content to be either a single content block or a list. Code accessing .type and .text directly now needs to handle both cases by checking isinstance(content, list) first. Also add explicit dict[str, Any] type annotations to test data containing nested empty dicts to satisfy pyright's type inference.
|
pushed a couple of minor CI fixes |
bhosmer-ant
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple minor notes inline, also these less minor ones:
- runtime validations of the spec constraints are missing. some claude notes:
⏺ The validations would go in src/mcp/server/session.py:215-248 in the create_message method. This is where the server sends sampling requests
to the client.
Specifically:
- Capability check ("MUST throw when tools/toolChoice defined but sampling.tools missing"):
# Would be added before send_request:
if (tools or tool_choice) and not self._has_sampling_tools_capability():
raise McpError("Client does not support sampling tools capability")
- Content mixing validation ("tool result content blocks MUST NOT contain other content types"):
Could be validated either:
- Here when building the request messages
- Or in a Pydantic validator on SamplingMessage itself
- missing new props in the API. more claude notes:
Note that the create_message method is also missing the new tools and toolChoice parameters entirely — the PR only adds the types but
doesn't wire them into the API method. Let me verify:
⏺ Read(src/mcp/server/session.py)
⎿ Read 50 lines
⏺ This is a gap in the PR: The create_message() method at src/mcp/server/session.py:215 doesn't expose the new tools and toolChoice
parameters. Currently it only passes the old parameters to CreateMessageRequestParams.
To actually use the new feature, developers would have to bypass this helper and construct the request manually.
The PR should probably also update this method to:
async def create_message(
self,
messages: list[types.SamplingMessage],
*,
max_tokens: int,
# ... existing params ...
tools: list[types.Tool] | None = None, # NEW
tool_choice: types.ToolChoice | None = None, # NEW
) -> types.CreateMessageResult:
And add the capability validation there.
| if result.content.type == "text": | ||
| return result.content.text | ||
| return str(result.content) | ||
| content = result.content[0] if isinstance(result.content, list) else result.content |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want this as the example of how to use the new multiple content blocks :)
(same comment on other places where this pattern shows up)
| toolUseId: str | ||
| """The unique identifier that corresponds to the tool call's id field.""" | ||
|
|
||
| content: list[Union[TextContent, ImageContent, AudioContent, "ResourceLink", "EmbeddedResource"]] = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just use ContentBlock here?
Implement types from modelcontextprotocol/modelcontextprotocol#1577 (accepted)
Spec PR: modelcontextprotocol/modelcontextprotocol#1796 (merged, and follow up modelcontextprotocol/modelcontextprotocol#1842 pending review)
cc/ @bhosmer-ant
Add support for tool calling during sampling requests, enabling MCP servers to execute agentic workflows using client LLM capabilities.
modelcontextprotocol/modelcontextprotocol#1577
Key changes:
The implementation maintains backward compatibility by keeping SamplingMessage as a flexible BaseModel while adding more specific UserMessage and AssistantMessage types for type-safe tool interactions.
All new types follow existing patterns: