docs/api-reference/python/type-hints.mdx
2024-11-20 12:24:08 -05:00

359 lines
No EOL
8.7 KiB
Text

---
title: "Python type hints"
description: "Python type system documentation"
---
## Core types
### Resource types
```python
from typing import TypedDict, Optional, Literal, Union, List
class Resource(TypedDict):
"""Represents a resource that can be accessed through MCP."""
uri: str
name: str
description: Optional[str]
mimeType: Optional[str]
class ResourceTemplate(TypedDict):
"""Template for constructing resource URIs."""
uriTemplate: str
name: str
description: Optional[str]
mimeType: Optional[str]
class ResourceContents(TypedDict):
"""Contents of a specific resource."""
uri: str
mimeType: Optional[str]
class TextResourceContents(ResourceContents):
"""Resource contents in text format."""
text: str
class BlobResourceContents(ResourceContents):
"""Resource contents in binary format."""
blob: bytes # Base64 encoded
```
### Message types
```python
class TextContent(TypedDict):
"""Text content in a message."""
type: Literal["text"]
text: str
class ImageContent(TypedDict):
"""Image content in a message."""
type: Literal["image"]
data: str # Base64 encoded
mimeType: str
MessageContent = Union[TextContent, ImageContent]
class Message(TypedDict):
"""A message in an LLM conversation."""
role: Literal["user", "assistant"]
content: MessageContent
```
### Tool types
```python
class ToolParameter(TypedDict):
"""Parameter definition for a tool."""
type: str
description: Optional[str]
required: Optional[bool]
class ToolSchema(TypedDict):
"""JSON Schema for tool parameters."""
type: Literal["object"]
properties: dict[str, ToolParameter]
required: Optional[List[str]]
class Tool(TypedDict):
"""Definition of a tool that can be called through MCP."""
name: str
description: str
inputSchema: ToolSchema
```
### Prompt types
```python
class PromptArgument(TypedDict):
"""Argument definition for a prompt template."""
name: str
description: Optional[str]
required: Optional[bool]
class Prompt(TypedDict):
"""A prompt template that can be used through MCP."""
name: str
description: Optional[str]
arguments: Optional[List[PromptArgument]]
class PromptResponse(TypedDict):
"""Response to a prompt request."""
description: Optional[str]
messages: List[Message]
```
### Progress types
```python
class Progress(TypedDict):
"""Progress information for long-running operations."""
progress: int
total: Optional[int]
```
### Logging types
```python
LogLevel = Literal["debug", "info", "warning", "error"]
class LogMessage(TypedDict):
"""A log message sent through MCP."""
level: LogLevel
logger: Optional[str]
data: Any # JSON-serializable value
```
## Request/Response types
### Resource requests
```python
class ListResourcesRequest(TypedDict):
"""Request to list available resources."""
cursor: Optional[str]
class ListResourcesResponse(TypedDict):
"""Response containing available resources."""
resources: List[Resource]
nextCursor: Optional[str]
class ReadResourceRequest(TypedDict):
"""Request to read a specific resource."""
uri: str
class ReadResourceResponse(TypedDict):
"""Response containing resource contents."""
contents: List[Union[TextResourceContents, BlobResourceContents]]
class SubscribeRequest(TypedDict):
"""Request to subscribe to resource updates."""
uri: str
class UnsubscribeRequest(TypedDict):
"""Request to unsubscribe from resource updates."""
uri: str
```
### Tool requests
```python
class ListToolsRequest(TypedDict):
"""Request to list available tools."""
cursor: Optional[str]
class ListToolsResponse(TypedDict):
"""Response containing available tools."""
tools: List[Tool]
nextCursor: Optional[str]
class CallToolRequest(TypedDict):
"""Request to call a specific tool."""
name: str
arguments: Optional[dict]
class CallToolResponse(TypedDict):
"""Response from a tool call."""
toolResult: Any # JSON-serializable value
```
### Prompt requests
```python
class ListPromptsRequest(TypedDict):
"""Request to list available prompts."""
cursor: Optional[str]
class ListPromptsResponse(TypedDict):
"""Response containing available prompts."""
prompts: List[Prompt]
nextCursor: Optional[str]
class GetPromptRequest(TypedDict):
"""Request to get a specific prompt."""
name: str
arguments: Optional[dict[str, str]]
```
## Protocol types
### Implementation Info
```python
class Implementation(TypedDict):
"""Information about an MCP implementation."""
name: str
version: str
```
### Capabilities
```python
class ResourceCapabilities(TypedDict):
"""Capabilities related to resources."""
subscribe: Optional[bool]
listChanged: Optional[bool]
class PromptCapabilities(TypedDict):
"""Capabilities related to prompts."""
listChanged: Optional[bool]
class ToolCapabilities(TypedDict):
"""Capabilities related to tools."""
listChanged: Optional[bool]
class ServerCapabilities(TypedDict):
"""Complete set of server capabilities."""
experimental: Optional[dict]
logging: Optional[dict]
prompts: Optional[PromptCapabilities]
resources: Optional[ResourceCapabilities]
tools: Optional[ToolCapabilities]
```
## Transport types
### Stream types
```python
class ReadStream(Protocol):
"""Protocol for reading from a transport."""
async def read(self) -> bytes: ...
class WriteStream(Protocol):
"""Protocol for writing to a transport."""
async def write(self, data: bytes) -> None: ...
```
### Session types
```python
class ServerSession(Protocol):
"""Protocol for server-side session operations."""
async def send_resource_updated(self, uri: str) -> None: ...
async def send_progress_notification(
self, token: str, progress: int, total: Optional[int] = None
) -> None: ...
async def send_log_message(
self, level: LogLevel, data: Any, logger: Optional[str] = None
) -> None: ...
```
## Usage examples
### Type usage in handlers
```python
from mcp_python.server import Server
from mcp_python.types import Resource, Tool, PromptResponse, Message
server = Server("example")
@server.list_resources()
async def list_resources() -> List[Resource]:
return [
{
"uri": "example://test",
"name": "Test Resource",
"description": "A test resource",
"mimeType": "text/plain"
}
]
@server.list_tools()
async def list_tools() -> List[Tool]:
return [
{
"name": "test-tool",
"description": "A test tool",
"inputSchema": {
"type": "object",
"properties": {
"param": {
"type": "string",
"description": "A parameter"
}
}
}
}
]
@server.get_prompt()
async def get_prompt(name: str, arguments: dict) -> PromptResponse:
return {
"description": "A test prompt",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": f"Test prompt with args: {arguments}"
}
}
]
}
```
### Type checking
```python
from typing import TypeGuard
def is_text_content(content: MessageContent) -> TypeGuard[TextContent]:
"""Type guard for text content."""
return content["type"] == "text"
def process_message(message: Message) -> str:
content = message["content"]
if is_text_content(content):
return content["text"]
return f"Image message with type: {content['mimeType']}"
```
## Additional notes
- All types are compatible with standard Python type checkers (mypy, pyright)
- TypedDict is used extensively to ensure proper structure of JSON-like objects
- Literal types are used to restrict string values to specific options
- Optional fields use the Optional type hint to indicate nullable values
- Protocol classes define interface contracts for pluggable components
For runtime type checking, you can use the following pattern:
```python
from typing import cast
from typing_extensions import assert_type
def validate_resource(data: dict) -> Resource:
"""Validate and convert a dict to a Resource type."""
required_fields = {"uri", "name"}
if not all(field in data for field in required_fields):
raise ValueError("Missing required fields")
return cast(Resource, {
"uri": str(data["uri"]),
"name": str(data["name"]),
"description": str(data.get("description")) if "description" in data else None,
"mimeType": str(data.get("mimeType")) if "mimeType" in data else None
})
```