-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #736 from Mirascope/release/v1.12
Release/v1.12
- Loading branch information
Showing
16 changed files
with
2,702 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# MCP Client | ||
|
||
!!! mira "" | ||
|
||
<div align="center"> | ||
If you haven't already, we recommend first reading the section on [MCP Server](./mcp_server.md) | ||
</div> | ||
|
||
MCP Client in Mirascope enables you to interact with MCP servers through a standardized protocol. The client provides methods to access resources, tools, and prompts exposed by MCP servers. | ||
|
||
## Basic Usage and Syntax | ||
|
||
Let's connect to our book recommendation server using the MCP client: | ||
|
||
```python hl_lines="11-15 19-26 28-33 35 39 44-47" | ||
--8<-- "examples/learn/mcp/client.py" | ||
``` | ||
|
||
This example demonstrates: | ||
|
||
1. Creating server parameters with `StdioServerParameters` | ||
2. Using the `create_mcp_client` context manager to connect to the server | ||
3. Accessing server components: | ||
- Listing and using prompts | ||
- Reading resources | ||
- Using tools with Mirascope calls | ||
|
||
## Client Components | ||
|
||
### Server Connection | ||
|
||
To connect to an MCP server, use the `create_mcp_client` context manager with appropriate server parameters: | ||
|
||
```python hl_lines="3-7 11" | ||
--8<-- "examples/learn/mcp/client.py:9:19" | ||
``` | ||
|
||
The `StdioServerParameters` specify how to launch and connect to the server process. | ||
|
||
### Prompts | ||
|
||
You can list available prompts and get prompt templates from the server: | ||
|
||
```python | ||
--8<-- "examples/learn/mcp/client.py:20:26" | ||
``` | ||
|
||
The client automatically converts server prompts into Mirascope-compatible prompt templates that return `BaseMessageParam` instances. | ||
|
||
### Resources | ||
|
||
Resources can be listed and read from the server: | ||
|
||
```python | ||
--8<-- "examples/learn/mcp/client.py:28:33" | ||
``` | ||
|
||
The client provides methods to: | ||
- `list_resources()`: Get available resources | ||
- `read_resource(uri)`: Read resource content by URI | ||
|
||
### Tools | ||
|
||
Tools from the server can be used with Mirascope's standard call decorators: | ||
|
||
```python hl_lines="1 5 10-13" | ||
--8<-- "examples/learn/mcp/client.py:35:47" | ||
``` | ||
|
||
The client automatically converts server tools into Mirascope-compatible tool types that can be used with any provider's call decorator. | ||
|
||
## Type Safety | ||
|
||
The MCP client preserves type information from the server: | ||
|
||
1. **Prompts**: Arguments and return types from server prompt definitions | ||
2. **Resources**: MIME types and content types for resources | ||
3. **Tools**: Input schemas and return types for tools | ||
|
||
This enables full editor support and type checking when using server components. | ||
|
||
|
||
## Next Steps | ||
|
||
By using the MCP client with Mirascope's standard features like [Calls](../calls.md), [Tools](../tools.md), and [Prompts](../prompts.md), you can build powerful applications that leverage local services through MCP servers. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# MCP Server | ||
|
||
!!! mira "" | ||
|
||
<div align="center"> | ||
If you haven't already, we recommend first reading the section on [Tools](./tools.md) and [Calls](./calls.md) | ||
</div> | ||
|
||
MCP (Model Context Protocol) Server in Mirascope enables you to expose resources, tools, and prompts to LLM clients through a standardized protocol. This allows for secure and controlled interactions between host applications (like Claude Desktop) and local services. | ||
|
||
## Basic Usage and Syntax | ||
|
||
Let's build a simple book recommendation server using MCP: | ||
|
||
```python hl_lines="7 10 27-32 40" | ||
--8<-- "examples/learn/mcp/server_decorators.py:3" | ||
``` | ||
|
||
|
||
This example demonstrates: | ||
|
||
1. Creating an MCP server with the `MCPServer` class | ||
2. Registering a tool to get book recommendations by genre | ||
3. Exposing a books database as a resource | ||
4. Creating a prompt template for book recommendations | ||
5. Running the server asynchronously | ||
|
||
## Server Components | ||
|
||
### Tools | ||
|
||
Tools in MCP Server expose callable functions to clients. Tools can be registered using the `@app.tool()` decorator, which follows the same patterns as described in the [Tools](./tools.md) documentation: | ||
|
||
```python | ||
--8<-- "examples/learn/mcp/server_decorators.py:12:26" | ||
``` | ||
|
||
The `@app.tool()` decorator supports all the same functionality as the standard Mirascope tool decorators, including: | ||
|
||
- Function-based tools | ||
- Class-based tools inheriting from `BaseTool` | ||
- Tool configurations and validation | ||
- Computed fields and dynamic configuration | ||
|
||
See the [Tools documentation](.././tools.md) for more details on defining and using tools. | ||
|
||
### Resources | ||
|
||
Resources provide access to data through URIs. They can be registered using the `@app.resource()` decorator with configuration options: | ||
|
||
```python | ||
--8<-- "examples/learn/mcp/server_decorators.py:29:39" | ||
``` | ||
|
||
Resources support both synchronous and asynchronous functions, making them flexible for different types of data access. | ||
|
||
### Prompts | ||
|
||
Prompts define reusable message templates. They can be registered using the `@app.prompt()` decorator, which provides the same functionality as the standard Mirascope `@prompt_template` decorator described in the [Prompts](./prompts.md) documentation: | ||
|
||
```python | ||
--8<-- "examples/learn/mcp/server_decorators.py:42:49" | ||
``` | ||
|
||
The `@app.prompt()` decorator supports all the features of standard Mirascope prompts, including: | ||
|
||
- String templates | ||
- Multi-line prompts | ||
- Chat history | ||
- Object attribute access | ||
- Format specifiers | ||
- Computed fields and dynamic configuration | ||
|
||
See the [Prompts documentation](.././prompts.md) for more details on creating and using prompts. | ||
|
||
## Alternative Definition Style | ||
|
||
In addition to using decorators, you can also define your functions first and then register them when creating the MCP server. This style enables better function reusability and separation of concerns: | ||
|
||
```python hl_lines="46-59" | ||
--8<-- "examples/learn/mcp/server.py:3:69" | ||
``` | ||
|
||
This alternative style offers several advantages: | ||
|
||
1. **Function Reusability**: Functions can be used both independently and as part of the MCP server | ||
2. **Cleaner Separation**: Clear separation between function definitions and server configuration | ||
3. **Easier Testing**: Functions can be tested in isolation before being registered with the server | ||
4. **Code Organization**: Related functions can be grouped together in separate modules | ||
|
||
The same applies for prompts defined with `@prompt_template` - see the [Prompts](.././prompts.md) documentation for more details about prompt reusability. | ||
|
||
Both the decorator style and this alternative style are fully supported - choose the one that better fits your application's needs. | ||
|
||
## Next Steps | ||
|
||
By leveraging MCP Server in Mirascope, you can create secure and standardized integrations between LLM clients and local services. This enables powerful capabilities while maintaining control over how LLMs interact with your systems. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
The Name of the Wind by Patrick Rothfuss | ||
The Silent Patient by Alex Michaelides |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import asyncio | ||
|
||
from pathlib import Path | ||
|
||
from mirascope.core import openai | ||
from mirascope.mcp.client import create_mcp_client, StdioServerParameters | ||
|
||
|
||
server_file = Path(__file__).parent / "server.py" | ||
|
||
server_params = StdioServerParameters( | ||
command="uv", | ||
args=["run", "python", str(server_file)], | ||
env=None, | ||
) | ||
|
||
|
||
async def main() -> None: | ||
async with create_mcp_client(server_params) as client: | ||
prompts = await client.list_prompts() | ||
print(prompts[0]) | ||
# name='recommend_book' description='Get book recommendations by genre.' arguments=[PromptArgument(name='genre', description='Genre of book to recommend (fantasy, mystery, sci-fi, etc.)', required=True)] | ||
prompt_template = await client.get_prompt_template(prompts[0].name) | ||
prompt = await prompt_template(genre="fantasy") | ||
print(prompt) | ||
# [BaseMessageParam(role='user', content='Recommend a fantasy book')] | ||
|
||
resources = await client.list_resources() | ||
resource = await client.read_resource(resources[0].uri) | ||
print(resources[0]) | ||
# uri=AnyUrl('file://books.txt/') name='Books Database' description='Read the books database file.' mimeType='text/plain' | ||
print(resource) | ||
# ['The Name of the Wind by Patrick Rothfuss\nThe Silent Patient by Alex Michaelides'] | ||
|
||
tools = await client.list_tools() | ||
|
||
@openai.call( | ||
"gpt-4o-mini", | ||
tools=tools, | ||
) | ||
def recommend_book(genre: str) -> str: | ||
return f"Recommend a {genre} book" | ||
|
||
if tool := recommend_book("fantasy").tool: | ||
call_result = await tool.call() | ||
print(call_result) | ||
# ['The Name of the Wind by Patrick Rothfuss'] | ||
|
||
|
||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Example of MCP server for book recommendations.""" | ||
|
||
import asyncio | ||
from pathlib import Path | ||
|
||
from mcp.types import Resource | ||
|
||
from pydantic import AnyUrl | ||
|
||
from mirascope.core import prompt_template | ||
from mirascope.mcp import MCPServer | ||
|
||
|
||
def get_book(genre: str) -> str: | ||
"""Get a recommendation for a specific book genre. | ||
Args: | ||
genre: Genre of book (fantasy, mystery, sci-fi, etc.) | ||
""" | ||
book_recommendations = { | ||
"fantasy": "The Name of the Wind by Patrick Rothfuss", | ||
"mystery": "The Silent Patient by Alex Michaelides", | ||
"sci-fi": "Project Hail Mary by Andy Weir", | ||
"romance": "The Love Hypothesis by Ali Hazelwood", | ||
"historical": "The Seven Husbands of Evelyn Hugo by Taylor Jenkins Reid", | ||
} | ||
return book_recommendations.get(genre, "Please specify a valid genre") | ||
|
||
|
||
async def read_books_database(): | ||
"""Read the books database file.""" | ||
data = Path(__file__).parent / "books.txt" | ||
with data.open() as f: | ||
return f.read() | ||
|
||
|
||
@prompt_template() | ||
def recommend_book(genre: str) -> str: | ||
"""Get book recommendations by genre. | ||
Args: | ||
genre: Genre of book to recommend (fantasy, mystery, sci-fi, etc.) | ||
""" | ||
return f"Recommend a {genre} book" | ||
|
||
|
||
# Create a server for book recommendations | ||
app = MCPServer( | ||
name="book-recommendations", # Server name | ||
version="1.0.0", # Server version | ||
tools=[get_book], # Pre-register tools | ||
resources=[ # Pre-register resources | ||
( | ||
Resource( | ||
uri=AnyUrl("file://books.txt"), | ||
name="Books Database", | ||
mimeType="text/plain", | ||
), | ||
read_books_database, | ||
) | ||
], | ||
prompts=[recommend_book], # Pre-register prompts | ||
) | ||
|
||
|
||
async def main(): | ||
"""Run the book recommendation server.""" | ||
await app.run() | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
"""Example of MCP server for book recommendations.""" | ||
|
||
import asyncio | ||
from pathlib import Path | ||
|
||
from mirascope.mcp import MCPServer | ||
|
||
# Create a server for book recommendations | ||
app = MCPServer("book-recommendations") | ||
|
||
|
||
@app.tool() | ||
def get_book(genre: str) -> str: | ||
"""Get a recommendation for a specific book genre. | ||
Args: | ||
genre: Genre of book (fantasy, mystery, sci-fi, etc.) | ||
""" | ||
book_recommendations = { | ||
"fantasy": "The Name of the Wind by Patrick Rothfuss", | ||
"mystery": "The Silent Patient by Alex Michaelides", | ||
"sci-fi": "Project Hail Mary by Andy Weir", | ||
"romance": "The Love Hypothesis by Ali Hazelwood", | ||
"historical": "The Seven Husbands of Evelyn Hugo by Taylor Jenkins Reid", | ||
} | ||
return book_recommendations.get(genre, "Please specify a valid genre") | ||
|
||
|
||
@app.resource( | ||
uri="file://books.txt", | ||
name="Books Database", | ||
mime_type="text/plain", | ||
description="Curated database of book recommendations by genre", | ||
) | ||
async def read_books_database(): | ||
"""Read the books database file.""" | ||
data = Path(__file__).parent / "books.txt" | ||
with data.open() as f: | ||
return f.read() | ||
|
||
|
||
@app.prompt() | ||
def recommend_book(genre: str) -> str: | ||
"""Get book recommendations by genre. | ||
Args: | ||
genre: Genre of book to recommend (fantasy, mystery, sci-fi, etc.) | ||
""" | ||
return f"Recommend a {genre} book" | ||
|
||
|
||
async def main(): | ||
"""Run the book recommendation server.""" | ||
await app.run() | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
"""Mirascope Model Context Protocol (MCP) implementation.""" | ||
|
||
from .server import MCPServer | ||
from .tools import MCPTool | ||
|
||
__all__ = ["MCPServer", "MCPTool"] |
Oops, something went wrong.