added specs
This commit is contained in:
parent
9681ec94e6
commit
21a38ebe74
3 changed files with 3532 additions and 60 deletions
|
|
@ -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)
|
||||
```
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Python Examples"
|
||||
description: "Example Python implementations"
|
||||
---
|
||||
|
||||
# Python Examples
|
||||
|
||||
Example Python implementations
|
||||
|
|
@ -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
|
||||
})
|
||||
```
|
||||
Loading…
Reference in a new issue