Metadata-Version: 2.4
Name: opal-mcp-adapter
Version: 0.0.1
Summary: Bidirectional adapter for converting between MCP and Opal tools
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.104.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: mcp>=1.9.4
Requires-Dist: optimizely-opal-opal-tools-sdk>=0.1.1.dev0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-multipart>=0.0.6
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: uvicorn>=0.24.0
Provides-Extra: dev
Requires-Dist: httpx>=0.25.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# MCP-Opal Adapter

A bidirectional adapter service that converts between MCP (Model Context Protocol) tools and Opal tools using the official Opal Tools SDK with automatic MCP discovery.

## Key Features

- **MCP Discovery**: Automatically discovers tools from MCP servers
- **Proper Opal Tools SDK Integration**: Uses `ToolsService` and `@tool` decorator
- **Dynamic Schema Translation**: JSON Schema to Pydantic model conversion
- **JSON-RPC Proxy**: Forwards MCP calls via JSON-RPC protocol
- **Discovery Endpoint**: Exposes `/discovery` for tool listing
- **Just-in-Time Configuration**: HTTP API for dynamic tool registration

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                    HTTP Configuration API                   │
│           POST /configure (MCP endpoint only)               │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                 MCP-Opal Proxy Service                      │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │   MCP Discovery │◄──►│   Opal Tools    │                │
│  │   (tools/list)  │    │   SDK           │                │
│  └─────────────────┘    └─────────────────┘                │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │  Dynamic Tool   │    │  Protocol       │                │
│  │  Registry       │    │  Translator     │                │
│  └─────────────────┘    └─────────────────┘                │
└─────────────────────────────────────────────────────────────┘
```

## Quick Start

### 1. Build and Run

```bash
# Build the Docker image
docker build -t mcp-opal-adapter .

# Run with Docker Compose
docker-compose up -d
```

### 2. Configure MCP Tools via Discovery

```bash
# Configure tools by discovering them from an MCP server
curl -X POST http://localhost:8000/configure \
  -H "Content-Type: application/json" \
  -d '"http://your-mcp-server:3000"'
```

### 3. Discover Available Tools

```bash
# Get list of available Opal tools
curl http://localhost:8000/discovery
```

### 4. Call Tools

```bash
# Call a discovered tool
curl -X POST http://localhost:8000/tools/weather_lookup \
  -H "Content-Type: application/json" \
  -d '{"location": "New York", "units": "imperial"}'
```

## API Reference

### Configuration Endpoints

#### POST /configure
Configure MCP tools by discovering them from an MCP server.

**Request Body:**
```json
"http://mcp-server:3000"
```

**Response:**
```json
{
  "status": "configured",
  "tools": ["weather_lookup", "calculator"],
  "total_discovered": 2,
  "successfully_configured": 2
}
```

### Opal Tools Endpoints

#### GET /discovery
Discover available Opal tools (auto-generated by Opal Tools SDK).

#### POST /tools/{tool_name}
Call a configured tool via Opal interface.

**Request Body:**
```json
{
  "param1": "value1",
  "param2": 42
}
```

### Management Endpoints

#### GET /health
Health check endpoint.

#### GET /status
Get adapter status and configuration.

#### DELETE /configure/{tool_name}
Remove a configured tool.

## MCP Discovery Process

The adapter automatically:

1. **Discovers Tools**: Calls `tools/list` on the MCP server
2. **Extracts Schemas**: Gets tool names, descriptions, and input schemas
3. **Converts Schemas**: Transforms JSON Schema to Pydantic models
4. **Creates Proxies**: Generates proxy functions for each tool
5. **Registers Tools**: Registers them with the Opal Tools SDK

### MCP Protocol Support

The adapter supports the standard MCP protocol:

- **tools/list**: Discovers available tools
- **tools/call**: Executes tool calls via JSON-RPC
- **server/health**: Health checking (optional)

## Development

### Local Development
```bash
# Install uv if not already installed
pip install uv

# Install dependencies using uv
uv sync

# For development with testing tools
uv sync --extra dev

# Run development server
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```

### Testing
```bash
# Run tests using uv
uv run pytest

# Or install dev dependencies and run tests
uv sync --extra dev
pytest
```

### Development Workflow
```bash
# Install all dependencies including dev tools
make build-dev

# Run tests
make test

# Run development server
make run
```

## Deployment

### Docker Compose
```yaml
version: '3.8'
services:
  mcp-opal-adapter:
    build: .
    ports:
      - "8000:8000"
    environment:
      - ADAPTER_PORT=8000
      - LOG_LEVEL=info
    networks:
      - adapter-network
```

### Kubernetes
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-opal-adapter
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mcp-opal-adapter
  template:
    metadata:
      labels:
        app: mcp-opal-adapter
    spec:
      containers:
      - name: adapter
        image: mcp-opal-adapter:latest
        ports:
        - containerPort: 8000
        env:
        - name: ADAPTER_PORT
          value: "8000"
        - name: LOG_LEVEL
          value: "info"
```

## Protocol Translation

### MCP to Opal Flow
1. **Discover Tools**: Call `tools/list` on MCP server
2. **Convert Schema**: JSON Schema → Pydantic model using `create_model()`
3. **Create Proxy Function**: Async function that forwards to MCP server
4. **Register with Opal SDK**: Use `@tool` decorator to register
5. **Handle Calls**: Proxy function forwards JSON-RPC calls to MCP server

### JSON-RPC Proxy
```python
# MCP JSON-RPC request format
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tool_name",
    "arguments": {"param1": "value1"}
  }
}
```

## Key Implementation Details

### Opal Tools SDK Integration
```python
from opal_tools_sdk import ToolsService, tool

# Initialize with FastAPI app
app = FastAPI()
tools_service = ToolsService(app)

# Register dynamic tool
tool_decorator = tool("tool_name", "description")
registered_func = tool_decorator(proxy_function)
```

### Dynamic Pydantic Model Creation
```python
from pydantic import create_model

# Convert JSON Schema to Pydantic model
model_class = create_model(
    "ToolParameters",
    **field_definitions
)
```

### MCP Discovery Function
```python
async def discover_mcp_tools(mcp_endpoint: str):
    # Call tools/list on MCP server
    discovery_request = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/list",
        "params": {}
    }
    # Process response and extract tool information
```

## Error Handling

### Network Errors
- Connection timeouts (30s default)
- MCP server unavailability
- JSON-RPC protocol errors

### Validation Errors
- Schema validation failures via Pydantic
- Required field missing
- Type conversion errors

### Discovery Errors
- MCP server discovery failures
- Invalid tool schemas
- Duplicate tool names

## Monitoring

### Health Checks
- Service availability
- Tool count monitoring
- Configuration status

### Logging
- Structured logging throughout
- Error tracking
- Performance monitoring

## Security Considerations

### Input Validation
- Schema-based validation via Pydantic
- Type checking and conversion
- Required field enforcement

### Network Security
- Timeout configuration
- Error message sanitization
- Connection pooling

## Future Enhancements

### Planned Features
- Authentication and authorization
- Rate limiting
- Caching layer
- Metrics collection
- WebSocket support
- GraphQL interface

### Scalability Improvements
- Database persistence
- Load balancing
- Service discovery
- Circuit breaker pattern

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request

## License

MIT License - see LICENSE file for details. 