MCP STDIO Webhook Server

MCP STDIO Webhook Server

A lightweight MCP server that accepts event envelopes, maps them to configurable tools, and supports STDIO transport with Docker deployment.

Category
Visit Server

README

MCP STDIO Webhook Server

A lightweight Python MCP (Model Context Protocol) server that accepts event envelopes and maps them to MCP tools. This server uses the STDIO transport and can be deployed with Docker Compose in a one-click style using a stdio-proxy (TCP bridge).

Overview

This project provides a robust MCP server that:

  • Communicates over STDIO internally with MCP clients
  • Exposes an easy-to-use TCP endpoint via a proxy/bridge for Docker deployments
  • Supports optional bearer-token authentication
  • Maps received event envelopes to registered MCP tools using configurable mappings
  • Supports both synchronous and asynchronous processing modes

Features

Core Features (MVP)

  • ✅ STDIO-based MCP server using FastMCP and the MCP Python SDK
  • ✅ Envelope router with configurable event-to-tool mappings
  • ✅ Optional bearer-token authentication (empty tokens = auth disabled)
  • ✅ TCP bridge (stdio-proxy) for Docker deployment
  • ✅ JSON structured logging
  • ✅ Example tools: ack_event, process_payload, list_recent_events

Additional Features (Implemented)

  • ✅ In-memory recent event log (via list_recent_events tool)
  • ✅ In-process worker pool for async jobs (configurable via ASYNC_PROCESSING)
  • ✅ Comprehensive testing (unit + integration)
  • ✅ CI/CD pipeline with GitHub Actions

Optional/Future Features

  • ✅ Redis-backed queue for high-throughput scenarios (use with --profile async)
  • 🔜 Example stdio client script (see Task 150)
  • 🔜 Prometheus metrics integration

Quick Start

Prerequisites

  • Docker and Docker Compose
  • (Optional) Python 3.11+ for local development

Docker Compose Deployment

  1. Clone the repository:
git clone https://github.com/encoded-evolution/mcp_webhook_python_zed.git
cd mcp_webhook_python_zed
  1. Copy the example environment file:
cp .env.example .env
  1. Configure your environment (optional):
# Edit .env to customize PORT, WEBHOOK_BEARER_TOKENS, etc.
  1. Create a mapping configuration:
cp config/mapping.yml.example config/mapping.yml
  1. Start the server:
docker-compose up --build

The server will be available at tcp://localhost:9000 (default port).

Testing the Connection

Quick TCP Test (netcat) Send a test envelope using netcat (for basic connectivity testing):

printf '%s\n' '{"type":"event","event_type":"file.save","payload":{"path":"/repo/file.py"},"meta":{"auth":"token1"}}' | nc localhost 9000

Using the Example Client For proper MCP stdio framing, use the example client:

python examples/stdio_client.py --event file.save --path /repo/file.py --auth token1

Note: The netcat test is for basic TCP connectivity only. Full MCP stdio framing is required for production usage. See examples/stdio_client.py for a complete client implementation.

MCP Client Configuration

This server can be used with any MCP-compatible client (Claude Desktop, VS Code MCP extension, etc.) by configuring the client to connect via Docker.

Prerequisites

  1. Pull the Docker image:
docker pull encoded-evolution/mcp-webhook-stdio:0.1.0
  1. Create a local configuration directory:
mkdir -p ~/.config/mcp-webhook
cp config/mapping.yml.example ~/.config/mcp-webhook/mapping.yml

Claude Desktop Configuration

Add the following to your Claude Desktop configuration file (claude_desktop_config.json):

Minimal configuration (no auth, default settings):

{
  "mcpServers": {
    "mcp-webhook": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-p", "9000:9000",
        "encoded-evolution/mcp-webhook-stdio:latest"
      ]
    }
  }
}

Full configuration with all settings:

{
  "mcpServers": {
    "mcp-webhook": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-e", "PORT=9000",
        "-e", "MCP_NAME=My-Webhook-Server",
        "-e", "WEBHOOK_BEARER_TOKENS=your-secret-token-1,another-token-2",
        "-e", "ASYNC_PROCESSING=false",
        "-e", "LOG_LEVEL=INFO",
        "-e", "REDIS_URL=",
        "-e", "MAPPING_FILE=/app/config/mapping.yml",
        "-v", "${HOME}/.config/mcp-webhook:/app/config:ro",
        "-p", "9000:9000",
        "encoded-evolution/mcp-webhook-stdio:latest"
      ]
    }
  }
}

VS Code MCP Extension Configuration

Claude Desktop Configuration

Add to your Claude Desktop config file (claude_desktop_config.json on macOS/Linux or claude_desktop_config.json in %APPDATA%\Claude\ on Windows):

Option 1: Using docker compose (recommended for multiple clients)

{
  "mcpServers": {
    "mcp-webhook": {
      "transport": {
        "type": "tcp",
        "host": "localhost",
        "port": 9000
      }
    }
  }
}

VS Code MCP Extension Configuration

Add to your VS Code settings (settings.json):

Option 1: Using docker compose (recommended for multiple clients)

{
  "mcp.servers": {
    "mcp-webhook": {
      "transport": {
        "type": "tcp",
        "host": "localhost",
        "port": 9000
      }
    }
  }
}

Option 2: Using individual container (one client per container)

{
  "mcp.servers": {
    "mcp-webhook": {
      "transport": {
        "type": "stdio",
        "command": "docker",
        "args": [
          "run", "--rm", "-i",
          "-e", "PORT=9000",
          "-e", "MCP_NAME=My-Webhook-Server",
          "-e", "WEBHOOK_BEARER_TOKENS=your-secret-token-1,another-token-2",
          "-e", "ASYNC_PROCESSING=false",
          "-e", "LOG_LEVEL=INFO",
          "-e", "REDIS_URL=",
          "-e", "MAPPING_FILE=/app/config/mapping.yml",
          "-v", "${env:HOME}/.config/mcp-webhook:/app/config:ro",
          "-p", "9000:9000",
          "encoded-evolution/mcp-webhook-stdio:latest"
        ]
      }
    }
  }
}

Zed Configuration

Configure Zed by adding to your settings.json:

Option 1: Using docker compose (recommended - server already running)

First, start the server:

cd mcp_webhook_python_zed
docker compose up

Then configure Zed (open settings.json):

{
  "context_servers": {
    "mcp-webhook": {
      "url": "tcp://localhost:9000"
    }
  }
}

Option 2: Using individual container (server starts with Zed)

Configure Zed (open settings.json):

{
  "context_servers": {
    "mcp-webhook": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-p", "9000:9000",
        "encoded-evolution/mcp-webhook-stdio:latest"
      ],
      "env": {}
    }
  }
}

Important: Do not use Option 2 if you already have docker compose up running, as it will cause a port conflict on 9000.

Note: When using "url" for remote connections, do not include a "command" field. The "command" field is only for starting local processes via STDIO transport.

TCP Transport (For Other Clients)

If your MCP client supports direct TCP connections, you can connect directly to the TCP proxy:

{
  "mcpServers": {
    "mcp-webhook-tcp": {
      "transport": {
        "type": "tcp",
        "host": "localhost",
        "port": 9000
      }
    }
  }
}

Environment Variables for Client Configuration

Variable Purpose Default Example
PORT Port for stdio-proxy listener 9000 9000
MCP_NAME Human-readable server name MCP-STDIO-Server My-Webhook-Server
WEBHOOK_BEARER_TOKENS Comma-separated auth tokens (empty = no auth) `` (disabled) token1,token2,token3
ASYNC_PROCESSING Enable async worker pool false true
LOG_LEVEL Logging verbosity INFO DEBUG, WARNING, ERROR
REDIS_URL Redis connection URL for async queue (optional) `` (disabled) redis://localhost:6379/0
MAPPING_FILE Path to event mapping config /app/config/mapping.yml /app/config/custom-mapping.yml

Testing the Connection

After configuring your MCP client:

If using docker compose:

  1. Verify the container is running:
docker ps | grep mcp-webhook
  1. Check logs for startup:
docker logs mcp-webhook-server
  1. Test TCP connection (optional):
nc -zv localhost 9000
  1. Look for successful client connection in logs:
docker logs -f mcp-webhook-server

If using individual container:

  1. Start your MCP client (Zed, Claude Desktop, etc.)
  2. Client will automatically start the Docker container
  3. Check logs from container:
docker ps | grep mcp-webhook-stdio
docker logs <container-id>
  1. Restart your MCP client if you make configuration changes

Common Issues

Port Already in Use

If using docker compose and seeing port conflicts, ensure you're not running multiple MCP clients configured for STDIO transport. Use TCP transport instead.

Connection Refused

Ensure the container is running before trying to connect with TCP transport. Check with docker ps.

Authentication Failures

Container not starting: Check Docker is running and the image is pulled correctly.

Port already in use: Change the port in your client configuration:

"-e", "PORT=9001",
"-p", "9001:9001",

Authentication errors: Ensure the token in your envelope matches one of the configured WEBHOOK_BEARER_TOKENS.

Configuration file not found: Verify the volume mount path matches where your mapping file is located on the host.

Configuration

Environment Variables

Variable Default Description
PORT 9000 Port for stdio-proxy TCP listener
MCP_NAME MCP-STDIO-Server Human-friendly server name
WEBHOOK_BEARER_TOKENS (empty) Comma-separated bearer tokens (empty = auth disabled)
ASYNC_PROCESSING false Enable async processing mode
MAPPING_FILE /app/config/mapping.yml Path to event mapping configuration
LOG_LEVEL INFO Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
REDIS_URL (empty) Redis connection URL (e.g., redis://redis:6379/0); empty uses in-memory queue

Using Redis-Backed Async Queue

For higher throughput scenarios, you can enable a Redis-backed queue instead of the in-memory queue:

  1. Start the services with the async profile:
docker-compose --profile async up --build
  1. Set the REDIS_URL environment variable in your .env file:
REDIS_URL=redis://redis:6379/0
ASYNC_PROCESSING=true
  1. The server will automatically use Redis for task queuing when:
    • REDIS_URL is configured and non-empty
    • The aioredis package is installed (included in [redis] optional dependency)

Benefits of Redis Queue:

  • Persistent queue that survives container restarts
  • Multiple worker processes can share the same queue
  • Better for high-throughput scenarios
  • Tasks are stored in a Redis list and processed by worker coroutines

Note: When Redis is unavailable, the server will fall back to the in-memory queue automatically and log a warning.

Event Mapping Configuration

Create a mapping.yml file to define how events map to tools:

mappings:
  - event: "file.save"
    tool: "process_payload"
    args:
      path: payload.path
      user_id: payload.user.id
  
  - event: "file.open"
    tool: "ack_event"
    args:
      file: payload.path

Envelope Format

Events are sent as JSON envelopes:

{
  "type": "event",
  "event_type": "file.save",
  "payload": {
    "path": "/repo/file.py",
    "user": {
      "id": "alice"
    }
  },
  "meta": {
    "auth": "token1",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2026-01-06T12:00:00Z"
  }
}

Envelope Fields

Field Type Required Description
type string Yes Must be "event"
event_type string Yes Event identifier for mapping
payload object Yes Event data (any structure)
meta.auth string Conditional Bearer token (required if auth enabled)
meta.id string No Unique event identifier
meta.timestamp string No ISO 8601 timestamp

Architecture

┌─────────────┐     TCP      ┌──────────────┐     STDIO      ┌─────────────┐
│   Client    │ ◄──────────► │ stdio-proxy  │ ◄────────────► │ MCP Server  │
│             │  Port: 9000   │ (TCP Bridge) │  Framing       │  (FastMCP)  │
└─────────────┘               └──────────────┘                └─────────────┘
                                     │
                                     ▼
                              ┌──────────────┐
                              │ Envelope     │
                              │ Router       │
                              └──────────────┘
                                     │
                                     ▼
                              ┌──────────────┐
                              │ Async Worker │
                              │ (in-memory   │
                              │  or Redis)   │
                              └──────────────┘
                                     │
                                     ▼
                              ┌──────────────┐
                              │ MCP Tools    │
                              │ (ack_event,  │
                              │  process_    │
                              │  payload,    │
                              │  list_recent)│
                              └──────────────┘

Components

  1. Client: Connects via TCP to the stdio-proxy
  2. stdio-proxy: TCP bridge that forwards data to/from server STDIO
  3. MCP Server: FastMCP-based server handling MCP protocol
  4. Envelope Router: Maps events to tools and validates auth
  5. MCP Tools: Executable functions that process events

Available MCP Tools

ack_event

Acknowledges an event and returns a confirmation.

# Parameters: event_type: str, payload: dict
# Returns: {"status": "acknowledged", "event_type": "..."}

process_payload

Processes a payload with path and user information.

# Parameters: path: str, user_id: str
# Returns: {"processed": true, "path": "...", "user_id": "..."}

list_recent_events

Returns the list of recently processed events.

# Parameters: None
# Returns: {"events": [...]}

Development

Local Development Setup

  1. Create a virtual environment:
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

2. Install dependencies:

# For basic development
pip install -e ".[dev]"

# For Redis queue support (optional)
pip install -e ".[dev,redis]"
  1. Run tests:
pytest
  1. Run linting:
ruff check src/
black src/
isort src/

Project Structure

mcp_webhook_python_zed/
├── src/
│   └── mcp_webhook/
│       ├── __init__.py
│       ├── config.py          # Configuration management
│       ├── mapping.py         # Event-to-tool mapping parser
│       ├── envelope.py        # Envelope Pydantic models
│       ├── tools.py           # MCP tool implementations
│       ├── router.py          # Envelope routing logic
│       ├── worker.py          # Async worker (optional)
│       ├── server.py          # FastMCP server bootstrap
│       └── proxy.py           # stdio-proxy (TCP bridge)
├── config/
│   ├── mapping.yml.example    # Example mapping configuration
│   └── .env.example           # Example environment variables
├── tests/
│   ├── unit/                  # Unit tests
│   └── integration/           # Integration tests
├── examples/
│   └── stdio_client.py       # Example client implementation
├── docker/
│   └── entrypoint.sh         # Docker entrypoint script
├── docker-compose.yml        # Docker Compose configuration
├── Dockerfile                # Docker image definition
├── pyproject.toml           # Python project configuration
├── README.md                # This file
├── Planning.md              # Project planning document
└── Task.md                  # Task tracking

Testing

Unit Tests

# Run all unit tests
pytest tests/unit/

# Run specific test file
pytest tests/unit/test_config.py

# Run with coverage
pytest --cov=src --cov-report=html

Integration Tests

# Run all integration tests
pytest tests/integration/

# Run specific integration test
pytest tests/integration/test_stdio_proxy.py

End-to-End Test with Docker

# Build and start the service
docker-compose up --build

# Run the example client (from another terminal)
python examples/stdio_client.py

# Verify logs for processed events
docker-compose logs -f mcp-stdio

Security

Authentication

  • Bearer tokens are stored in environment variables
  • When WEBHOOK_BEARER_TOKENS is empty, authentication is disabled
  • In production, use proper secret management (e.g., Docker secrets, Vault)

Recommendations

  • Run behind a firewall or in a secure network
  • Use an external proxy (e.g., Traefik, Nginx) for TLS termination
  • Rotate bearer tokens regularly
  • Enable structured logging for audit trails

Troubleshooting

Port Already in Use

# Find process using port 9000
netstat -ano | findstr :9000  # Windows
lsof -i :9000                 # macOS/Linux

# Change port in .env
PORT=9001

Connection Refused

  • Verify the container is running: docker-compose ps
  • Check logs: docker-compose logs mcp-stdio
  • Ensure firewall allows connections to the configured port

Authentication Failures

  • Verify WEBHOOK_BEARER_TOKENS matches the token in envelope meta
  • Check that meta.auth field is present in the envelope
  • Review logs for detailed error messages

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes and write tests
  4. Run tests: pytest
  5. Run linting: ruff check src/ && black src/ && isort src/
  6. Commit your changes: git commit -m "Add my feature"
  7. Push to the branch: git push origin feature/my-feature
  8. Open a Pull Request

License

MIT License - see LICENSE file for details

Roadmap

See Planning.md for detailed project planning and Task.md for task tracking.

Upcoming Features

  • [ ] Enhanced admin tooling
  • [ ] Per-client token management
  • [ ] Multi-tenant support
  • [ ] Kubernetes manifests / Helm chart
  • [ ] OAuth or HMAC signing flows
  • [ ] Prometheus metrics integration
  • [ ] Example stdio client script

Support

For issues, questions, or contributions, please open an issue on the project repository.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured