Claude-skill-registry-data mcp-pydantic-tool-definition
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry-data
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/mcp-pydantic-tool-definition" ~/.claude/skills/majiayu000-claude-skill-registry-data-mcp-pydantic-tool-definition && rm -rf "$T"
manifest:
data/mcp-pydantic-tool-definition/SKILL.mdsource content
MCP Pydantic Tool Definition Skill
Metadata (Tier 1)
Keywords: pydantic, strict mode, input schema, tool schema, validation
File Patterns: **/schemas.py, **/tools/*.py
Modes: backend_python
Instructions (Tier 2)
Schema-First Development Pattern
CRITICAL: Pydantic V2 models are the single source of truth for MCP tool schemas.
from pydantic import BaseModel, Field, ConfigDict from typing import Literal class ToolInput(BaseModel): """Input schema for tool - becomes inputSchema automatically.""" model_config = ConfigDict(strict=True) query: str = Field(..., description="Search query string") limit: int = Field(10, ge=1, le=100, description="Max results") filter: Literal["all", "code", "docs"] = "all" # JSON Schema generated automatically schema = ToolInput.model_json_schema() # { # "type": "object", # "properties": { # "query": {"type": "string", "description": "Search query string"}, # "limit": {"type": "integer", "minimum": 1, "maximum": 100, ...}, # "filter": {"type": "string", "enum": ["all", "code", "docs"]} # }, # "required": ["query"] # }
Strict Mode (MANDATORY)
ConfigDict(strict=True) prevents silent type coercion.
# ❌ WITHOUT STRICT MODE class Input(BaseModel): count: int # Silent coercion: "10" → 10 input = Input(count="10") # Works, but dangerous! # ✅ WITH STRICT MODE class Input(BaseModel): model_config = ConfigDict(strict=True) count: int # Validation error: no coercion input = Input(count="10") # ❌ ValidationError! input = Input(count=10) # ✅ OK
Field Validation
from pydantic import Field, field_validator, model_validator class SearchInput(BaseModel): model_config = ConfigDict(strict=True) query: str = Field(..., min_length=1, max_length=500) limit: int = Field(10, ge=1, le=100) offset: int = Field(0, ge=0) @field_validator("query") @classmethod def validate_query(cls, v: str) -> str: """Custom query validation.""" if len(v.split()) > 50: raise ValueError("Query too complex (max 50 terms)") return v.strip() @model_validator(mode="after") def validate_pagination(self) -> "SearchInput": """Cross-field validation.""" if self.offset + self.limit > 10000: raise ValueError("Pagination limit exceeded") return self
Complex Types
from typing import Annotated, Literal from pydantic import BaseModel, ConfigDict, Field class FileFilter(BaseModel): model_config = ConfigDict(strict=True) pattern: str = Field(..., description="Glob pattern") exclude_dirs: list[str] = Field(default_factory=list) max_size_mb: int | None = Field(None, ge=1, le=1000) class AdvancedSearchInput(BaseModel): model_config = ConfigDict(strict=True) # Union types target: str | FileFilter # Literal enums mode: Literal["exact", "fuzzy", "regex"] # Bounded integers confidence: Annotated[float, Field(ge=0.0, le=1.0)] # Optional with default case_sensitive: bool = True # Nested models filters: list[FileFilter] = Field(default_factory=list)
Output Schemas
class SearchResult(BaseModel): """Output schema for search tool.""" model_config = ConfigDict(strict=True) file_path: str line_number: int match_text: str confidence: float = Field(ge=0.0, le=1.0) class SearchOutput(BaseModel): """Top-level output schema.""" model_config = ConfigDict(strict=True) results: list[SearchResult] total_count: int execution_time_ms: int # Usage in tool handler async def execute_search(input: SearchInput) -> SearchOutput: results = await perform_search(input) return SearchOutput( results=results, total_count=len(results), execution_time_ms=42 )
Tool Registration Pattern
from tools.schemas import SearchInput, SearchOutput @server.list_tools() async def list_tools(): """Register tools with auto-generated schemas.""" return [ { "name": "search_code", "description": "Search codebase with advanced filters", "inputSchema": SearchInput.model_json_schema() } ] @server.call_tool() async def call_tool(name: str, arguments: dict): """Execute tool with Pydantic validation.""" if name == "search_code": # Automatic validation via Pydantic input_data = SearchInput(**arguments) # Type-safe execution output = await execute_search(input_data) # Serialize output to JSON return output.model_dump() raise ValueError(f"Unknown tool: {name}")
JSON Schema Customization
from pydantic import BaseModel, ConfigDict, Field class CustomSchemaInput(BaseModel): model_config = ConfigDict( strict=True, # Custom JSON Schema metadata json_schema_extra={ "examples": [ {"query": "async def", "limit": 10} ] } ) query: str = Field( ..., description="Search query", json_schema_extra={ "examples": ["async def", "class MyClass"] } )
Validation Error Handling
from pydantic import ValidationError @server.call_tool() async def call_tool(name: str, arguments: dict): try: input_data = SearchInput(**arguments) return await execute_search(input_data) except ValidationError as e: # Convert Pydantic errors to MCP errors error_details = [] for error in e.errors(): error_details.append({ "field": ".".join(str(loc) for loc in error["loc"]), "message": error["msg"], "type": error["type"] }) raise McpError( code=-32602, # Invalid params message=f"Validation failed: {error_details}" )
Anti-Patterns
❌ Manual JSON Schema Writing
# WRONG schema = { "type": "object", "properties": {"query": {"type": "string"}} }
❌ Missing Strict Mode
# WRONG - allows type coercion class Input(BaseModel): count: int # No ConfigDict(strict=True)
❌ Ignoring Validation Errors
# WRONG try: input_data = Input(**arguments) except ValidationError: pass # Silent failure!
❌ Using BaseModel Without ConfigDict
# WRONG class Input(BaseModel): value: str # Missing model_config
Resources (Tier 3)
Pydantic V2 Docs: https://docs.pydantic.dev/latest/ Strict Mode Guide: https://docs.pydantic.dev/latest/concepts/strict_mode/ Field Validators: https://docs.pydantic.dev/latest/concepts/validators/ JSON Schema: https://docs.pydantic.dev/latest/concepts/json_schema/