Skip to main content

A simple wrapper library for FastMCP + Starlette

Project description

viyv_mcp

viyv_mcp is a production-ready Python wrapper around FastMCP and Starlette that simplifies creating MCP (Model Context Protocol) servers with minimal boilerplate.

PyPI version Python 3.10+ License: MIT Version

๐Ÿš€ Quick Start

# Install the package
pip install viyv_mcp

# Create a new MCP server project
create-viyv-mcp new my_mcp_server

# Navigate to the project and install dependencies
cd my_mcp_server
uv sync

# Run the server
uv run python main.py

Your MCP server is now running at http://localhost:8000 ๐ŸŽ‰

โœจ Key Features

๐Ÿ› ๏ธ Simple Tool Creation

from viyv_mcp import tool

@tool(description="Add two numbers")
def add(a: int, b: int) -> int:
    return a + b

๐Ÿค– Agent Support with OpenAI Integration

from viyv_mcp import agent
from viyv_mcp.openai_bridge import build_function_tools

@agent(name="calculator", use_tools=["add", "subtract"])
async def calculator_agent(query: str) -> str:
    tools = build_function_tools(use_tools=["add", "subtract"])
    # Agent implementation using OpenAI SDK
    return f"Result: {result}"

๐ŸŒ‰ External MCP Server Bridge

// app/mcp_server_configs/filesystem.json
{
  "command": "npx",
  "args": ["@modelcontextprotocol/server-filesystem", "/workspace"],
  "env": {
    "API_KEY": "$API_KEY"  // Environment variable interpolation
  },
  "cwd": "/path/to/working/dir",  // Optional
  "tags": ["filesystem", "io"]     // Optional: for filtering
}

๐Ÿš€ Production-Ready Multi-Worker Support (New in v0.1.10)

# Enable stateless HTTP mode for multi-worker deployments
STATELESS_HTTP=true uv run python main.py

# Deploy with Gunicorn (recommended for production)
uv pip install gunicorn
STATELESS_HTTP=true uv run gunicorn main:app \
  -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000

๐Ÿ”— Built-in Integrations

  • Slack: Full event handling, file management, thread context
  • OpenAI Agents SDK: Seamless function calling bridge
  • ChatGPT: Compatible with required search/fetch tools
  • Custom FastAPI Endpoints: Mount additional APIs with @entry

๐Ÿ“ฆ Installation

# Basic installation
pip install viyv_mcp

# With all optional dependencies
pip install "viyv_mcp[slack,openai]"

๐Ÿ“ Project Structure

When you create a new project with create-viyv-mcp new my_project:

my_project/
โ”œโ”€โ”€ main.py                # Server entry point
โ”œโ”€โ”€ pyproject.toml         # Dependencies (managed by uv)
โ”œโ”€โ”€ Dockerfile             # Production-ready container
โ”œโ”€โ”€ .env                   # Environment variables
โ””โ”€โ”€ app/
    โ”œโ”€โ”€ config.py          # Configuration management
    โ”œโ”€โ”€ tools/             # MCP tools (@tool decorator)
    โ”œโ”€โ”€ resources/         # MCP resources (@resource decorator)
    โ”œโ”€โ”€ prompts/           # MCP prompts (@prompt decorator)
    โ”œโ”€โ”€ agents/            # AI agents (@agent decorator)
    โ”œโ”€โ”€ entries/           # Custom HTTP endpoints (@entry decorator)
    โ””โ”€โ”€ mcp_server_configs/ # External MCP server configurations

๐Ÿ’ป Advanced Usage Examples

Tools with Runtime Context (Slack Integration)

from viyv_mcp import tool
from viyv_mcp.run_context import RunContext
from agents import RunContextWrapper

def register(mcp):
    @tool(description="Get user info from context")
    def get_user_info(
        wrapper: RunContextWrapper[RunContext],
        user_id: str
    ) -> dict:
        """Get user information from Slack context"""
        context = wrapper.context
        if context and hasattr(context, 'slack_event'):
            # Access Slack event data
            return {"user": context.slack_event.get("user"), "channel": context.channel}
        return {"user": user_id, "source": "direct"}

Creating Resources with URI Templates

from viyv_mcp import resource

def register(mcp):
    @resource("database://{table}/{id}")
    def get_record(table: str, id: str) -> dict:
        """Fetch a database record by table and ID"""
        # Your database logic here
        return {"table": table, "id": id, "data": "..."}

Prompts with Parameters

from viyv_mcp import prompt
from typing import Annotated
from pydantic import Field

def register(mcp):
    @prompt("code_review")
    def code_review_prompt(
        language: Annotated[str, Field(description="Programming language")],
        code: Annotated[str, Field(description="Code to review")]
    ) -> str:
        return f"""
        Please review this {language} code:
        ```{language}
        {code}
        ```
        Focus on: performance, security, and best practices.
        """

Slack Bot with File Handling

from viyv_mcp import entry
from viyv_mcp.app.adapters.slack_adapter import SlackAdapter
from viyv_mcp.run_context import RunContext

@entry("/slack")
def create_slack_app():
    adapter = SlackAdapter(
        bot_token=os.getenv("SLACK_BOT_TOKEN"),
        signing_secret=os.getenv("SLACK_SIGNING_SECRET"),
        context_cls=RunContext,
        handle_files=True,  # Enable file upload/download
        build_thread_history=True,  # Include thread context
    )
    return adapter.as_fastapi_app()

ChatGPT-Compatible Tools

from viyv_mcp import tool

def register(mcp):
    # Required for ChatGPT integration
    @tool(description="Search for information")
    def search(query: str) -> list:
        """Search tool required by ChatGPT"""
        results = perform_search(query)
        return [{"resource_link": f"resource://{r.id}", "title": r.title} for r in results]

    @tool(description="Fetch resource by ID")
    def fetch(id: str) -> dict:
        """Fetch tool required by ChatGPT (note: 'id' not 'uri')"""
        return get_resource_by_id(id)

๐Ÿ”ง Configuration

Environment Variables

# Server Configuration
HOST=0.0.0.0                    # Server host (default: 127.0.0.1)
PORT=8000                        # Server port (default: 8000)
STATELESS_HTTP=true              # Enable stateless mode for multi-worker

# Directory Configuration
BRIDGE_CONFIG_DIR=app/mcp_server_configs  # External MCP configs
STATIC_DIR=static/images                  # Static file serving

# Integration Keys (optional)
SLACK_BOT_TOKEN=xoxb-...        # Slack bot token
SLACK_SIGNING_SECRET=...        # Slack signing secret
OPENAI_API_KEY=sk-...           # OpenAI API key

Configuration Class

# app/config.py
from viyv_mcp.app.config import Config

class MyConfig(Config):
    # Inherit base configuration

    @staticmethod
    def get_stateless_http():
        """Get stateless HTTP setting from environment"""
        env_val = os.getenv("STATELESS_HTTP", "").lower()
        if env_val in ("true", "1", "yes", "on"):
            return True
        elif env_val in ("false", "0", "no", "off"):
            return False
        return None  # Use FastMCP default

๐Ÿ—๏ธ Architecture & Advanced Features

ASGI-Level Routing (SSE Streaming Fix)

viyv_mcp implements custom ASGI routing to fix SSE streaming issues:

  • Direct /mcp path routing bypasses Starlette middleware
  • Ensures proper Server-Sent Events handling
  • Compatible with FastMCP's streaming protocol

Dynamic Tool Injection

  • Tools are refreshed on every request
  • Agents always have access to the latest tools
  • Supports runtime tool filtering with tags

RunContextWrapper Pattern

  • Signature manipulation for dual compatibility
  • Works with both FastMCP and OpenAI Agents SDK
  • Provides access to runtime context (Slack events, user info)

External MCP Server Management

  • Child process management with stdio communication
  • Automatic tool/resource/prompt registration
  • Environment variable interpolation in configs
  • Tag-based filtering for selective tool inclusion

Production Deployment Features

Stateless HTTP Mode

  • No session ID requirements
  • Perfect for load-balanced environments
  • Enable with STATELESS_HTTP=true

Multi-Worker Deployment

# test_app.py - Create a module for Gunicorn
from viyv_mcp import ViyvMCP
from app.config import Config

stateless_http = Config.get_stateless_http()
app = ViyvMCP("Production Server", stateless_http=stateless_http).get_app()
# Run with Gunicorn
gunicorn test_app:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000

Docker Deployment

FROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
CMD ["uv", "run", "gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]

๐Ÿ“Š Performance Optimization

Caching Strategies

  • Tools are cached per request
  • External MCP connections are persistent
  • Static file serving with efficient caching headers

Resource Management

  • Automatic cleanup of external MCP processes
  • Connection pooling for external services
  • Graceful shutdown handling

Monitoring & Debugging

# Enable debug logging
LOG_LEVEL=DEBUG uv run python main.py

# Health check endpoint
curl http://localhost:8000/health

๐Ÿ” Troubleshooting

Common Issues

SSE Streaming Not Working

  • Ensure no middleware interferes with /mcp path
  • Check ASGI routing configuration
  • Verify FastMCP version >= 2.12.3

Multi-Worker Startup Failures

  • Enable STATELESS_HTTP=true for multi-worker mode
  • Use Gunicorn instead of uvicorn's --workers flag
  • Check for asyncio event loop conflicts

External MCP Server Issues

# Check external server logs
tail -f logs/external_mcp.log

# Verify command exists
which npx

# Test configuration
cat app/mcp_server_configs/test.json | jq .

Protocol Compatibility

  • Use MCP protocol version 2024-11-05
  • Pydantic v2 compatibility is patched automatically
  • Check mcp_initialize_fix.py for validation patches

๐Ÿ“š Examples

Complete working examples in the example/ directory:

  • claude_code_mcp: Claude Code CLI integration
  • test: Comprehensive example with all features
    • Slack integration
    • OpenAI Agents
    • External MCP servers
    • Custom endpoints

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide.

Development Setup

# Clone the repository
git clone https://github.com/BrainFiber/viyv_mcp
cd viyv_mcp

# Install in development mode
pip install -e .

# Run tests
pytest

# Build package
python -m build

# Run example project
cd example/test
uv sync
STATELESS_HTTP=true uv run python main.py

Testing Guidelines

  • Add sample implementations in test/ directory
  • Test with both session and stateless modes
  • Verify Slack and OpenAI integrations
  • Check external MCP server bridging

๐Ÿ“„ License

MIT License - see the LICENSE file for details.

๐Ÿ‘ฅ Authors

๐Ÿ™ Acknowledgments

๐Ÿ“ฎ Support

๐Ÿšฆ Roadmap

  • WebSocket support for real-time communication
  • Built-in authentication/authorization
  • Tool versioning and migration support
  • Performance profiling dashboard
  • Plugin system for custom integrations
  • GraphQL endpoint support

๐Ÿ“ˆ Changelog

v0.1.10 (Latest)

  • โœจ Added stateless HTTP support for multi-worker deployments
  • ๐Ÿ”ง Improved ASGI-level routing for SSE streaming
  • ๐Ÿ“ฆ Updated FastMCP to 2.12.3 for better compatibility
  • ๐Ÿ› Fixed Pydantic v2 validation issues
  • ๐Ÿ“š Enhanced documentation and examples

v0.1.9

  • ๐ŸŒ‰ External MCP server bridging with tags and filtering
  • ๐Ÿ”„ Dynamic tool refresh on every request
  • ๐Ÿ“ RunContextWrapper pattern for dual compatibility

v0.1.8

  • ๐Ÿค– OpenAI Agents SDK integration
  • ๐Ÿ’ฌ Slack adapter with file handling
  • ๐ŸŽฏ ChatGPT-compatible tool requirements

Made with โค๏ธ by the viyv_mcp community

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

viyv_mcp-0.1.11.tar.gz (45.1 kB view details)

Uploaded Source

Built Distribution

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

viyv_mcp-0.1.11-py3-none-any.whl (51.6 kB view details)

Uploaded Python 3

File details

Details for the file viyv_mcp-0.1.11.tar.gz.

File metadata

  • Download URL: viyv_mcp-0.1.11.tar.gz
  • Upload date:
  • Size: 45.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for viyv_mcp-0.1.11.tar.gz
Algorithm Hash digest
SHA256 23b1ca3d86bc92f926144d0c8e6f9ec4a39dd2ed3f37a273ca0887b8df778510
MD5 78c5d1da39d63dc692ba09f35e96d6dc
BLAKE2b-256 e6760baa383d0bb9004a96ea6017c8d66f21439df39c726bfdcf55042389230c

See more details on using hashes here.

File details

Details for the file viyv_mcp-0.1.11-py3-none-any.whl.

File metadata

  • Download URL: viyv_mcp-0.1.11-py3-none-any.whl
  • Upload date:
  • Size: 51.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for viyv_mcp-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 5e83a38f12bbd22fa9557d499a837509790f38388e7ac81fb8b15fe816c11894
MD5 a37467def4bdf09eee1caee3d7f2696b
BLAKE2b-256 d23cfc4171f6b60739c79400ac1da85353484ac3d6ff347fd2510ffa98df1cc6

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