Skip to content

Commit 97b6993

Browse files
committed
Addressing comments
1 parent 9bb8e06 commit 97b6993

File tree

6 files changed

+167
-112
lines changed

6 files changed

+167
-112
lines changed

docs/builtin-tools.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -448,9 +448,9 @@ agent = Agent(
448448
'anthropic:claude-sonnet-4-0',
449449
builtin_tools=[
450450
MCPServerTool(
451-
server_label='your-mcp-server',
452-
server_url='https://example.com/mcp-server',
453-
server_description='Your MCP Server',
451+
label='your-mcp-server',
452+
url='https://example.com/mcp-server',
453+
description='Your MCP Server',
454454
authorization='$YOUR_AUTHORIZATION_TOKEN',
455455
)
456456
]
@@ -472,9 +472,9 @@ agent = Agent(
472472
'openai-responses:gpt-4o',
473473
builtin_tools=[
474474
MCPServerTool(
475-
server_label='your-mcp-server',
476-
server_url='https://example.com/mcp-server',
477-
server_description='Your MCP Server',
475+
label='your-mcp-server',
476+
url='https://example.com/mcp-server',
477+
description='Your MCP Server',
478478
authorization='$YOUR_AUTHORIZATION_TOKEN',
479479
)
480480
]
@@ -498,9 +498,9 @@ agent = Agent(
498498
'openai-responses:gpt-4o',
499499
builtin_tools=[
500500
MCPServerTool(
501-
server_label='your-mcp-server',
502-
server_url='https://example.com/mcp-server',
503-
server_description='Your MCP Server',
501+
label='your-mcp-server',
502+
url='https://example.com/mcp-server',
503+
description='Your MCP Server',
504504
authorization='$YOUR_AUTHORIZATION_TOKEN',
505505
allowed_tools=['tool-1', 'tool-2'],
506506
headers={'X-CUSTOM-HEADER': 'custom-value'},

pydantic_ai_slim/pydantic_ai/builtin_tools.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -251,28 +251,53 @@ class MCPServerTool(AbstractBuiltinTool):
251251

252252
kind: str = 'mcp_server'
253253

254-
server_label: str
254+
label: str
255255
"""The label of the MCP server to use."""
256256

257-
server_url: str
258-
"""The URL of the MCP server to use."""
259-
260-
server_description: str
257+
description: str
261258
"""A description of the MCP server."""
262259

263-
allowed_tools: list[str] | None = None
264-
"""A list of tools that the MCP server can use."""
265-
266260
authorization: str
267261
"""Authorization header to use when making requests to the MCP server."""
268262

263+
url: str | None = None
264+
"""The URL of the MCP server to use.
265+
266+
For OpenAI Responses, one of `url` or `connector_id` must be provided.
267+
"""
268+
269+
allowed_tools: list[str] | None = None
270+
"""A list of tools that the MCP server can use.
271+
272+
Supported by:
273+
274+
* OpenAI Responses
275+
* Anthropic
276+
"""
277+
269278
headers: dict[str, str] | None = None
270279
"""Optional HTTP headers to send to the MCP server.
271280
272281
Use for authentication or other purposes.
282+
283+
Supported by:
284+
285+
* OpenAI Responses
273286
"""
274287

275-
connector_id: str | None = None
288+
connector_id: (
289+
Literal[
290+
'connector_dropbox',
291+
'connector_gmail',
292+
'connector_googlecalendar',
293+
'connector_googledrive',
294+
'connector_microsoftteams',
295+
'connector_outlookcalendar',
296+
'connector_outlookemail',
297+
'connector_sharepoint',
298+
]
299+
| None
300+
) = None
276301
"""The ID of the connector to use.
277302
278303
Supported by:

pydantic_ai_slim/pydantic_ai/models/anthropic.py

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
BetaInputJSONDelta,
7171
BetaMCPToolResultBlock,
7272
BetaMCPToolUseBlock,
73+
BetaMCPToolUseBlockParam,
7374
BetaMemoryTool20250818Param,
7475
BetaMessage,
7576
BetaMessageParam,
@@ -268,8 +269,7 @@ async def _messages_create(
268269
) -> BetaMessage | AsyncStream[BetaRawMessageStreamEvent]:
269270
# standalone function to make it easier to override
270271
tools = self._get_tools(model_request_parameters)
271-
tools, beta_features = self._add_builtin_tools(tools, model_request_parameters)
272-
mcp_servers, beta_features = self._get_mcp_servers(model_request_parameters, beta_features)
272+
tools, mcp_servers, beta_features = self._add_builtin_tools(tools, model_request_parameters)
273273

274274
tool_choice: BetaToolChoiceParam | None
275275

@@ -325,8 +325,6 @@ def _process_response(self, response: BetaMessage) -> ModelResponse:
325325
"""Process a non-streamed response, and prepare a message to return."""
326326
items: list[ModelResponsePart] = []
327327
for item in response.content:
328-
from anthropic.types.beta import BetaMCPToolUseBlock
329-
330328
if isinstance(item, BetaTextBlock):
331329
items.append(TextPart(content=item.text))
332330
elif isinstance(item, BetaServerToolUseBlock):
@@ -395,8 +393,9 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[B
395393

396394
def _add_builtin_tools(
397395
self, tools: list[BetaToolUnionParam], model_request_parameters: ModelRequestParameters
398-
) -> tuple[list[BetaToolUnionParam], list[str]]:
396+
) -> tuple[list[BetaToolUnionParam], list[BetaRequestMCPServerURLDefinitionParam], list[str]]:
399397
beta_features: list[str] = []
398+
mcp_servers: list[BetaRequestMCPServerURLDefinitionParam] = []
400399
for tool in model_request_parameters.builtin_tools:
401400
if isinstance(tool, WebSearchTool):
402401
user_location = UserLocation(type='approximate', **tool.user_location) if tool.user_location else None
@@ -420,36 +419,26 @@ def _add_builtin_tools(
420419
tools = [tool for tool in tools if tool['name'] != 'memory']
421420
tools.append(BetaMemoryTool20250818Param(name='memory', type='memory_20250818'))
422421
beta_features.append('context-management-2025-06-27')
423-
elif isinstance(tool, MCPServerTool):
424-
# Anthropic MCP servers are a separate parameter in the API call
425-
pass
422+
if isinstance(tool, MCPServerTool) and tool.url:
423+
tool_configuration = BetaRequestMCPServerToolConfigurationParam(
424+
enabled=True,
425+
allowed_tools=tool.allowed_tools,
426+
)
427+
mcp_servers.append(
428+
BetaRequestMCPServerURLDefinitionParam(
429+
type='url',
430+
name=tool.label,
431+
url=tool.url,
432+
authorization_token=tool.authorization,
433+
tool_configuration=tool_configuration,
434+
)
435+
)
436+
beta_features.append('mcp-client-2025-04-04')
426437
else: # pragma: no cover
427438
raise UserError(
428439
f'`{tool.__class__.__name__}` is not supported by `AnthropicModel`. If it should be, please file an issue.'
429440
)
430-
return tools, beta_features
431-
432-
def _get_mcp_servers(
433-
self, model_request_parameters: ModelRequestParameters, beta_features: list[str]
434-
) -> tuple[list[BetaRequestMCPServerURLDefinitionParam], list[str]]:
435-
mcp_servers: list[BetaRequestMCPServerURLDefinitionParam] = []
436-
for tool in model_request_parameters.builtin_tools:
437-
if isinstance(tool, MCPServerTool):
438-
tool_configuration = BetaRequestMCPServerToolConfigurationParam(
439-
enabled=True,
440-
allowed_tools=tool.allowed_tools,
441-
)
442-
mcp_servers.append(
443-
BetaRequestMCPServerURLDefinitionParam(
444-
type='url',
445-
name=tool.server_label,
446-
url=tool.server_url,
447-
authorization_token=tool.authorization,
448-
tool_configuration=tool_configuration,
449-
)
450-
)
451-
beta_features.append('mcp-client-2025-04-04')
452-
return mcp_servers, beta_features
441+
return tools, mcp_servers, beta_features
453442

454443
async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[BetaMessageParam]]: # noqa: C901
455444
"""Just maps a `pydantic_ai.Message` to a `anthropic.types.MessageParam`."""
@@ -495,6 +484,8 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Be
495484
| BetaCodeExecutionToolResultBlockParam
496485
| BetaThinkingBlockParam
497486
| BetaRedactedThinkingBlockParam
487+
| BetaMCPToolUseBlockParam
488+
| BetaMCPToolResultBlock
498489
] = []
499490
for response_part in m.parts:
500491
if isinstance(response_part, TextPart):
@@ -553,6 +544,16 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Be
553544
input=response_part.args_as_dict(),
554545
)
555546
assistant_content_params.append(server_tool_use_block_param)
547+
elif response_part.tool_name == MCPServerTool.kind: # pragma: no branch
548+
args = response_part.args_as_dict()
549+
mcp_tool_use_block_param = BetaMCPToolUseBlockParam(
550+
id=tool_use_id,
551+
type='mcp_tool_use',
552+
name=response_part.tool_name,
553+
server_name=cast(str, args.get('server_name')),
554+
input=args.get('input'),
555+
)
556+
assistant_content_params.append(mcp_tool_use_block_param)
556557
elif isinstance(response_part, BuiltinToolReturnPart):
557558
if response_part.provider_name == self.system:
558559
tool_use_id = _guard_tool_call_id(t=response_part)
@@ -584,6 +585,21 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Be
584585
),
585586
)
586587
)
588+
elif response_part.tool_name in ( # pragma: no branch
589+
MCPServerTool.kind,
590+
'mcp_tool_result', # Backward compatibility
591+
) and isinstance(response_part.content, str | list):
592+
assistant_content_params.append(
593+
BetaMCPToolResultBlock(
594+
tool_use_id=tool_use_id,
595+
type='mcp_tool_result',
596+
content=cast(
597+
str | list[BetaTextBlock],
598+
response_part.content, # pyright: ignore[reportUnknownMemberType]
599+
),
600+
is_error=False,
601+
)
602+
)
587603
elif isinstance(response_part, FilePart): # pragma: no cover
588604
# Files generated by models are not sent back to models that don't themselves generate files.
589605
pass
@@ -870,7 +886,7 @@ def _map_mcp_server_use_block(item: BetaMCPToolUseBlock, provider_name: str) ->
870886
return BuiltinToolCallPart(
871887
provider_name=provider_name,
872888
tool_name=MCPServerTool.kind,
873-
args=cast(dict[str, Any], item.input) or None,
889+
args=cast(dict[str, Any], {'input': item.input, 'server_name': item.server_name}) or None,
874890
tool_call_id=item.id,
875891
)
876892

@@ -883,7 +899,7 @@ def _map_mcp_server_use_block(item: BetaMCPToolUseBlock, provider_name: str) ->
883899
def _map_mcp_server_result_block(item: BetaMCPToolResultBlock, provider_name: str) -> BuiltinToolReturnPart:
884900
return BuiltinToolReturnPart(
885901
provider_name=provider_name,
886-
tool_name=CodeExecutionTool.kind,
902+
tool_name=MCPServerTool.kind,
887903
content=mcp_server_result_content_ta.dump_python(item.content, mode='json'),
888904
tool_call_id=item.tool_use_id,
889905
)

0 commit comments

Comments
 (0)