Skip to content

Commit c096d99

Browse files
mochow13Motta KinDouweM
authored
Expose MCP server instructions in MCPServer.instructions property (#3431)
Co-authored-by: Motta Kin <[email protected]> Co-authored-by: Douwe Maan <[email protected]>
1 parent 468e60a commit c096d99

File tree

5 files changed

+48
-1
lines changed

5 files changed

+48
-1
lines changed

docs/mcp/client.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,29 @@ calculator_server = MCPServerSSE(
338338
agent = Agent('openai:gpt-5', toolsets=[weather_server, calculator_server])
339339
```
340340

341+
## Server Instructions
342+
343+
MCP servers can provide instructions during initialization that give context about how to best interact with the server's tools. These instructions are accessible via the [`instructions`][pydantic_ai.mcp.MCPServer.instructions] property after the server connection is established.
344+
345+
```python {title="mcp_server_instructions.py"}
346+
from pydantic_ai import Agent
347+
from pydantic_ai.mcp import MCPServerStreamableHTTP
348+
349+
server = MCPServerStreamableHTTP('http://localhost:8000/mcp')
350+
agent = Agent('openai:gpt-5', toolsets=[server])
351+
352+
@agent.instructions
353+
async def mcp_server_instructions():
354+
return server.instructions # (1)!
355+
356+
async def main():
357+
result = await agent.run('What is 7 plus 5?')
358+
print(result.output)
359+
#> The answer is 12.
360+
```
361+
362+
1. The server connection is guaranteed to be established by this point, so `server.instructions` is available.
363+
341364
## Tool metadata
342365

343366
MCP tools can include metadata that provides additional information about the tool's characteristics, which can be useful when [filtering tools][pydantic_ai.toolsets.FilteredToolset]. The `meta`, `annotations`, and `output_schema` fields can be found on the `metadata` dict on the [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] object that's passed to filter functions.

pydantic_ai_slim/pydantic_ai/mcp.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ class MCPServer(AbstractToolset[Any], ABC):
122122
_read_stream: MemoryObjectReceiveStream[SessionMessage | Exception]
123123
_write_stream: MemoryObjectSendStream[SessionMessage]
124124
_server_info: mcp_types.Implementation
125+
_instructions: str | None
125126

126127
def __init__(
127128
self,
@@ -200,6 +201,15 @@ def server_info(self) -> mcp_types.Implementation:
200201
)
201202
return self._server_info
202203

204+
@property
205+
def instructions(self) -> str | None:
206+
"""Access the instructions sent by the MCP server during initialization."""
207+
if not hasattr(self, '_instructions'):
208+
raise AttributeError(
209+
f'The `{self.__class__.__name__}.instructions` is only available after initialization.'
210+
)
211+
return self._instructions
212+
203213
async def list_tools(self) -> list[mcp_types.Tool]:
204214
"""Retrieve tools that are currently active on the server.
205215
@@ -337,6 +347,7 @@ async def __aenter__(self) -> Self:
337347
with anyio.fail_after(self.timeout):
338348
result = await self._client.initialize()
339349
self._server_info = result.serverInfo
350+
self._instructions = result.instructions
340351
if log_level := self.log_level:
341352
await self._client.set_logging_level(log_level)
342353

tests/mcp_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
)
1717
from pydantic import AnyUrl, BaseModel
1818

19-
mcp = FastMCP('Pydantic AI MCP Server')
19+
mcp = FastMCP('Pydantic AI MCP Server', instructions='Be a helpful assistant.')
2020
log_level = 'unset'
2121

2222

tests/test_examples.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ class MockMCPServer(AbstractToolset[Any]):
304304
def id(self) -> str | None:
305305
return None # pragma: no cover
306306

307+
@property
308+
def instructions(self) -> str | None:
309+
return None
310+
307311
async def __aenter__(self) -> MockMCPServer:
308312
return self
309313

tests/test_mcp.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,15 @@ async def test_server_info(mcp_server: MCPServerStdio) -> None:
17571757
assert mcp_server.server_info.name == 'Pydantic AI MCP Server'
17581758

17591759

1760+
async def test_instructions(mcp_server: MCPServerStdio) -> None:
1761+
with pytest.raises(
1762+
AttributeError, match='The `MCPServerStdio.instructions` is only available after initialization.'
1763+
):
1764+
mcp_server.instructions
1765+
async with mcp_server:
1766+
assert mcp_server.instructions == 'Be a helpful assistant.'
1767+
1768+
17601769
async def test_agent_run_stream_with_mcp_server_http(allow_model_requests: None, model: Model):
17611770
server = MCPServerStreamableHTTP(url='https://mcp.deepwiki.com/mcp', timeout=30)
17621771
agent = Agent(model, toolsets=[server], instructions='Be concise.')

0 commit comments

Comments
 (0)