Skip to main content
Glama

MCP Server Template

by rwxproject
README.mdโ€ข26 kB
# MCP Server Template A comprehensive, modular template for building Model Context Protocol (MCP) servers using FastMCP with professional architecture, auto-discovery, and flexible deployment options. ## ๐Ÿš€ Project Overview This template provides a robust foundation for creating MCP servers with: - **FastMCP Framework**: Built on FastMCP 2.11.3+ for rapid MCP server development - **Modular Architecture**: Clean separation of tools, resources, prompts, and configuration - **Auto-Discovery Registry**: Automatic component registration using registry pattern - **Multiple Entry Points**: Backward compatibility with flexible deployment options - **Transport Flexibility**: Supports streamable HTTP and Server-Sent Events (SSE) transports - **Comprehensive Testing**: Unit and integration test suite structure - **Development Template**: Docker support, structured logging, and configuration management - **Type Safety**: Pydantic models and type hints throughout - **Extensible Design**: Easy to add new tools, resources, and prompts **Version**: 0.1.0 ## ๐Ÿƒ Quick Start Guide ### Prerequisites - Python 3.13+ - [uv](https://github.com/astral-sh/uv) (recommended package manager) ### 1. Clone and Setup ```bash git clone <your-repo> cd mcp-server-template uv venv source .venv/bin/activate uv install ``` ### 2. Run the Server Choose your preferred method: **New Modular Way (Recommended):** ```bash source .venv/bin/activate && uv run python -m mcp_server ``` **Backward Compatible:** ```bash source .venv/bin/activate && uv run python main.py ``` **With Custom Transport:** ```bash # Streamable HTTP transport export MCP_TRANSPORT=streamable-http export MCP_PORT=8080 source .venv/bin/activate && uv run python -m mcp_server # Server-Sent Events transport export MCP_TRANSPORT=sse export MCP_PORT=8081 source .venv/bin/activate && uv run python -m mcp_server ``` ### 3. Test Connection ```bash # Run diagnostic test source .venv/bin/activate && uv run python diagnosis_test.py # Run verification test source .venv/bin/activate && uv run python verification_test.py ``` ## ๐Ÿ“ฆ Installation Instructions ### Development Installation ```bash # Clone the repository git clone <your-repo-url> cd mcp-server-template # Create and activate virtual environment uv venv source .venv/bin/activate # Install dependencies uv install # Install development dependencies uv install --group dev ``` ### Production Installation ```bash # Install from source uv install git+<your-repo-url> # Or from local directory uv install . ``` ## ๐Ÿ”ง Available Tools ### Arithmetic Tools - **add**: Add two integers together - **subtract**: Subtract two integers ### Weather Tools - **get_current_weather**: Get current weather information for a location **Note**: Weather tool uses OpenWeatherMap API. Set `WEATHER_API_KEY` environment variable for real data, or it will use mock data for development. ## ๐Ÿ”ง Usage Examples ### 1. Default Mode ```bash # Standard streamable HTTP mode source .venv/bin/activate && uv run python -m mcp_server ``` ### 2. Streamable HTTP Server Mode ```bash # Run as streamable HTTP server export MCP_TRANSPORT=streamable-http export MCP_HOST=0.0.0.0 export MCP_PORT=8080 source .venv/bin/activate && uv run python -m mcp_server ``` ### 3. Server-Sent Events (SSE) Mode ```bash # Run as SSE server export MCP_TRANSPORT=sse export MCP_HOST=0.0.0.0 export MCP_PORT=8081 source .venv/bin/activate && uv run python -m mcp_server ``` ### 4. Development Mode with Debug Logging ```bash # Enable debug logging export MCP_LOG_LEVEL=DEBUG export MCP_ENVIRONMENT=development source .venv/bin/activate && uv run python -m mcp_server ``` ### 5. Docker Deployment ```bash # Build image docker build -t mcp-server . # Run container (default mode) docker run -it mcp-server # Run container (Streamable HTTP mode) docker run -e MCP_TRANSPORT=streamable-http -e MCP_PORT=8080 -p 8080:8080 mcp-server # With custom configuration docker run -e MCP_LOG_LEVEL=DEBUG -e MCP_ENVIRONMENT=production -it mcp-server ``` ### 6. Integration with Claude Desktop Add to your Claude Desktop MCP configuration: **Default Mode (Recommended):** ```json { "mcpServers": { "mcp-server-template": { "command": "uv", "args": ["run", "python", "-m", "mcp_server"], "cwd": "/path/to/your/mcp-server-template" } } } ``` **Streamable HTTP Mode:** ```json { "mcpServers": { "mcp-server-template": { "url": "http://localhost:8080/mcp", "transport": "streamable-http" } } } ``` ## ๐Ÿ—๏ธ Architecture Overview ### Directory Structure ``` mcp-server-template/ โ”œโ”€โ”€ src/mcp_server/ # Main package (v0.1.0) โ”‚ โ”œโ”€โ”€ __init__.py # Package initialization & lazy imports โ”‚ โ”œโ”€โ”€ __main__.py # Module entry point โ”‚ โ”œโ”€โ”€ server.py # Core FastMCP server implementation โ”‚ โ”œโ”€โ”€ config/ # Configuration management โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”‚ โ”œโ”€โ”€ settings.py # Pydantic settings with environment support โ”‚ โ”‚ โ””โ”€โ”€ logging.py # Structured logging configuration โ”‚ โ”œโ”€โ”€ tools/ # MCP tools โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”‚ โ”œโ”€โ”€ base.py # Base tool class โ”‚ โ”‚ โ”œโ”€โ”€ arithmetic.py # Arithmetic tools (add, subtract) โ”‚ โ”‚ โ”œโ”€โ”€ weather.py # Weather tools (get_current_weather) โ”‚ โ”‚ โ””โ”€โ”€ registry.py # Tool auto-discovery registry โ”‚ โ”œโ”€โ”€ resources/ # MCP resources โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”‚ โ”œโ”€โ”€ base.py # Base resource class โ”‚ โ”‚ โ”œโ”€โ”€ system.py # System information resources โ”‚ โ”‚ โ””โ”€โ”€ registry.py # Resource auto-discovery registry โ”‚ โ””โ”€โ”€ prompts/ # MCP prompts โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”œโ”€โ”€ base.py # Base prompt class โ”‚ โ”œโ”€โ”€ text_processing.py # Text processing prompts โ”‚ โ””โ”€โ”€ registry.py # Prompt auto-discovery registry โ”œโ”€โ”€ tests/ # Test suite โ”‚ โ”œโ”€โ”€ conftest.py # Shared test fixtures โ”‚ โ”œโ”€โ”€ unit/ # Unit tests โ”‚ โ”‚ โ””โ”€โ”€ test_tools.py โ”‚ โ””โ”€โ”€ integration/ # Integration tests โ”‚ โ””โ”€โ”€ test_client_interactions.py โ”œโ”€โ”€ main.py # Backward compatibility entry โ”œโ”€โ”€ Dockerfile # Container deployment โ”œโ”€โ”€ diagnosis_test.py # Server diagnostic tool โ”œโ”€โ”€ verification_test.py # Server verification tool โ””โ”€โ”€ pyproject.toml # Project configuration ``` ### Key Components #### 1. Server Factory Pattern Clean server creation with comprehensive configuration: ```python # Server creation with auto-discovery from mcp_server import create_server server = create_server() # Automatically discovers and registers all components ``` #### 2. Registry Pattern with Auto-Discovery All components are automatically discovered and registered: ```python # Components are automatically found and registered from mcp_server.tools.registry import register_all_tools from mcp_server.resources.registry import register_all_resources from mcp_server.prompts.registry import register_all_prompts # Registration happens automatically in create_server() register_all_tools(mcp) register_all_resources(mcp) register_all_prompts(mcp) ``` #### 3. Transport-Agnostic Design Supports multiple transport methods: ```python # Flexible transport configuration await mcp.run_async( transport=settings.transport, # streamable-http or sse host=settings.host, # configurable host port=settings.port # configurable port ) ``` #### 4. Comprehensive Configuration Environment-based configuration with validation: ```python from mcp_server.config.settings import get_settings settings = get_settings() # Loads from environment with defaults # Supports: transport, host, port, log_level, environment, etc. ``` ## ๐Ÿ”จ Extension Guide ### Adding New Tools 1. **Create a new tool file** in `src/mcp_server/tools/`: ```python # src/mcp_server/tools/my_tool.py from typing import Any from fastmcp import FastMCP from .base import BaseTool class MyTool(BaseTool): """Example tool that processes text input.""" def __init__(self): super().__init__(name="my_tool") def register_with_mcp(self, mcp: FastMCP) -> None: """Register tools with FastMCP instance.""" @mcp.tool() async def process_text(text: str) -> str: """Process text input and return formatted result. Args: text: Input text to process Returns: Processed text in uppercase """ self._log_tool_call("process_text", text=text) return f"Processed: {text.upper()}" self.logger.info("Registered my_tool: process_text") # The tool is automatically discovered by the registry! ``` 2. **The tool is automatically registered** - no manual registration needed! 3. **Advanced tool with validation**: ```python from typing import Dict, Any from fastmcp import FastMCP from .base import BaseTool class ValidatedTool(BaseTool): """Example tool with validation using FastMCP decorators""" def __init__(self): super().__init__(name="validated") def register_with_mcp(self, mcp: FastMCP) -> None: @mcp.tool() async def process_data(value: int, name: str) -> Dict[str, Any]: """Process data with validation. Args: value: Integer value to process name: Name to include in result Returns: Processed data dictionary """ if not (0 <= value <= 100): raise ValueError("Value must be between 0-100") if not name or not name.strip(): raise ValueError("Name cannot be empty") return {"value": value, "name": name.strip(), "processed": True} self.logger.info("Registered validated tool: process_data") ``` ### Adding New Resources 1. **Create a resource file** in `src/mcp_server/resources/`: ```python # src/mcp_server/resources/my_resource.py import json from typing import Any from .base import BaseResource class MyResource(BaseResource): """Example resource that provides data.""" uri_template = "my://data/{category}" name = "My Data Resource" description = "Provides categorized data" mime_type = "application/json" async def read(self, category: str = "default") -> str: """Read resource data for the given category.""" data = { "category": category, "items": [f"item-{i}" for i in range(1, 6)], "timestamp": "2024-01-01T00:00:00Z" } return json.dumps(data, indent=2) # Automatically discovered by the registry! ``` ### Adding New Prompts 1. **Create a prompt file** in `src/mcp_server/prompts/`: ```python # src/mcp_server/prompts/my_prompt.py from typing import Any, List from fastmcp import FastMCP from .base import BasePrompt class MyPrompt(BasePrompt): """Example prompt for content generation.""" def __init__(self): super().__init__(name="my_prompt") def register_with_mcp(self, mcp: FastMCP) -> None: """Register prompts with FastMCP instance.""" @mcp.prompt() async def generate_content(topic: str, format: str = "markdown") -> str: """Generate structured content about a topic. Args: topic: The topic to generate content about format: Output format (markdown, text, etc.) Returns: Generated content in the specified format """ self._log_prompt_call("generate_content", topic=topic, format=format) if format == "markdown": return f"""# {topic} ## Overview This is an overview of {topic}. ## Key Points - Point 1 about {topic} - Point 2 about {topic} - Point 3 about {topic} ## Conclusion Summary of {topic}. """ else: return f"Content about {topic} in {format} format" self.logger.info("Registered my_prompt: generate_content") # Automatically discovered by the registry! ``` ## ๐Ÿงช Testing ### Running Tests ```bash # All tests source .venv/bin/activate && uv run pytest # Unit tests only source .venv/bin/activate && uv run pytest tests/unit/ -v # Integration tests only source .venv/bin/activate && uv run pytest tests/integration/ -v # Specific test file source .venv/bin/activate && uv run pytest tests/unit/test_tools.py -v # With coverage source .venv/bin/activate && uv run pytest --cov=src/mcp_server --cov-report=html # Parallel execution source .venv/bin/activate && uv run pytest -n auto ``` ### Test Structure ``` tests/ โ”œโ”€โ”€ conftest.py # Shared test fixtures โ”œโ”€โ”€ unit/ # Unit tests โ”‚ โ””โ”€โ”€ test_tools.py # Tool testing โ””โ”€โ”€ integration/ # Integration tests โ””โ”€โ”€ test_client_interactions.py # End-to-end tests ``` ### Writing Tests Example unit test for tools: ```python import pytest from mcp_server.tools.arithmetic import ArithmeticTools @pytest.mark.asyncio async def test_arithmetic_tools(): tools = ArithmeticTools() # Test direct methods assert tools.add_numbers(5, 3) == 8 assert tools.subtract_numbers(10, 4) == 6 @pytest.mark.asyncio async def test_weather_tools(): from mcp_server.tools.weather import WeatherTools tools = WeatherTools() # Weather tool would require proper MCP setup for full testing # This is a simplified example assert tools._use_mock_data() == True # Default is mock data ``` Example integration test: ```python import pytest from mcp_server import create_server @pytest.mark.asyncio async def test_server_creation(): server = create_server() assert server is not None # Test component registration # This would require proper async setup in real tests assert server is not None # Verify tools are available (actual implementation would vary) # The server would have add, subtract, get_current_weather tools ``` ## โš™๏ธ Configuration ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `MCP_TRANSPORT` | `streamable-http` | Transport method (streamable-http, sse) | | `MCP_HOST` | `0.0.0.0` | Server host for network transports | | `MCP_PORT` | `8080` | Server port for network transports | | `MCP_LOG_LEVEL` | `INFO` | Logging level (DEBUG, INFO, WARNING, ERROR) | | `MCP_LOG_FORMAT` | `[%(levelname)s]: %(message)s` | Log format string | | `MCP_ENVIRONMENT` | `development` | Environment (development, production, testing) | | `MCP_SERVER_NAME` | `MCP Server Template` | Server identification name | | `MCP_VERSION` | `0.1.0` | Server version | | `PORT` | - | Cloud Run compatible port override | ### Configuration Examples **Development Configuration:** ```bash export MCP_ENVIRONMENT=development export MCP_LOG_LEVEL=DEBUG export MCP_TRANSPORT=streamable-http ``` **Streamable HTTP Server Configuration:** ```bash export MCP_TRANSPORT=streamable-http export MCP_HOST=0.0.0.0 export MCP_PORT=8080 export MCP_ENVIRONMENT=production export MCP_LOG_LEVEL=INFO ``` **Server-Sent Events Configuration:** ```bash export MCP_TRANSPORT=sse export MCP_HOST=0.0.0.0 export MCP_PORT=8081 export MCP_ENVIRONMENT=production ``` ### Advanced Configuration The settings system supports complex configuration scenarios: ```python # src/mcp_server/config/settings.py from pydantic import BaseModel, Field from typing import Literal class Settings(BaseModel): # Server Configuration server_name: str = "MCP Server Template" host: str = "0.0.0.0" port: int = 8080 transport: Literal["streamable-http", "sse"] = "streamable-http" # Logging Configuration log_level: str = "INFO" log_format: str = "[%(levelname)s]: %(message)s" # Environment Configuration environment: Literal["development", "production", "testing"] = "development" version: str = "0.1.0" model_config = { "env_prefix": "MCP_", "case_sensitive": False, "env_file": ".env", "env_file_encoding": "utf-8" } ``` ## ๐Ÿš€ Deployment ### Docker Deployment 1. **Build the image**: ```bash docker build -t my-mcp-server . ``` 2. **Run with different transports**: ```bash # Default mode docker run -it my-mcp-server # Streamable HTTP mode docker run -e MCP_TRANSPORT=streamable-http -e MCP_HOST=0.0.0.0 -e MCP_PORT=8080 -p 8080:8080 my-mcp-server # Server-Sent Events mode docker run -e MCP_TRANSPORT=sse -e MCP_HOST=0.0.0.0 -e MCP_PORT=8081 -p 8081:8081 my-mcp-server # With custom environment docker run -e MCP_LOG_LEVEL=DEBUG -e MCP_ENVIRONMENT=production -it my-mcp-server ``` 3. **Docker Compose**: ```yaml version: '3.8' services: mcp-server-default: build: . environment: - MCP_TRANSPORT=streamable-http - MCP_LOG_LEVEL=INFO stdin_open: true tty: true mcp-server-http: build: . environment: - MCP_TRANSPORT=streamable-http - MCP_HOST=0.0.0.0 - MCP_PORT=8080 - MCP_LOG_LEVEL=INFO ports: - "8080:8080" mcp-server-sse: build: . environment: - MCP_TRANSPORT=sse - MCP_HOST=0.0.0.0 - MCP_PORT=8081 - MCP_LOG_LEVEL=INFO ports: - "8081:8081" ``` ### Production Deployment 1. **System Service** (systemd example): ```ini # /etc/systemd/system/mcp-server.service [Unit] Description=MCP Server After=network.target [Service] Type=simple User=mcp WorkingDirectory=/opt/mcp-server Environment=MCP_TRANSPORT=streamable-http Environment=MCP_HOST=0.0.0.0 Environment=MCP_PORT=8080 Environment=MCP_LOG_LEVEL=INFO Environment=MCP_ENVIRONMENT=production ExecStart=/opt/mcp-server/.venv/bin/python -m mcp_server Restart=always RestartSec=10 [Install] WantedBy=multi-user.target ``` 2. **Process Manager** (PM2 example): ```json { "name": "mcp-server", "script": "python", "args": ["-m", "mcp_server"], "cwd": "/opt/mcp-server", "interpreter": "/opt/mcp-server/.venv/bin/python", "env": { "MCP_TRANSPORT": "streamable-http", "MCP_HOST": "0.0.0.0", "MCP_PORT": "8080", "MCP_LOG_LEVEL": "INFO", "MCP_ENVIRONMENT": "production" } } ``` 3. **Kubernetes Deployment**: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: mcp-server spec: replicas: 3 selector: matchLabels: app: mcp-server template: metadata: labels: app: mcp-server spec: containers: - name: mcp-server image: my-mcp-server:latest env: - name: MCP_TRANSPORT value: "streamable-http" - name: MCP_HOST value: "0.0.0.0" - name: MCP_PORT value: "8080" - name: MCP_ENVIRONMENT value: "production" ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: mcp-server-service spec: selector: app: mcp-server ports: - port: 80 targetPort: 8080 type: LoadBalancer ``` ## ๐Ÿ‘ฅ Development ### Development Setup ```bash # Clone and setup git clone <repo-url> cd mcp-server-template uv venv source .venv/bin/activate uv install --group dev # Set development environment export MCP_ENVIRONMENT=development export MCP_LOG_LEVEL=DEBUG ``` ### Code Quality ```bash # Format and lint code source .venv/bin/activate && uv run ruff check src tests --fix source .venv/bin/activate && uv run ruff format src tests # Type checking (mypy not included in current dependencies) # Add mypy to dev dependencies if type checking is needed # Run all quality checks source .venv/bin/activate && uv run pytest && uv run ruff check src tests ``` ### Contributing Guidelines 1. **Fork and clone** the repository 2. **Create a feature branch**: `git checkout -b feature/my-feature` 3. **Set development environment**: `export MCP_ENVIRONMENT=development` 4. **Write tests** for new functionality 5. **Ensure all tests pass**: `source .venv/bin/activate && uv run pytest` 6. **Run linting**: `source .venv/bin/activate && uv run ruff check src tests --fix` 7. **Test different transports**: Test streamable-http and sse modes 8. **Commit changes**: Follow conventional commits 9. **Submit a pull request** ### Development Workflows **Testing Different Transports:** ```bash # Test default streamable HTTP mode export MCP_TRANSPORT=streamable-http && source .venv/bin/activate && uv run python -m mcp_server # Test SSE mode export MCP_TRANSPORT=sse && export MCP_PORT=8081 && source .venv/bin/activate && uv run python -m mcp_server ``` **Component Development:** ```bash # Verify tool registration source .venv/bin/activate && uv run python -c " from mcp_server.tools.registry import get_all_tools print([tool.__class__.__name__ for tool in get_all_tools()]) " # Test new components source .venv/bin/activate && uv run python diagnosis_test.py ``` ## ๐Ÿ› Troubleshooting ### Common Issues 1. **Server not starting**: ```bash # Check Python version python --version # Should be 3.13+ # Check dependencies source .venv/bin/activate && uv pip list # Check with debug logging export MCP_LOG_LEVEL=DEBUG source .venv/bin/activate && uv run python -m mcp_server ``` 2. **Transport-specific issues**: ```bash # Streamable HTTP transport issues export MCP_TRANSPORT=streamable-http export MCP_HOST=localhost export MCP_PORT=8080 curl http://localhost:8080/health # Test endpoint # SSE transport issues export MCP_TRANSPORT=sse export MCP_PORT=8081 # Test with SSE client ``` 3. **Components not registered**: ```bash # Verify component discovery source .venv/bin/activate && uv run python -c " from mcp_server import create_server server = create_server() print('Server created successfully with all components') " ``` 4. **Docker issues**: ```bash # Check container logs docker logs <container-id> # Interactive debugging docker run -it --entrypoint /bin/bash my-mcp-server # Test different transports docker run -e MCP_TRANSPORT=streamable-http -e MCP_PORT=8080 -p 8080:8080 my-mcp-server ``` ### Debug Mode Enable comprehensive debugging: ```bash export MCP_LOG_LEVEL=DEBUG export MCP_ENVIRONMENT=development source .venv/bin/activate && uv run python -m mcp_server ``` ### Health Checks Use the provided diagnostic tools: ```bash # Basic functionality test source .venv/bin/activate && uv run python diagnosis_test.py # Full verification test source .venv/bin/activate && uv run python verification_test.py # Test specific transport export MCP_TRANSPORT=streamable-http && source .venv/bin/activate && uv run python verification_test.py ``` ## ๐Ÿ”ง FastMCP Features This template leverages FastMCP's powerful capabilities: ### Multi-Transport Support ```python # Automatic transport detection and configuration await mcp.run_async( transport="streamable-http", # Streamable HTTP server mode transport="sse" # Server-Sent Events mode ) ``` ### Automatic Type Validation ```python from fastmcp import tool @tool async def validated_function(count: int, name: str) -> dict: """FastMCP handles automatic type conversion and validation.""" return {"count": count, "name": name} ``` ### Built-in Error Handling ```python # FastMCP provides comprehensive error handling try: result = await tool.execute(params) except ValidationError as e: logger.error(f"Validation error: {e}") except Exception as e: logger.error(f"Execution error: {e}") ``` ### Lazy Loading for Performance ```python # The template uses lazy imports for optimal startup def create_server(): from .server import create_server as _create_server return _create_server() ``` ## ๐Ÿ“„ Dependencies ### Core Dependencies - **fastmcp** (>=2.11.3): FastMCP framework for rapid MCP server development - **httpx** (>=0.28.1): HTTP client for external API integration - **pydantic** (>=2.0.0): Data validation and settings management ### Development Dependencies - **pytest** (>=8.4.1): Testing framework with async support - **pytest-asyncio** (>=0.23.0): Async testing support for pytest - **ruff** (>=0.12.10): Fast Python linter and formatter - **ipykernel** (>=6.30.1): Jupyter kernel for interactive development ## ๐Ÿ†• What's New in v0.1.0 - **Multi-Transport Support**: Streamable HTTP and Server-Sent Events transport options - **Environment-Based Configuration**: Comprehensive settings management with MCP_ prefixes - **Registry Pattern**: Automatic component discovery and registration - **Structured Logging**: Configurable logging formats with proper levels - **Development Template**: Docker support with Python 3.13, structured for extension - **FastMCP Integration**: Built on the latest FastMCP framework - **Lazy Loading**: Optimized startup performance with lazy imports - **Flexible Deployment**: Multiple deployment options and configurations ## ๐Ÿ“„ License [Your License Here] ## ๐Ÿค Support - **Issues**: [GitHub Issues](your-repo/issues) - **Discussions**: [GitHub Discussions](your-repo/discussions) - **Documentation**: This README and inline code documentation - **FastMCP Docs**: [FastMCP Documentation](https://github.com/jlowin/fastmcp) - **MCP Specification**: [Model Context Protocol](https://modelcontextprotocol.io/) --- **Happy building with MCP and FastMCP! ๐Ÿš€**

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/rwxproject/mcp-server-template'

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