Metadata-Version: 2.4
Name: viyv_mcp
Version: 1.0.1
Summary: A simple wrapper library for FastMCP + Starlette
Author-email: hiroki takezawa <hiroki.takezawa@brainfiber.net>
License: MIT
Project-URL: Homepage, https://github.com/BrainFiber/viyv_mcp
Project-URL: Repository, https://github.com/BrainFiber/viyv_mcp
Keywords: mcp,fastmcp,starlette,uvicorn
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: starlette>=0.25.0
Requires-Dist: fastmcp>=3.1.0
Requires-Dist: uvicorn>=0.22.0
Requires-Dist: fastapi>=0.115.12
Requires-Dist: build>=1.2.2.post1
Requires-Dist: pydantic>=2
Requires-Dist: pytest>=7.0
Requires-Dist: websockets>=13.0
Requires-Dist: PyJWT>=2.0
Provides-Extra: security
Requires-Dist: PyYAML>=6.0; extra == "security"
Provides-Extra: slack
Requires-Dist: slack-bolt>=1.23.0; extra == "slack"
Requires-Dist: aiohttp>=3.11.18; extra == "slack"
Provides-Extra: openai
Requires-Dist: openai-agents>=0.0.13; extra == "openai"
Dynamic: license-file

# viyv_mcp

**viyv_mcp** is a production-ready Python wrapper around [FastMCP](https://github.com/jlowin/fastmcp) and [Starlette](https://www.starlette.io/) that simplifies creating MCP (Model Context Protocol) servers with minimal boilerplate.

[![PyPI version](https://badge.fury.io/py/viyv_mcp.svg)](https://badge.fury.io/py/viyv_mcp)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Version](https://img.shields.io/badge/version-1.0.0-green.svg)](https://pypi.org/project/viyv_mcp/)

## 🚀 Quick Start

```bash
# 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
```python
from viyv_mcp import tool

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

### 🌉 External MCP Server Bridge
```json
// 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)
```bash
# 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
```

### 🔒 JWT Authentication & Access Control
```python
# Tools with security metadata
@tool(
    description="Query salary",
    namespace="hr",                 # Visible only to hr agents
    security_level="confidential",  # Requires confidential+ clearance
)
def query_salary(employee_id: str) -> str:
    return f"Salary: $100,000"
```

```bash
# Generate JWT for an agent
python -m viyv_mcp generate-jwt \
  --sub hr-agent --clearance confidential --namespace hr \
  --trust common --expires 24h --secret "$SECRET"
```

- **Namespace**: Controls tool visibility (`tools/list` filtering)
- **Security Level**: Controls tool executability (`tools/call` clearance check)
- **Modes**: bypass (dev), authenticated (JWT), deny_all (default safe)
- **Both transports**: Works for stdio (`.mcp.json`) and HTTP

### 🔗 Built-in Integrations
- **Custom FastAPI Endpoints**: Mount additional APIs with `@entry`

## 📦 Installation

```bash
# Basic installation
pip install viyv_mcp

# With optional security config (YAML support)
pip install "viyv_mcp[security]"
```

## 📁 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

### Creating Resources with URI Templates

```python
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

```python
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.
        """
```

### 📂 Tool Grouping (New in v0.1.13)

Organize tools into groups for better discoverability and UI presentation:

```python
from viyv_mcp import tool

def register(mcp):
    @tool(
        description="Add two numbers",
        group="計算ツール",  # Group name
        title="加算"         # UI display name (optional)
    )
    def add(a: int, b: int) -> int:
        return a + b

    @tool(
        description="Subtract two numbers",
        group="計算ツール"  # Same group
    )
    def subtract(a: int, b: int) -> int:
        return a - b

    @tool(
        description="Delete a file",
        group="ファイルシステム",
        destructive=True  # Destructive operation hint
    )
    def delete_file(path: str) -> bool:
        import os
        os.remove(path)
        return True
```

**External MCP Server Grouping:**

```json
// app/mcp_server_configs/filesystem.json
{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
  "group": "ファイルシステム",  // Apply to all tools
  "group_map": {                 // Override per tool (optional)
    "read_file": "ファイル操作/読み込み",
    "write_file": "ファイル操作/書き込み"
  }
}
```

**How it works:**
- Group information is stored in `_meta.viyv.group` (vendor namespace)
- MCP clients can use groups for organized display
- Backward compatible: tools without groups work normally

## 🔧 Configuration

### Environment Variables

```bash
# 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
```

### Configuration Class

```python
# 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

### 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
```python
# 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()
```

```bash
# Run with Gunicorn
gunicorn test_app:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
```

#### Docker Deployment
```dockerfile
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
```bash
# 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
```bash
# 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
  - External MCP servers
  - Custom endpoints

## 🤝 Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md).

### Development Setup

```bash
# 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
- Check external MCP server bridging

## 📄 License

MIT License - see the [LICENSE](LICENSE) file for details.

## 👥 Authors

- **Hiroki Takezawa** - [BrainFiber](https://github.com/BrainFiber)

## 🙏 Acknowledgments

- Built on [FastMCP](https://github.com/jlowin/fastmcp) by jlowin
- Powered by [Starlette](https://www.starlette.io/) ASGI framework
- Implements [Model Context Protocol](https://modelcontextprotocol.io/) specification

## 📮 Support

- 📧 Email: hiroki.takezawa@brainfiber.net
- 🐛 Issues: [GitHub Issues](https://github.com/BrainFiber/viyv_mcp/issues)
- 💬 Discussions: [GitHub Discussions](https://github.com/BrainFiber/viyv_mcp/discussions)
- 📖 Documentation: [Wiki](https://github.com/BrainFiber/viyv_mcp/wiki)

## 🚦 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.14 (Latest - 2025-10-13)
- 📚 **Implementation Examples**: Added comprehensive tool grouping examples in `example/test`
  - 9 internal tools with group organization (Math, Statistics, Web Search, Image Tools)
  - Real-world Playwright MCP server configuration (20 browser automation tools)
- 📖 **Enhanced Documentation**:
  - `GROUPING_IMPLEMENTATION.md` - detailed implementation report
  - `app/mcp_server_configs/README.md` - external MCP server grouping guide
  - Sample configuration files for learning
- ✅ **Verified Implementation**: All examples tested and working with MCP Inspector
- 🎯 Makes tool grouping feature (v0.1.13) immediately usable with practical examples

### v0.1.13
- 📂 **Tool Grouping**: Organize tools with `group` parameter in `@tool` and `@agent` decorators
- 🏷️ **Vendor Namespace**: Uses `_meta.viyv.group` for MCP spec compliance
- 🌉 **External MCP Grouping**: Support `group` and `group_map` in `mcp_server_configs/*.json`
- ✨ **Optional Parameters**: Added `title` and `destructive` hints
- 🔄 **Backward Compatible**: Tools without groups work normally
- 📚 Enhanced templates and documentation with grouping examples

### v0.1.10
- ✨ 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

---

Made with ❤️ by the viyv_mcp community
