Skip to main content
Glama

EXIF Extractor MCP Server

by yjqian19
AGENTS.md17.1 kB
# AGENTS.md Welcome to the **Smithery Python MCP Server Scaffold**! This is the template project that gets cloned when you run `uvx smithery init`. It provides everything you need to build, test, and deploy a Model Context Protocol (MCP) server with Smithery. ## What's Included - **FastMCP Server** with Smithery session-scoped configuration support - **Example Tool** (`hello` tool with pirate mode configuration) - **Example Resource** (`history://hello-world` with Hello World origin story) - **Example Prompt** (`greet` prompt for generating greeting messages) - **Development Workflow** (`uv run dev` for local testing, `uv run playground` for interactive testing) - **Deployment Ready** configuration for the Smithery platform - **Session Management** via `@smithery.server()` decorator with optional config schemas ## Quick Start Commands ```bash # Run development server (streamable HTTP on port 8081) uv run dev # Run production server (optimized for deployment) uv run start # Test with interactive playground uv run playground ``` ## Development Workflow Based on the [Model Context Protocol architecture](https://modelcontextprotocol.io/docs/learn/architecture.md), MCP servers provide three core primitives: ### 1. Tools (for actions) Add executable functions that AI applications can invoke to perform actions: ```python @server.tool() def hello(name: str, ctx: Context) -> str: """Say hello to someone.""" session_config = ctx.session_config if session_config.pirate_mode: return f"Ahoy, {name}!" else: return f"Hello, {name}!" ``` ### 2. Resources (for static data) Add data sources that provide contextual information: ```python @server.resource("history://hello-world") def hello_world() -> str: """The origin story of the famous 'Hello, World' program.""" return ( '"Hello, World" first appeared in a 1972 Bell Labs memo by ' "Brian Kernighan and later became the iconic first program " "for beginners in countless languages." ) ``` ### 3. Prompts (for interaction templates) Add reusable templates that help structure interactions: ```python @server.prompt() def greet(name: str) -> list: """Generate a greeting prompt.""" return [ { "role": "user", "content": f"Say hello to {name}", }, ] ``` ### Project Structure ``` your-server/ ├── pyproject.toml # Project config with [tool.smithery] section ├── smithery.yaml # Runtime specification (runtime: python) ├── src/ │ └── hello_server/ # Your server module (rename this!) │ ├── __init__.py │ └── server.py # Main server implementation └── README.md ``` ### Customizing Your Project **Important:** You'll want to rename `hello_server` to match your actual project: 1. **Rename the module directory:** ```bash mv src/hello_server src/your_project_name ``` 2. **Update pyproject.toml:** ```toml [project] name = "your-project-name" [tool.smithery] server = "your_project_name.server:create_server" # Points to your server function ``` 3. **Update imports in your code:** ```bash # Test your renamed server works uv run python -c "from your_project_name.server import create_server; print(create_server())" ``` **Note:** The function name `create_server` can be anything you want - just make sure the `[tool.smithery]` server path matches your actual function name (e.g., `"module:my_function_name"`). ## Session Configuration Session configuration allows clients to connect to your MCP server with personalized settings. Think of it like user preferences - each connection gets its own configuration that doesn't affect other sessions, perfect for passing API keys, customizing behavior, and personalizing responses. When you define a configuration schema, Smithery automatically: - **Generates a configuration UI** with form elements (text inputs, dropdowns, checkboxes) - **Passes configurations to your server** as URL parameters - **Shows helpful descriptions** as form labels and tooltips - **Applies default values** and enforces required fields This is accessed through the FastMCP `Context` object in your tools and resources. ### Real-World Example: Weather Server Let's say you're building a weather server. You might want users to customize their preferred temperature unit, provide an API key, or set their default location: ```python class WeatherConfig(BaseModel): weather_api_key: str = Field(..., description="Your OpenWeatherMap API key") # Note: 'api_key' is reserved temperature_unit: str = Field("celsius", description="Temperature unit (celsius/fahrenheit)") default_location: str = Field("New York", description="Default city for weather queries") @smithery.server(config_schema=WeatherConfig) def create_weather_server(): # Your weather tools use ctx.session_config.weather_api_key, ctx.session_config.temperature_unit, etc. ``` **Usage scenarios:** - **User A**: API key `abc123`, prefers Fahrenheit, lives in San Francisco - **User B**: API key `xyz789`, prefers Celsius, lives in Singapore Each user gets personalized weather data without affecting others. ### Understanding Context The `Context` object is automatically injected into tool and resource functions via type hints. In Smithery, it includes session-specific configuration: ```python from mcp.server.fastmcp import Context @server.tool() def my_tool(name: str, ctx: Context) -> str: """Tool that uses session config.""" # Access session-specific config config = ctx.session_config # Use config values (API keys, preferences, etc.) if config.debug: return f"DEBUG: Hello {name}" return f"Hello {name}" ``` ### How Session Config Works 1. **Define config schema** (optional): ```python class ConfigSchema(BaseModel): # Required field - users must provide this user_api_key: str = Field(..., description="Your API key") # Note: avoid 'api_key' (reserved) # Optional fields with defaults - users can customize or use defaults debug: bool = Field(False, description="Debug mode") max_results: int = Field(10, description="Maximum results to return") # Optional field without default - can be None custom_endpoint: str | None = Field(None, description="Custom API endpoint") @smithery.server(config_schema=ConfigSchema) def create_server(): # Your server setup ``` **Important:** Avoid using reserved parameter names (`api_key`, `profile`, `config`) in your schema fields. These are handled internally by Smithery. **Field Types and Validation Behavior:** - **Required Fields**: Use `Field(...)` - Server returns 422 error if missing ```python api_key: str = Field(..., description="Your API key") # Missing this field → 422 error with config schema ``` - **Optional with Default**: Use `Field(default_value)` - Uses default if not provided ```python debug: bool = Field(False, description="Debug mode") max_results: int = Field(10, description="Maximum results") # Missing these fields → Uses defaults (debug=False, max_results=10) ``` - **Optional without Default**: Use `Field(None)` with nullable type - Can be None ```python custom_endpoint: str | None = Field(None, description="Custom API endpoint") # Missing this field → Sets to None, no validation error ``` **Validation Logic:** - **No config provided** → Uses defaults for optional fields, 422 only if required fields exist - **Partial config** → Uses provided values + defaults for missing optional fields - **Missing required fields** → 422 error with validation details and config schema - **Invalid values** → 422 error (wrong types, constraint violations, etc.) 2. **Pass config via URL parameters**: ``` http://localhost:8000/mcp?user_api_key=xyz123&debug=true ``` **Reserved Parameters:** The following parameter names are reserved and cannot be used in your configuration schema: - `api_key` - Reserved for API key handling - `profile` - Reserved for profile management - `config` - Reserved for internal configuration handling Use alternative names for your configuration fields (e.g., `user_api_key`, `service_profile`, `app_config`). 3. **Each session gets isolated config**: - Session A: `debug=true, user_api_key=xyz123` - Session B: `debug=false, user_api_key=abc456` - Sessions don't interfere with each other ### Why This Matters - **Multi-user support**: Different users can have different API keys/settings - **Environment isolation**: Dev/staging/prod configs per session - **Security**: API keys stay session-scoped, not server-global ### Secure Config Distribution (Production) In production, Smithery handles sensitive configuration securely: 1. **Users save config in Smithery** (API keys, tokens, etc.) 2. **OAuth authentication** is built-in - no manual key management 3. **Smithery Gateway** securely forwards config to your server 4. **Your server receives config** via `ctx.session_config` as usual **The flow:** ``` User → Smithery Platform → Gateway (OAuth) → Your Server (saves config) (secure forwarding) (receives config) ``` **Benefits:** - Users never expose sensitive keys directly to your server - OAuth handles authentication automatically - Config is encrypted in transit through the gateway - You focus on your server logic, not security infrastructure ### Testing Your Server There are two main ways to test your MCP server: #### Method 1: Smithery Playground ```bash uv run playground # Actually runs: uv run smithery playground ``` This opens the Smithery Playground in your browser with your local server tunneled through ngrok. Perfect for interactive testing and seeing your tools in action. **Note**: If using `--reload` mode, you'll need to refresh the playground to start a new session after code changes. #### Method 2: Direct MCP Protocol Testing ```bash # Start development server (with optional reload) uv run dev # Actually runs: uv run smithery dev uv run dev --reload # Auto-reload on code changes uv run dev --log-level debug # More verbose logging # Start production server (optimized startup) uv run start # Actually runs: uv run smithery start uv run start --log-level warning # Minimal production logging ``` **Complete MCP Testing Workflow:** 1. Start server: `uv run dev` (runs on port 8081 by default) 2. **Test scenarios based on your config schema:** **Scenario A: Required fields (like `pirate_mode: bool = Field(...)`)** ```bash # Must include required config - will get 422 error without it curl -X POST "http://127.0.0.1:8081/mcp?pirate_mode=true" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"clientInfo":{"name":"test-client","version":"1.0.0"}}}' ``` **Scenario B: Optional fields with defaults (like `debug: bool = Field(False)`)** ```bash # Can omit config - will use defaults curl -X POST "http://127.0.0.1:8081/mcp" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"clientInfo":{"name":"test-client","version":"1.0.0"}}}' ``` 3. Get session ID from server logs: "Created new transport with session ID: [uuid]" 4. Send notifications/initialized with session header: ```bash curl -X POST "http://127.0.0.1:8081/mcp" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "mcp-session-id: [session-id]" \ -d '{"jsonrpc":"2.0","method":"notifications/initialized"}' ``` 5. Test your tools: ```bash curl -X POST "http://127.0.0.1:8081/mcp" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "mcp-session-id: [session-id]" \ -d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"hello","arguments":{"name":"World"}}}' ``` **Expected Responses:** - With `pirate_mode=true`: `"Ahoy, World!"` - With `pirate_mode=false` or default: `"Hello, World!"` - Missing required fields: `422 error` with config schema ### Deployment Configuration **pyproject.toml:** ```toml [tool.smithery] server = "my_server.server:create_server" # Points to your @smithery.server() function [project.scripts] dev = "smithery.cli.dev:main" # Development server playground = "smithery.cli.playground:main" # Interactive testing ``` ## Deployment & CI/CD ### Local Deployment ```bash # Python server deployment prep uv build # Creates wheel in dist/ git add . && git commit -m "Deploy ready" git push origin main ``` ### Production Deployment 1. Push code to GitHub repository 2. Deploy via [smithery.ai/new](https://smithery.ai/new) 3. Smithery handles containerization and hosting 4. **Automatic Registry Mirroring**: Your server gets published to both the Smithery platform and the official MCP registry for better discoverability ## Architecture Notes ### Key Dependencies - **mcp>=1.6.0**: Model Context Protocol SDK - **Python >=3.10**: Required Python version ### FastMCP Compatibility The scaffold works with both: - **MCP SDK FastMCP** (bundled with official mcp package) - **FastMCP 2.0** (fastmcp package) When using with existing FastMCP servers, ensure you have compatible versions: - `mcp>=1.6.0` OR `fastmcp>=2.0.0` ### Security Considerations - Session-scoped API keys and configuration - CORS headers for web client compatibility - Request logging and monitoring via gateway - Authentication handled by Smithery platform ## Pre-Deployment Checklist Before deploying, ensure your server works locally: ### 1. Basic Server Test ```bash # Development server with timing info and reload support uv run dev # Production server with optimized startup (recommended for deployment testing) uv run start ``` **What you'll see:** - **Development mode**: `Server started in 45.2ms` (shows startup timing) - **Production mode**: Minimal output, faster startup (no dev overhead) **Common issues:** - **"Module not found"**: Run `uv sync` first - **"Server function not callable"**: Check your `[tool.smithery]` server reference in `pyproject.toml` - **"Config schema errors"**: Verify your Pydantic model can be instantiated - **Port unavailable**: In production mode, server fails fast instead of switching ports ### 2. Validate Server Creation ```bash # Test that your server function works (replace with your actual module name) uv run python -c "from your_project_name.server import create_server; print(create_server())" ``` **Expected output:** Should print something like `<smithery.server.fastmcp_patch.SmitheryFastMCP object at 0x...>` without errors. If you see import errors or exceptions, check your server configuration. ### 3. Test with Playground ```bash # This should open playground in your browser uv run playground ``` **Expected behavior:** Browser opens with Smithery Playground connected to your local server. ## Troubleshooting ### Port Issues - Default port is **8081** (not 8000) - **Development**: `uv run dev --port 8000` (auto-switches if port busy) - **Production**: `uv run start --port 8000` (fails fast if port unavailable) - Kill existing process: `lsof -ti:8081 | xargs kill` ### Log Level Control - **Development**: `uv run dev --log-level debug` (default: info) - **Production**: `uv run start --log-level error` (default: warning) - Available levels: critical, error, warning, info, debug, trace ### Config Issues ```bash # Check your pyproject.toml configuration cat pyproject.toml | grep -A5 "tool.smithery" # Should show: # [tool.smithery] # server = "hello_server.server:create_server" ``` ### Import Issues - Ensure you're in the project root directory - Run `uv sync` to install dependencies - Check that your server module path matches the `[tool.smithery]` reference ## Resources - **Documentation**: [smithery.ai/docs](https://smithery.ai/docs) - **MCP Protocol**: [modelcontextprotocol.io](https://modelcontextprotocol.io) - **Python Quickstart**: [smithery.ai/docs/getting_started/quickstart_build_python.md](https://smithery.ai/docs/getting_started/quickstart_build_python.md) - **GitHub**: [github.com/smithery-ai/sdk](https://github.com/smithery-ai/sdk) - **Registry**: [smithery.ai](https://smithery.ai) for discovering and deploying MCP servers ## Community & Support - **Discord**: Join our community for help and discussions: [discord.gg/Afd38S5p9A](https://discord.gg/Afd38S5p9A) - **Bug Reports**: Found an issue? Report it on GitHub: [github.com/smithery-ai/sdk/issues](https://github.com/smithery-ai/sdk/issues) - **Feature Requests**: Suggest new features on our GitHub discussions: [github.com/smithery-ai/sdk/discussions](https://github.com/smithery-ai/sdk/discussions)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yjqian19/personal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server