Skip to main content

Generate MCP (Model Context Protocol) tools from YAML configuration files. Turn any REST API into callable MCP tools without writing code.

Project description

MCP YAML Server

PyPI version Python 3.10+ License: MIT

Generate MCP (Model Context Protocol) tools from YAML configuration files. Turn any REST API into callable MCP tools without writing code.

Perfect for teams who want to expose internal APIs to AI assistants like Claude Desktop, GitHub Copilot, or any MCP-compatible client.

✨ Features

  • 🎯 Zero-Code Integration - Define API endpoints in YAML, get working MCP tools
  • 🔐 Multiple Auth Methods - API key, Bearer token, Basic auth, custom headers
  • 📁 File Upload Support - Handle multipart/form-data with type/size validation
  • 🔄 All HTTP Methods - GET, POST, PUT, PATCH, DELETE
  • 🌐 Remote & Local - Works with both local and remote MCP servers
  • High Performance - Async HTTP with connection pooling and HTTP/2
  • 🛡️ Type Safe - Pydantic validation for configuration and parameters
  • 🐳 Docker Ready - Deploy as containerized HTTP/SSE server
  • 🔧 Environment Variables - Secure credential management with ${VAR} syntax

📦 Installation

pip install mcp-yaml-server

Requirements: Python 3.10+

🚀 Quick Start

1. Create a YAML Configuration

Create my-api.yaml:

server:
  name: "my_api_tools"
  version: "1.0.0"
  description: "My API integration"

global:
  base_url: "https://jsonplaceholder.typicode.com"
  timeout: 30

endpoints:
  - name: "get_user"
    description: "Retrieve user information by their unique ID"
    method: "GET"
    path: "/users/{id}"
    parameters:
      - name: "id"
        type: "integer"
        description: "The unique identifier of the user"
        required: true
        location: "path"

  - name: "create_post"
    description: "Create a new blog post for a user"
    method: "POST"
    path: "/posts"
    parameters:
      - name: "title"
        type: "string"
        description: "The title of the blog post"
        required: true
        location: "body"
      - name: "body"
        type: "string"
        description: "The content body of the post"
        required: true
        location: "body"
      - name: "userId"
        type: "integer"
        description: "The ID of the user creating the post"
        required: true
        location: "body"

2. Start the MCP Server

# Standard MCP server (stdio transport for Claude Desktop)
mcp-yaml-server my-api.yaml

# HTTP server for remote access
mcp-yaml-server --transport http --host 0.0.0.0 --port 8000 my-api.yaml

# SSE/Streaming HTTP server (for GitHub Copilot, etc.)
mcp-yaml-server --transport streamable-http --host 0.0.0.0 --port 8000 my-api.yaml

# Validate configuration without starting
mcp-yaml-server --dry-run my-api.yaml

# Debug mode with verbose logging
mcp-yaml-server --debug my-api.yaml

3. Connect from Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "my_api_tools": {
      "command": "mcp-yaml-server",
      "args": ["/absolute/path/to/my-api.yaml"]
    }
  }
}

Restart Claude Desktop - your tools are now available!

4. Connect from GitHub Copilot

Add to your MCP settings:

{
  "servers": {
    "my_api_tools": {
      "type": "sse",
      "url": "http://localhost:8000/mcp"
    }
  }
}

📖 Configuration Reference

Server Configuration

server:
  name: "my_server"           # Required: Server identifier (alphanumeric + underscore)
  version: "1.0.0"            # Required: Semantic version
  description: "Description"   # Optional: Human-readable description

Global Settings

global:
  base_url: "https://api.example.com"  # Required: Base URL for all endpoints
  timeout: 30                           # Optional: Default timeout in seconds (default: 30)
  headers:                              # Optional: Headers added to all requests
    X-Custom-Header: "value"
  auth:                                 # Optional: Authentication configuration
    type: "bearer"                      # Options: bearer, api_key, basic, custom
    bearer:
      token: "${API_TOKEN}"

Authentication Types

Bearer Token

auth:
  type: "bearer"
  bearer:
    token: "${AUTH_TOKEN}"

API Key

auth:
  type: "api_key"
  api_key:
    header_name: "X-API-Key"
    token: "${API_KEY}"

Basic Auth

auth:
  type: "basic"
  basic:
    username: "${API_USER}"
    password: "${API_PASS}"

Custom Headers

auth:
  type: "custom"
  custom:
    headers:
      Authorization: "Custom ${TOKEN}"
      X-Auth-Provider: "my-provider"

Endpoint Configuration

endpoints:
  - name: "endpoint_name"              # Required: Tool name (alphanumeric + underscore)
    description: "What this does"       # Required: Min 20 characters
    method: "GET"                       # Required: GET, POST, PUT, PATCH, DELETE
    path: "/resource/{id}"              # Required: URL path with optional {placeholders}
    parameters: [...]                   # Optional: List of parameters
    request_config: {...}               # Optional: Request customization
    response_config: {...}              # Optional: Response handling

Parameter Configuration

parameters:
  - name: "param_name"                 # Required: Parameter name
    type: "string"                     # Required: string, integer, number, boolean, array, object
    description: "What this param is"  # Required: Min 20 characters
    required: true                     # Required: true or false
    location: "path"                   # Required: path, query, header, body, file
    default: "value"                   # Optional: Default value if not provided

Parameter Locations:

  • path - URL path parameter (e.g., /users/{id})
  • query - URL query parameter (e.g., ?limit=10)
  • header - HTTP header
  • body - JSON request body field
  • file - File upload (multipart/form-data)

Request Configuration

request_config:
  body_type: "json"              # Options: json, form, multipart (default: json)
  timeout: 60                    # Override global timeout for this endpoint
  headers:                       # Additional headers for this endpoint
    X-Custom: "value"
  files:                         # File upload configuration
    max_size_mb: 50
    allowed_types:
      - "application/pdf"
      - "image/jpeg"
      - "image/png"
    field_name: "file"           # Form field name for file
    multiple: false              # Allow multiple files

Response Configuration

response_config:
  success_codes: [200, 201]              # Expected success status codes
  extract_path: "$.data.items"           # JSONPath to extract from response
  error_handling:
    extract_message_path: "$.error.msg"  # JSONPath to extract error message
    default_message: "Request failed"    # Fallback error message
    include_status_code: true            # Include HTTP status in error
    include_response_body: false         # Include response body in error

📁 File Uploads

The server supports file uploads from both local and remote MCP clients:

endpoints:
  - name: "upload_document"
    description: "Upload and process a document file"
    method: "POST"
    path: "/documents/upload"
    parameters:
      - name: "file"
        type: "string"
        description: "Path to the document file to upload"
        required: true
        location: "file"
      - name: "title"
        type: "string"
        description: "Title for the uploaded document"
        required: true
        location: "body"
    request_config:
      body_type: "multipart"
      files:
        max_size_mb: 50
        allowed_types:
          - "application/pdf"
          - "image/jpeg"
          - "image/png"

Usage:

  • Local paths: /Users/me/document.pdf - File is read automatically
  • Base64 content: Raw base64-encoded string for programmatic uploads
  • Data URI: data:application/pdf;base64,JVBERi0xLjQ...

🔐 Environment Variables

Use ${VAR_NAME} syntax for secure credential management:

global:
  base_url: "${API_BASE_URL}"
  auth:
    type: "bearer"
    bearer:
      token: "${API_TOKEN}"

With defaults:

base_url: "${API_BASE_URL:https://api.example.com}"
timeout: "${TIMEOUT:30}"

Set variables before running:

export API_BASE_URL="https://api.example.com"
export API_TOKEN="your-secret-token"
mcp-yaml-server my-api.yaml

🐳 Docker Deployment

Using the Dockerfile

FROM python:3.11-slim

WORKDIR /app

RUN pip install mcp-yaml-server

COPY my-api.yaml /app/config.yaml

ENV MCP_CONFIG=/app/config.yaml
ENV HOST=0.0.0.0
ENV PORT=8000

CMD ["mcp-yaml-server", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8000", "/app/config.yaml"]

Build and Run

docker build -t my-mcp-server .
docker run -p 8000:8000 -e API_TOKEN=secret my-mcp-server

Docker Compose

version: '3.8'
services:
  mcp-server:
    build: .
    ports:
      - "8000:8000"
    environment:
      - API_TOKEN=${API_TOKEN}
      - API_BASE_URL=https://api.example.com
    volumes:
      - ./configs:/app/configs
    command: >
      mcp-yaml-server
      --transport streamable-http
      --host 0.0.0.0
      --port 8000
      /app/configs/my-api.yaml

🛠️ CLI Reference

# Start MCP server (stdio transport - default)
mcp-yaml-server config.yaml

# Start HTTP server
mcp-yaml-server --transport http --port 8000 config.yaml

# Start SSE/streaming server
mcp-yaml-server --transport streamable-http --port 8000 config.yaml

# Validate configuration
mcp-yaml-server --dry-run config.yaml
mcp-yaml-validate config.yaml

# Debug mode
mcp-yaml-server --debug config.yaml

# Multiple configurations
mcp-yaml-server api1.yaml api2.yaml

# Full options
mcp-yaml-server \
  --transport streamable-http \
  --host 0.0.0.0 \
  --port 8000 \
  --debug \
  config.yaml

🔧 Troubleshooting

Common Issues

"Configuration file not found"

# Use absolute paths
mcp-yaml-server /absolute/path/to/config.yaml

"bearer field required when type is 'bearer'"

# Correct nested structure:
auth:
  type: "bearer"
  bearer:
    token: "${TOKEN}"

"String should have at least 20 characters"

# Descriptions must be at least 20 characters
description: "This is a detailed description of the endpoint"

"Environment variable 'X' is not set"

# Set required variables
export API_TOKEN="your-token"
mcp-yaml-server config.yaml

File upload "File not found" on remote server

  • Ensure you're running the latest version with client-side file reading
  • For remote servers, files are read locally and uploaded automatically

Debug Mode

# Enable verbose logging
mcp-yaml-server --debug config.yaml

# Validate without starting
mcp-yaml-server --dry-run config.yaml

📚 Examples

See the examples/ directory for complete configuration examples:

  • sample-config.yaml - Basic GET endpoints
  • sample-github-api.yaml - GitHub API with authentication
  • sample-file-upload.yaml - File upload endpoints
  • dpr-mock-server-config.yaml - Complex multi-endpoint configuration

🏗️ Architecture

  • Language: Python 3.10+
  • MCP Framework: FastMCP 2.x
  • HTTP Client: httpx (async, HTTP/2)
  • Validation: Pydantic 2.x
  • YAML Parser: PyYAML 6.0+

⚡ Performance

  • YAML parse/load: <1s for 50+ endpoints
  • Tool metadata generation: <100ms per tool
  • HTTP request overhead: <50ms beyond API latency
  • Supports 100+ concurrent tool invocations
  • Connection pooling and HTTP/2 for efficiency

🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

# Clone and install dev dependencies
git clone https://github.com/labtessi/mcp-yaml-server.git
cd mcp-yaml-server
pip install -e ".[dev]"

# Run tests
pytest

# Run linter
ruff check src/ tests/

# Format code
black src/ tests/

📄 License

MIT License - see LICENSE file for details.

🔗 Related Projects

📞 Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_yaml_server-1.1.0.tar.gz (37.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_yaml_server-1.1.0-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file mcp_yaml_server-1.1.0.tar.gz.

File metadata

  • Download URL: mcp_yaml_server-1.1.0.tar.gz
  • Upload date:
  • Size: 37.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for mcp_yaml_server-1.1.0.tar.gz
Algorithm Hash digest
SHA256 67d9b552c217755beb169310126fe037b186ed2208c469c849a1f9750462154e
MD5 8e88122a671405e6905f365f4200d0ad
BLAKE2b-256 d9cea3368478ea8c395aca0a2e176db3c06bfb7c10a0fd0040d8609792315b63

See more details on using hashes here.

File details

Details for the file mcp_yaml_server-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_yaml_server-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 384fc2d6d84b8553532afacf347121cc2b7d848746ef4a6bd45ea761691ed511
MD5 8b7d2cb0439b4ec3c0280e0f2dd0e5d5
BLAKE2b-256 275ae290dc9a4e135f8597f391a728a3c4edebb031a221316c854995af10bf6b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page