added specs

This commit is contained in:
Zack Lee 2024-11-18 11:36:07 -05:00
commit 21a38ebe74
No known key found for this signature in database
3 changed files with 3532 additions and 60 deletions

View file

@ -3,6 +3,338 @@ title: "Python Class Reference"
description: "Complete Python SDK class documentation"
---
# Python Class Reference
## Server Class
Complete Python SDK class documentation
The main class for implementing MCP servers in Python.
```python
from mcp_python.server import Server
```
### Constructor
```python
Server(name: str, version: str = "1.0.0")
```
Creates a new MCP server instance.
**Parameters:**
- `name` (str): Name of the server
- `version` (str, optional): Version of the server. Defaults to "1.0.0"
### Decorators
#### Resource Handling
##### @server.list_resources()
```python
@server.list_resources()
async def list_resources() -> List[Resource]:
"""Lists available resources."""
```
**Returns:** List of `Resource` objects containing:
- `uri` (str): Resource identifier
- `name` (str): Human-readable name
- `description` (str, optional): Resource description
- `mimeType` (str, optional): MIME type of the resource
##### @server.read_resource()
```python
@server.read_resource()
async def read_resource(uri: str) -> Union[str, bytes]:
"""Reads content of a specific resource."""
```
**Parameters:**
- `uri` (str): Resource URI to read
**Returns:** Content of the resource as either string or bytes
##### @server.subscribe_resource()
```python
@server.subscribe_resource()
async def subscribe_resource(uri: str) -> None:
"""Handles resource subscription requests."""
```
**Parameters:**
- `uri` (str): Resource URI to subscribe to
##### @server.unsubscribe_resource()
```python
@server.unsubscribe_resource()
async def unsubscribe_resource(uri: str) -> None:
"""Handles resource unsubscribe requests."""
```
**Parameters:**
- `uri` (str): Resource URI to unsubscribe from
#### Tool Support
##### @server.list_tools()
```python
@server.list_tools()
async def list_tools() -> List[Tool]:
"""Lists available tools."""
```
**Returns:** List of `Tool` objects containing:
- `name` (str): Tool identifier
- `description` (str): Human-readable description
- `parameters` (dict): JSON Schema defining tool parameters
##### @server.call_tool()
```python
@server.call_tool()
async def call_tool(name: str, **kwargs) -> Any:
"""Handles tool execution requests."""
```
**Parameters:**
- `name` (str): Tool identifier
- `**kwargs`: Tool-specific parameters
**Returns:** Tool execution result (any JSON-serializable value)
#### Prompt Management
##### @server.list_prompts()
```python
@server.list_prompts()
async def list_prompts() -> List[Prompt]:
"""Lists available prompts."""
```
**Returns:** List of `Prompt` objects containing:
- `name` (str): Prompt identifier
- `description` (str, optional): Human-readable description
- `parameters` (dict, optional): JSON Schema defining prompt parameters
##### @server.get_prompt()
```python
@server.get_prompt()
async def get_prompt(name: str, arguments: dict) -> PromptResponse:
"""Retrieves specific prompt templates."""
```
**Parameters:**
- `name` (str): Prompt identifier
- `arguments` (dict): Prompt parameters
**Returns:** `PromptResponse` object containing:
- `messages` (List[Message]): List of prompt messages
- `description` (str, optional): Description of the prompt response
### Session Methods
Methods available on the server session object:
#### send_resource_updated()
```python
async def send_resource_updated(uri: str) -> None:
"""Notifies clients that a resource has been updated."""
```
#### send_progress_notification()
```python
async def send_progress_notification(
token: str,
progress: int,
total: Optional[int] = None
) -> None:
"""Sends progress updates for long-running operations."""
```
#### send_log_message()
```python
async def send_log_message(
level: str,
data: Any,
logger: Optional[str] = None
) -> None:
"""Sends log messages to clients."""
```
## Data Classes
### Resource
```python
@dataclass
class Resource:
uri: str
name: str
description: Optional[str] = None
mimeType: Optional[str] = None
```
### Tool
```python
@dataclass
class Tool:
name: str
description: str
parameters: dict
```
### Prompt
```python
@dataclass
class Prompt:
name: str
description: Optional[str] = None
parameters: Optional[dict] = None
```
### Message
```python
@dataclass
class Message:
role: Literal["user", "assistant"]
content: Union[TextContent, ImageContent]
```
### PromptResponse
```python
@dataclass
class PromptResponse:
messages: List[Message]
description: Optional[str] = None
```
## Example Usage
Here's a complete example demonstrating the main features:
```python
from mcp_python.server import Server
import anyio
server = Server("example-server")
@server.list_resources()
async def list_resources():
return [
{
"uri": "example://resource1",
"name": "Example Resource 1",
"description": "An example resource"
}
]
@server.read_resource()
async def read_resource(uri):
if uri == "example://resource1":
return "Example resource content"
raise ValueError(f"Unknown resource: {uri}")
@server.list_tools()
async def list_tools():
return [
{
"name": "example-tool",
"description": "An example tool",
"parameters": {
"type": "object",
"properties": {
"param1": {"type": "string"}
}
}
}
]
@server.call_tool()
async def call_tool(name, **kwargs):
if name == "example-tool":
return f"Tool executed with params: {kwargs}"
raise ValueError(f"Unknown tool: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
anyio.run(main)
```
## Best Practices
1. **Error Handling**: Always implement proper error handling in your server methods:
```python
@server.read_resource()
async def read_resource(uri):
try:
return await fetch_resource(uri)
except ResourceNotFoundError as e:
raise ValueError(f"Resource not found: {uri}") from e
```
2. **Type Hints**: Use typing hints for better code clarity:
```python
@server.list_resources()
async def list_resources() -> List[Resource]:
resources: List[Resource] = []
return resources
```
3. **Progress Updates**: For long-running operations, send progress updates:
```python
@server.call_tool()
async def call_tool(name: str, session: ServerSession, **kwargs):
for i in range(100):
await session.send_progress_notification(
"operation-1",
progress=i,
total=100
)
```
4. **Resource Updates**: Notify clients when resources change:
```python
@server.call_tool()
async def call_tool(name: str, session: ServerSession, **kwargs):
# ... perform update ...
await session.send_resource_updated("example://resource1")
```
## Transport Options
### stdio Transport
```python
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
```
### SSE Transport
```python
from mcp_python.transport import SSETransport
app = FastAPI()
transport = SSETransport()
@app.get("/sse")
async def sse_endpoint():
return await transport.handle_sse()
@app.post("/message")
async def message_endpoint(request: Request):
return await transport.handle_message(request)
```
### WebSocket Transport
```python
from mcp_python.transport import WebSocketTransport
app = FastAPI()
transport = WebSocketTransport()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await transport.handle_websocket(websocket)
```

View file

@ -1,8 +0,0 @@
---
title: "Python Examples"
description: "Example Python implementations"
---
# Python Examples
Example Python implementations

View file

@ -3,6 +3,357 @@ title: "Python Type Hints"
description: "Python type system documentation"
---
# Python Type Hints
## Core Types
Python type system documentation
### 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
})
```