azurefunctions-mcp-stdio-adapter


Nameazurefunctions-mcp-stdio-adapter JSON
Version 0.1.0a1 PyPI version JSON
download
home_pageNone
SummaryAzure Functions Python extension for MCP STDIO adapter - converts STDIO MCP servers to streamable HTTP endpoints
upload_time2025-08-04 18:42:44
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseMIT License Copyright (c) 2025 Microsoft Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords authentication azure azure-ad azure-functions functions mcp model-context-protocol oauth2 stdio
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Azure Functions MCP STDIO Adapter

A Python extension for Azure Functions that acts as an adapter between MCP (Model Context Protocol) servers running on STDIO and HTTP clients. This adapter surfaces STDIO-based MCP servers as streamable HTTP endpoints without modifying the underlying MCP server behavior.

## Overview

The Azure Functions MCP STDIO Adapter enables seamless integration between:

- **Input**: Python MCP servers that communicate via STDIO (JSON-RPC over stdin/stdout with Content-Length framing)
- **Output**: Azure Functions HTTP endpoints that expose streamable HTTP responses
- **Transport**: Maintains protocol parity without modifying customer MCP servers

### Data Flow Diagram

```
Client ⇄ HTTP Stream ⇄ Azure Function Adapter ⇄ STDIO ⇄ MCP Server
      │                     │                  │           │
      │                     │                  │           └─ Customer's MCP Server
      │                     │                  └─ JSON-RPC over STDIO
      │                     └─ Process Management & Forwarding
      └─ Streamable HTTP Responses
```

## Features

- **Multi-format Configuration Support**: Supports various JSON configuration formats
- **Process Lifecycle Management**: Automatic start, monitor, and graceful shutdown of MCP servers
- **Streaming HTTP Integration**: Uses MCP SDK's StreamableHTTPSessionManager for real-time communication  
- **UVX Integration**: Supports `uvx` (uv tool run) for running MCP servers without global installation
- **Error Recovery**: Handles MCP server crashes and reconnection scenarios
- **Environment Variable Support**: Passes through environment variables to MCP servers
- **Well-known Configuration Files**: Supports loading from standard file locations

## Session Isolation & Multi-Tenancy

The Azure Functions MCP STDIO Adapter provides **best-effort session isolation** for multi-tenant scenarios while maintaining optimal resource utilization.

### Session-to-Process Mapping

Each unique session gets its own dedicated MCP server process, ensuring proper isolation between different clients:

```text
Session ID → Adapter Instance → Process Manager → MCP Server Process
session-1  →   adapter_1     →   process_1    →     PID 1001
session-2  →   adapter_2     →   process_2    →     PID 1002
session-3  →   adapter_3     →   process_3    →     PID 1003
```

### How It Works

#### Session Lifecycle

```python
# Client A connects with session-1
GET /mcp HTTP/1.1
mcp-session-id: session-1
# → Creates new MCPStdioAdapter instance → Spawns new MCP server process

# Client A makes multiple calls - all use the same process
POST /mcp HTTP/1.1
mcp-session-id: session-1
{"method": "initialize", ...}     # → process_1

POST /mcp HTTP/1.1  
mcp-session-id: session-1
{"method": "tools/list", ...}     # → process_1

POST /mcp HTTP/1.1
mcp-session-id: session-1  
{"method": "tools/call", ...}     # → process_1

# Client B connects with session-2 (concurrent)
GET /mcp HTTP/1.1
mcp-session-id: session-2
# → Creates SEPARATE MCPStdioAdapter → Spawns SEPARATE MCP server process

POST /mcp HTTP/1.1
mcp-session-id: session-2
{"method": "initialize", ...}     # → process_2 (ISOLATED!)
```

#### Session Isolation Guarantees

1. **Process Isolation**: Each session runs in its own MCP server subprocess

   ```python
   # Each session maintains separate process state
   session_adapters = {
       "session-1": MCPStdioAdapter(process_1),  # PID 1001
       "session-2": MCPStdioAdapter(process_2),  # PID 1002  
       "session-3": MCPStdioAdapter(process_3),  # PID 1003
   }
   ```

2. **Memory Isolation**: Each adapter has independent buffers and state

   ```python
   # Session 1's adapter state
   adapter_1._read_buffer = b"session_1_data"
   adapter_1._session_state = "initialized"
   
   # Session 2's adapter state (completely separate)  
   adapter_2._read_buffer = b"session_2_data"
   adapter_2._session_state = "uninitialized"
   ```

3. **Communication Isolation**: Each session has dedicated STDIO channels

   ```python
   # No cross-session message contamination
   adapter_1.process_manager.stdin  # → process_1 stdin
   adapter_2.process_manager.stdin  # → process_2 stdin
   
   adapter_1.process_manager.stdout # ← process_1 stdout  
   adapter_2.process_manager.stdout # ← process_2 stdout
   ```

### Session Management

#### Session Headers

Sessions are identified via HTTP headers:

```http
POST /mcp HTTP/1.1
mcp-session-id: client-unique-session-id
Content-Type: application/json

{"jsonrpc": "2.0", "method": "tools/list", "id": 1}
```

#### Automatic Session Creation

If no session ID is provided, the adapter generates one:

```python
# Client request without session ID
session_id = req.headers.get("mcp-session-id")
if not session_id:
    session_id = str(uuid.uuid4()).replace("-", "")  # Generate new session
    # New adapter and process created automatically
```

#### Session Persistence

Sessions persist across multiple HTTP requests:

```python
# Session state maintained in memory
class MCPSessionState:
    session_id: str
    is_initialized: bool = False
    initialization_response: Optional[Dict[str, Any]] = None
    last_activity: float = 0.0  # Auto-cleanup after timeout
```

### Best-Effort Multi-Tenancy

#### What "Best-Effort" Means

✅ **Guaranteed Isolation:**
- Each session has its own MCP server process
- Memory spaces are completely separate  
- STDIO communication channels are isolated
- Session state is tracked independently

⚠️ **Azure Functions Shared Environment:**
- Sessions share the same Azure Functions runtime
- Sessions share the same file system
- Sessions share network and system resources
- No cryptographic isolation between sessions

#### Resource Management

```python
# Automatic resource cleanup
class MCPSessionManager:
    def __init__(self, session_timeout_seconds: float = 3600):  # 1 hour default
        self._sessions: Dict[str, MCPSessionState] = {}
        
    async def _cleanup_expired_sessions(self):
        """Remove expired sessions and their processes"""
        current_time = time.time()
        expired_sessions = [
            sid for sid, session in self._sessions.items()
            if current_time - session.last_activity > self._session_timeout
        ]
        
        for session_id in expired_sessions:
            # Clean up adapter and terminate process
            await self._cleanup_session(session_id)
```

#### Recommended Usage Patterns

1. **Trusted Multi-Tenancy**: Use for scenarios where tenants are trusted (e.g., different teams in same organization)

2. **Development/Testing**: Ideal for development environments with multiple concurrent users

3. **Microservice Integration**: Perfect for multiple services calling the same MCP functionality

4. **Session-Aware Applications**: Applications that maintain client state across multiple MCP calls

### Limitations & Considerations

#### Security Considerations
- **File System Access**: MCP servers can access the same file system
- **Environment Variables**: Shared environment between sessions  
- **Network Access**: Sessions share network interfaces
- **Process Visibility**: Processes may be visible to each other

#### Resource Limits
- **Memory Usage**: Multiple processes increase memory consumption
- **Process Limits**: Azure Functions has process count limitations
- **Connection Limits**: Each session maintains persistent connections

#### Best Practices
```python
# 1. Use unique session IDs per client
session_id = f"client-{client_id}-{timestamp}"

# 2. Implement proper session cleanup
@app.function_name("cleanup_sessions")
@app.timer_trigger(schedule="0 */30 * * * *")  # Every 30 minutes
async def cleanup_expired_sessions(timer: func.TimerRequest):
    await session_manager.cleanup_expired_sessions()

# 3. Monitor resource usage
@app.function_name("session_metrics")  
@app.http_trigger(methods=["GET"])
async def get_session_metrics(req: func.HttpRequest):
    return {
        "active_sessions": len(session_adapters),
        "total_processes": sum(1 for adapter in session_adapters.values() 
                              if adapter.is_connected)
    }
```

### Configuration for Multi-Tenancy

```json
{
  "mcpServers": {
    "shared-mcp-server": {
      "command": "uvx",
      "args": ["your-mcp-server"],
      "env": {
        "MAX_CONCURRENT_SESSIONS": "10",
        "SESSION_TIMEOUT_SECONDS": "3600"
      },
      "timeout_seconds": 30,
      "restart_on_failure": true,
      "max_restarts": 3
    }
  }
}
```

This architecture provides robust session isolation suitable for most multi-tenant Azure Functions scenarios while maintaining the flexibility and performance benefits of the MCP protocol.

## Authentication & Authorization

The Azure Functions MCP STDIO Adapter provides comprehensive authentication support for both Azure and non-Azure MCP servers, enabling secure remote access with proper token handling and On-Behalf-Of (OBO) flows.

### Authentication Architecture

```text
Client Request → Azure Functions → Auth Provider → MCP Server Process
     ↓               ↓               ↓               ↓
Bearer Token → Token Validation → Env Variables → Authenticated SDK
```

### Supported Authentication Methods

#### 1. No Authentication (`none`)
For development, testing, or internal-only MCP servers:

```json
{
  "mcpServers": {
    "internal-tools": {
      "command": "uvx",
      "args": ["internal-mcp-server"],
      "auth": {
        "method": "none"
      }
    }
  }
}
```

#### 2. Azure Default Credentials (`azure_default`)
Uses Azure Managed Identity when deployed, DefaultAzureCredential locally:

```json
{
  "mcpServers": {
    "azure-resources": {
      "command": "uvx", 
      "args": ["azure-resource-mcp"],
      "auth": {
        "method": "azure_default",
        "azure_scopes": [
          "https://management.azure.com/.default"
        ],
        "forward_user_token": false
      }
    }
  }
}
```

**Use Cases:**
- MCP servers that need to access Azure resources with the function's identity
- Scenarios where the MCP server itself needs Azure permissions
- Backend services that don't need user context

#### 3. Azure On-Behalf-Of (`azure_obo`)
**Perfect for Fabric RTI and similar scenarios** - forwards user tokens to Azure services:

```json
{
  "mcpServers": {
    "fabric-rti-mcp": {
      "command": "uvx",
      "args": ["microsoft-fabric-rti-mcp"],
      "env": {
        "KUSTO_SERVICE_URI": "https://help.kusto.windows.net/",
        "KUSTO_SERVICE_DEFAULT_DB": "Samples"
      },
      "auth": {
        "method": "azure_obo",
        "azure_client_id": "${AZURE_CLIENT_ID}",
        "azure_client_secret": "${AZURE_CLIENT_SECRET}",
        "azure_scopes": [
          "https://management.azure.com/.default",
          "https://fabric.microsoft.com/.default"
        ],
        "forward_user_token": true
      }
    }
  }
}
```

**Environment Variables Set for MCP Server:**
```bash
AZURE_CLIENT_ID=your-app-registration-id
AZURE_CLIENT_SECRET=your-client-secret  
AZURE_TENANT_ID=extracted-from-user-token
AZURE_USER_ASSERTION=original-user-token
AZURE_USE_OBO=true
```

**Use Cases:**
- Fabric RTI MCP servers accessing user's Fabric workspaces
- Any Azure service requiring user context (SharePoint, Graph, etc.)
- Multi-tenant applications with user-specific data access

#### 4. Generic OAuth2 Bearer (`oauth2_bearer`)
For non-Azure OAuth2 providers (Google, GitHub, custom identity providers):

```json
{
  "mcpServers": {
    "github-tools": {
      "command": "uvx",
      "args": ["github-mcp-server"],
      "auth": {
        "method": "oauth2_bearer",
        "oauth2_required_scopes": [
          "repo:read",
          "user:read"
        ],
        "oauth2_issuer": "https://github.com",
        "forward_user_token": true
      }
    }
  }
}
```

**Environment Variables Set for MCP Server:**
```bash
OAUTH_ACCESS_TOKEN=user-provided-token
OAUTH_USER_ID=extracted-user-id
OAUTH_SCOPES=repo:read user:read
```

### Client-Side Authentication

#### HTTP Headers Required

All authenticated requests must include the `Authorization` header:

```http
POST /api/mcp HTTP/1.1
Host: your-function-app.azurewebsites.net
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
mcp-session-id: session-12345

{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "id": 1
}
```

#### MCP Client Configuration

When using the MCP SDK, configure HTTP transport with authentication:

```python
from mcp import ClientSession
from mcp.client.stdio import StdioServerParameters
from mcp.client.sse import SseServerParameters

# For HTTP streaming with auth
server = SseServerParameters(
    url="https://your-function-app.azurewebsites.net/api/mcp",
    headers={
        "Authorization": f"Bearer {user_token}",
        "Content-Type": "application/json"
    }
)

async with ClientSession(server) as session:
    # Use authenticated session
    result = await session.call_tool("list_files", {"path": "/"})
```

### Azure Active Directory Integration

#### App Registration Setup

1. **Create App Registration** in Azure Portal
2. **Configure API Permissions** for target services:
   ```text
   - Microsoft Graph: User.Read
   - Azure Service Management: user_impersonation  
   - Power BI Service: Dataset.Read.All (for Fabric)
   ```
3. **Generate Client Secret**
4. **Configure Application Settings**:
   ```bash
   AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012
   AZURE_CLIENT_SECRET=your-secret-value
   ```

#### Token Acquisition Flow

```typescript
// Client-side token acquisition (JavaScript example)
import { PublicClientApplication } from "@azure/msal-browser";

const msalConfig = {
    auth: {
        clientId: "your-client-id",
        authority: "https://login.microsoftonline.com/your-tenant"
    }
};

const pca = new PublicClientApplication(msalConfig);

// Get token for MCP server access
const tokenRequest = {
    scopes: [
        "https://management.azure.com/.default",
        "https://fabric.microsoft.com/.default"
    ]
};

const response = await pca.acquireTokenSilent(tokenRequest);
const accessToken = response.accessToken;

// Use token with MCP client
const mcpClient = new McpClient({
    url: "https://your-function.azurewebsites.net/api/mcp",
    headers: {
        "Authorization": `Bearer ${accessToken}`
    }
});
```

### Error Handling

#### Authentication Errors

The adapter returns standard HTTP status codes for auth failures:

```json
// 401 Unauthorized - Missing or invalid token
{
  "error": {
    "code": "authentication_required",
    "message": "Missing or invalid Authorization header"
  }
}

// 403 Forbidden - Insufficient scopes  
{
  "error": {
    "code": "insufficient_scopes", 
    "message": "Token missing required scopes: repo:write"
  }
}
```

#### Debugging Authentication

Enable debug logging to troubleshoot auth issues:

```python
import logging
logging.getLogger("azurefunctions.extensions.mcp_server.auth").setLevel(logging.DEBUG)
```

### Security Considerations

#### Token Validation
- Bearer tokens are parsed for claims extraction
- **Production deployments should implement proper JWT signature verification**
- Tokens are validated for required scopes before processing

#### Token Storage
- User tokens are only stored in memory during request processing
- Tokens are passed to MCP servers via environment variables
- No persistent token storage in the adapter

#### Environment Isolation
- Each session gets isolated environment variables
- Authentication credentials are scoped to individual MCP server processes
- No credential sharing between sessions

### Best Practices

#### For Azure MCP Servers
```json
{
  "auth": {
    "method": "azure_obo",
    "azure_scopes": [
      "https://management.azure.com/.default"  // Be specific about scopes
    ],
    "forward_user_token": true  // Enable for user context
  }
}
```

#### For Non-Azure MCP Servers
```json
{
  "auth": {
    "method": "oauth2_bearer", 
    "oauth2_required_scopes": ["read:data"],  // Validate required scopes
    "forward_user_token": true
  }
}
```

#### Environment Variables
```bash
# Use Azure App Settings for secrets
AZURE_CLIENT_SECRET="@Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/client-secret/)"

# Reference environment variables in config
"azure_client_id": "${AZURE_CLIENT_ID}"
```

This authentication architecture ensures secure, scalable access to MCP servers while supporting both Azure-native and generic OAuth2 authentication patterns.

## Installation

```bash
# Install with UV (recommended)
uv add azurefunctions-mcp-stdio-adapter

# Or with pip
pip install azurefunctions-mcp-stdio-adapter
```

## Quick Start

### Configuration-Only Usage

1. Create a configuration file `mcp_config.json`:

```json
{
  "mcpServers": {
    "git-tools": {
      "command": "uvx",
      "args": ["mcp-server-git"],
      "env": {
        "GIT_REPO_PATH": "/path/to/your/repo"
      }
    }
  }
}
```

2. Create your Azure Function app:

```python
from azurefunctions.extensions.mcp_server import MCPFunctionApp, MCPMode

# Load configuration from file
app = MCPFunctionApp(
    mode=MCPMode.STDIO,
    config_file="mcp_config.json"
)
```

### Programmatic Usage

```python
import azure.functions as func
from azurefunctions.extensions.mcp_server import (
    MCPFunctionApp,
    MCPMode,
    MCPStdioConfiguration,
    MCPServerStdioParams
)

# Define MCP server configuration
git_mcp = MCPStdioConfiguration(
    name="git-tools",
    params=MCPServerStdioParams(
        command="uvx",
        args=["mcp-server-git"],
        env={"GIT_REPO_PATH": "/path/to/repo"}
    )
)

# Create MCP Function App
app = MCPFunctionApp(
    mode=MCPMode.STDIO,
    mcp_server=git_mcp
)
```

## Configuration Formats

The adapter supports JSON configuration files with the following format:

### Standard Configuration Format
```json
{
  "mcpServers": {
    "mssql": {
      "command": "python",
      "args": ["server.py"],
      "env": {
        "MSSQL_SERVER": "your_server",
        "MSSQL_DATABASE": "your_database"
      }
    }
  }
}
```

### Example: MySQL Configuration
```json
{
  "mcpServers": {
    "mysql": {
      "command": "uvx",
      "args": ["--from", "mysql-mcp-server", "mysql_mcp_server"],
      "env": {
        "MYSQL_HOST": "localhost",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "your_username",
        "MYSQL_PASSWORD": "your_password",
        "MYSQL_DATABASE": "your_database"
      }
    }
  }
}
```

### Example: Fabric RTI Configuration  
```json
{
  "mcpServers": {
    "fabric-rti-mcp": {
      "command": "uvx",
      "args": ["microsoft-fabric-rti-mcp"],
      "env": {
        "KUSTO_SERVICE_URI": "https://help.kusto.windows.net/",
        "KUSTO_SERVICE_DEFAULT_DB": "Samples"
      }
    }
  }
}
```

## API Reference

### MCPFunctionApp

The main class for creating Azure Function apps with MCP STDIO adapter functionality.

```python
class MCPFunctionApp:
    def __init__(
        self,
        mode: MCPMode = MCPMode.STDIO,
        mcp_server: Optional[MCPStdioConfiguration] = None,
        config_file: Optional[str] = None,
        auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION,
        **kwargs
    ):
        """
        Initialize MCP Function App
        
        Args:
            mode: Operating mode (currently only STDIO supported)
            mcp_server: Programmatic MCP server configuration
            config_file: Path to JSON configuration file
            auth_level: Azure Functions authorization level
        """
```

### MCPStdioConfiguration

Configuration container for MCP STDIO servers.

```python
class MCPStdioConfiguration:
    def __init__(
        self,
        name: str,
        params: MCPServerStdioParams
    ):
        """
        MCP STDIO server configuration
        
        Args:
            name: Unique name for the MCP server
            params: Server execution parameters
        """
```

### MCPServerStdioParams

Parameters for STDIO server execution.

```python
class MCPServerStdioParams:
    def __init__(
        self,
        command: str,
        args: List[str] = None,
        env: Dict[str, str] = None,
        working_dir: Optional[str] = None
    ):
        """
        STDIO server execution parameters
        
        Args:
            command: Command to execute (e.g., "uvx", "python")
            args: Command arguments
            env: Environment variables
            working_dir: Working directory for the process
        """
```

## Deployment

### Local Development

```bash
# Clone and setup
git clone <your-repo>
cd azurefunctions-mcp-stdio-adapter

# Install dependencies
uv sync

# Run tests
uv run pytest

# Format code
uv run black .
uv run isort .
```

### Azure Deployment

1. Ensure your `function_app.py` uses the MCP adapter:

```python
from azurefunctions.extensions.mcp_server import MCPFunctionApp, MCPMode

app = MCPFunctionApp(
    mode=MCPMode.STDIO,
    config_file="mcp_config.json"
)
```

2. Deploy using Azure Functions Core Tools:

```bash
func azure functionapp publish <your-function-app-name>
```

## Error Handling

The adapter includes comprehensive error handling:

- **UVX Detection**: Automatically detects missing `uvx` and provides helpful error messages
- **Process Recovery**: Handles MCP server crashes with automatic restart
- **Connection Management**: Manages STDIO connections with proper cleanup
- **Timeout Handling**: Configurable timeouts for process startup and communication

## Logging and Monitoring

Enable detailed logging by setting the log level:

```python
import logging
logging.basicConfig(level=logging.INFO)

app = MCPFunctionApp(
    mode=MCPMode.STDIO,
    config_file="mcp_config.json"
)
```

## Troubleshooting

### Common Issues

1. **UVX not found**: Ensure `uvx` is installed and available in PATH
2. **Process startup timeout**: Increase timeout in configuration or check MCP server startup time
3. **STDIO communication errors**: Verify MCP server implements proper Content-Length framing

### Debug Mode

Enable debug logging for detailed troubleshooting:

```python
import logging
logging.basicConfig(level=logging.DEBUG)
```

## References

- [MCP Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports) - Official MCP transport specification
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) - STDIO and Streamable HTTP support
- [Azure Functions Python Streaming](https://docs.microsoft.com/azure/azure-functions/functions-reference-python#http-streaming) - Azure Functions HTTP streaming documentation
- [UVX Documentation](https://docs.astral.sh/uv/guides/tools/) - UV tool runner documentation

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Run the test suite: `uv run pytest`
6. Format code: `uv run black . && uv run isort .`
7. Submit a pull request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Support

For issues and questions:

- [GitHub Issues](https://github.com/Azure/azure-functions-python-extensions/issues)
- [Azure Functions Documentation](https://docs.microsoft.com/azure/azure-functions/)
- [MCP Community](https://github.com/modelcontextprotocol)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "azurefunctions-mcp-stdio-adapter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": "Microsoft Corporation <azpysdkhelp@microsoft.com>",
    "keywords": "authentication, azure, azure-ad, azure-functions, functions, mcp, model-context-protocol, oauth2, stdio",
    "author": null,
    "author_email": "Microsoft Corporation <azpysdkhelp@microsoft.com>",
    "download_url": "https://files.pythonhosted.org/packages/43/33/9845d49fa34846d78c4628a239f4b50ecd6de4c3baf0786273ca5e783542/azurefunctions_mcp_stdio_adapter-0.1.0a1.tar.gz",
    "platform": null,
    "description": "# Azure Functions MCP STDIO Adapter\n\nA Python extension for Azure Functions that acts as an adapter between MCP (Model Context Protocol) servers running on STDIO and HTTP clients. This adapter surfaces STDIO-based MCP servers as streamable HTTP endpoints without modifying the underlying MCP server behavior.\n\n## Overview\n\nThe Azure Functions MCP STDIO Adapter enables seamless integration between:\n\n- **Input**: Python MCP servers that communicate via STDIO (JSON-RPC over stdin/stdout with Content-Length framing)\n- **Output**: Azure Functions HTTP endpoints that expose streamable HTTP responses\n- **Transport**: Maintains protocol parity without modifying customer MCP servers\n\n### Data Flow Diagram\n\n```\nClient \u21c4 HTTP Stream \u21c4 Azure Function Adapter \u21c4 STDIO \u21c4 MCP Server\n      \u2502                     \u2502                  \u2502           \u2502\n      \u2502                     \u2502                  \u2502           \u2514\u2500 Customer's MCP Server\n      \u2502                     \u2502                  \u2514\u2500 JSON-RPC over STDIO\n      \u2502                     \u2514\u2500 Process Management & Forwarding\n      \u2514\u2500 Streamable HTTP Responses\n```\n\n## Features\n\n- **Multi-format Configuration Support**: Supports various JSON configuration formats\n- **Process Lifecycle Management**: Automatic start, monitor, and graceful shutdown of MCP servers\n- **Streaming HTTP Integration**: Uses MCP SDK's StreamableHTTPSessionManager for real-time communication  \n- **UVX Integration**: Supports `uvx` (uv tool run) for running MCP servers without global installation\n- **Error Recovery**: Handles MCP server crashes and reconnection scenarios\n- **Environment Variable Support**: Passes through environment variables to MCP servers\n- **Well-known Configuration Files**: Supports loading from standard file locations\n\n## Session Isolation & Multi-Tenancy\n\nThe Azure Functions MCP STDIO Adapter provides **best-effort session isolation** for multi-tenant scenarios while maintaining optimal resource utilization.\n\n### Session-to-Process Mapping\n\nEach unique session gets its own dedicated MCP server process, ensuring proper isolation between different clients:\n\n```text\nSession ID \u2192 Adapter Instance \u2192 Process Manager \u2192 MCP Server Process\nsession-1  \u2192   adapter_1     \u2192   process_1    \u2192     PID 1001\nsession-2  \u2192   adapter_2     \u2192   process_2    \u2192     PID 1002\nsession-3  \u2192   adapter_3     \u2192   process_3    \u2192     PID 1003\n```\n\n### How It Works\n\n#### Session Lifecycle\n\n```python\n# Client A connects with session-1\nGET /mcp HTTP/1.1\nmcp-session-id: session-1\n# \u2192 Creates new MCPStdioAdapter instance \u2192 Spawns new MCP server process\n\n# Client A makes multiple calls - all use the same process\nPOST /mcp HTTP/1.1\nmcp-session-id: session-1\n{\"method\": \"initialize\", ...}     # \u2192 process_1\n\nPOST /mcp HTTP/1.1  \nmcp-session-id: session-1\n{\"method\": \"tools/list\", ...}     # \u2192 process_1\n\nPOST /mcp HTTP/1.1\nmcp-session-id: session-1  \n{\"method\": \"tools/call\", ...}     # \u2192 process_1\n\n# Client B connects with session-2 (concurrent)\nGET /mcp HTTP/1.1\nmcp-session-id: session-2\n# \u2192 Creates SEPARATE MCPStdioAdapter \u2192 Spawns SEPARATE MCP server process\n\nPOST /mcp HTTP/1.1\nmcp-session-id: session-2\n{\"method\": \"initialize\", ...}     # \u2192 process_2 (ISOLATED!)\n```\n\n#### Session Isolation Guarantees\n\n1. **Process Isolation**: Each session runs in its own MCP server subprocess\n\n   ```python\n   # Each session maintains separate process state\n   session_adapters = {\n       \"session-1\": MCPStdioAdapter(process_1),  # PID 1001\n       \"session-2\": MCPStdioAdapter(process_2),  # PID 1002  \n       \"session-3\": MCPStdioAdapter(process_3),  # PID 1003\n   }\n   ```\n\n2. **Memory Isolation**: Each adapter has independent buffers and state\n\n   ```python\n   # Session 1's adapter state\n   adapter_1._read_buffer = b\"session_1_data\"\n   adapter_1._session_state = \"initialized\"\n   \n   # Session 2's adapter state (completely separate)  \n   adapter_2._read_buffer = b\"session_2_data\"\n   adapter_2._session_state = \"uninitialized\"\n   ```\n\n3. **Communication Isolation**: Each session has dedicated STDIO channels\n\n   ```python\n   # No cross-session message contamination\n   adapter_1.process_manager.stdin  # \u2192 process_1 stdin\n   adapter_2.process_manager.stdin  # \u2192 process_2 stdin\n   \n   adapter_1.process_manager.stdout # \u2190 process_1 stdout  \n   adapter_2.process_manager.stdout # \u2190 process_2 stdout\n   ```\n\n### Session Management\n\n#### Session Headers\n\nSessions are identified via HTTP headers:\n\n```http\nPOST /mcp HTTP/1.1\nmcp-session-id: client-unique-session-id\nContent-Type: application/json\n\n{\"jsonrpc\": \"2.0\", \"method\": \"tools/list\", \"id\": 1}\n```\n\n#### Automatic Session Creation\n\nIf no session ID is provided, the adapter generates one:\n\n```python\n# Client request without session ID\nsession_id = req.headers.get(\"mcp-session-id\")\nif not session_id:\n    session_id = str(uuid.uuid4()).replace(\"-\", \"\")  # Generate new session\n    # New adapter and process created automatically\n```\n\n#### Session Persistence\n\nSessions persist across multiple HTTP requests:\n\n```python\n# Session state maintained in memory\nclass MCPSessionState:\n    session_id: str\n    is_initialized: bool = False\n    initialization_response: Optional[Dict[str, Any]] = None\n    last_activity: float = 0.0  # Auto-cleanup after timeout\n```\n\n### Best-Effort Multi-Tenancy\n\n#### What \"Best-Effort\" Means\n\n\u2705 **Guaranteed Isolation:**\n- Each session has its own MCP server process\n- Memory spaces are completely separate  \n- STDIO communication channels are isolated\n- Session state is tracked independently\n\n\u26a0\ufe0f **Azure Functions Shared Environment:**\n- Sessions share the same Azure Functions runtime\n- Sessions share the same file system\n- Sessions share network and system resources\n- No cryptographic isolation between sessions\n\n#### Resource Management\n\n```python\n# Automatic resource cleanup\nclass MCPSessionManager:\n    def __init__(self, session_timeout_seconds: float = 3600):  # 1 hour default\n        self._sessions: Dict[str, MCPSessionState] = {}\n        \n    async def _cleanup_expired_sessions(self):\n        \"\"\"Remove expired sessions and their processes\"\"\"\n        current_time = time.time()\n        expired_sessions = [\n            sid for sid, session in self._sessions.items()\n            if current_time - session.last_activity > self._session_timeout\n        ]\n        \n        for session_id in expired_sessions:\n            # Clean up adapter and terminate process\n            await self._cleanup_session(session_id)\n```\n\n#### Recommended Usage Patterns\n\n1. **Trusted Multi-Tenancy**: Use for scenarios where tenants are trusted (e.g., different teams in same organization)\n\n2. **Development/Testing**: Ideal for development environments with multiple concurrent users\n\n3. **Microservice Integration**: Perfect for multiple services calling the same MCP functionality\n\n4. **Session-Aware Applications**: Applications that maintain client state across multiple MCP calls\n\n### Limitations & Considerations\n\n#### Security Considerations\n- **File System Access**: MCP servers can access the same file system\n- **Environment Variables**: Shared environment between sessions  \n- **Network Access**: Sessions share network interfaces\n- **Process Visibility**: Processes may be visible to each other\n\n#### Resource Limits\n- **Memory Usage**: Multiple processes increase memory consumption\n- **Process Limits**: Azure Functions has process count limitations\n- **Connection Limits**: Each session maintains persistent connections\n\n#### Best Practices\n```python\n# 1. Use unique session IDs per client\nsession_id = f\"client-{client_id}-{timestamp}\"\n\n# 2. Implement proper session cleanup\n@app.function_name(\"cleanup_sessions\")\n@app.timer_trigger(schedule=\"0 */30 * * * *\")  # Every 30 minutes\nasync def cleanup_expired_sessions(timer: func.TimerRequest):\n    await session_manager.cleanup_expired_sessions()\n\n# 3. Monitor resource usage\n@app.function_name(\"session_metrics\")  \n@app.http_trigger(methods=[\"GET\"])\nasync def get_session_metrics(req: func.HttpRequest):\n    return {\n        \"active_sessions\": len(session_adapters),\n        \"total_processes\": sum(1 for adapter in session_adapters.values() \n                              if adapter.is_connected)\n    }\n```\n\n### Configuration for Multi-Tenancy\n\n```json\n{\n  \"mcpServers\": {\n    \"shared-mcp-server\": {\n      \"command\": \"uvx\",\n      \"args\": [\"your-mcp-server\"],\n      \"env\": {\n        \"MAX_CONCURRENT_SESSIONS\": \"10\",\n        \"SESSION_TIMEOUT_SECONDS\": \"3600\"\n      },\n      \"timeout_seconds\": 30,\n      \"restart_on_failure\": true,\n      \"max_restarts\": 3\n    }\n  }\n}\n```\n\nThis architecture provides robust session isolation suitable for most multi-tenant Azure Functions scenarios while maintaining the flexibility and performance benefits of the MCP protocol.\n\n## Authentication & Authorization\n\nThe Azure Functions MCP STDIO Adapter provides comprehensive authentication support for both Azure and non-Azure MCP servers, enabling secure remote access with proper token handling and On-Behalf-Of (OBO) flows.\n\n### Authentication Architecture\n\n```text\nClient Request \u2192 Azure Functions \u2192 Auth Provider \u2192 MCP Server Process\n     \u2193               \u2193               \u2193               \u2193\nBearer Token \u2192 Token Validation \u2192 Env Variables \u2192 Authenticated SDK\n```\n\n### Supported Authentication Methods\n\n#### 1. No Authentication (`none`)\nFor development, testing, or internal-only MCP servers:\n\n```json\n{\n  \"mcpServers\": {\n    \"internal-tools\": {\n      \"command\": \"uvx\",\n      \"args\": [\"internal-mcp-server\"],\n      \"auth\": {\n        \"method\": \"none\"\n      }\n    }\n  }\n}\n```\n\n#### 2. Azure Default Credentials (`azure_default`)\nUses Azure Managed Identity when deployed, DefaultAzureCredential locally:\n\n```json\n{\n  \"mcpServers\": {\n    \"azure-resources\": {\n      \"command\": \"uvx\", \n      \"args\": [\"azure-resource-mcp\"],\n      \"auth\": {\n        \"method\": \"azure_default\",\n        \"azure_scopes\": [\n          \"https://management.azure.com/.default\"\n        ],\n        \"forward_user_token\": false\n      }\n    }\n  }\n}\n```\n\n**Use Cases:**\n- MCP servers that need to access Azure resources with the function's identity\n- Scenarios where the MCP server itself needs Azure permissions\n- Backend services that don't need user context\n\n#### 3. Azure On-Behalf-Of (`azure_obo`)\n**Perfect for Fabric RTI and similar scenarios** - forwards user tokens to Azure services:\n\n```json\n{\n  \"mcpServers\": {\n    \"fabric-rti-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"microsoft-fabric-rti-mcp\"],\n      \"env\": {\n        \"KUSTO_SERVICE_URI\": \"https://help.kusto.windows.net/\",\n        \"KUSTO_SERVICE_DEFAULT_DB\": \"Samples\"\n      },\n      \"auth\": {\n        \"method\": \"azure_obo\",\n        \"azure_client_id\": \"${AZURE_CLIENT_ID}\",\n        \"azure_client_secret\": \"${AZURE_CLIENT_SECRET}\",\n        \"azure_scopes\": [\n          \"https://management.azure.com/.default\",\n          \"https://fabric.microsoft.com/.default\"\n        ],\n        \"forward_user_token\": true\n      }\n    }\n  }\n}\n```\n\n**Environment Variables Set for MCP Server:**\n```bash\nAZURE_CLIENT_ID=your-app-registration-id\nAZURE_CLIENT_SECRET=your-client-secret  \nAZURE_TENANT_ID=extracted-from-user-token\nAZURE_USER_ASSERTION=original-user-token\nAZURE_USE_OBO=true\n```\n\n**Use Cases:**\n- Fabric RTI MCP servers accessing user's Fabric workspaces\n- Any Azure service requiring user context (SharePoint, Graph, etc.)\n- Multi-tenant applications with user-specific data access\n\n#### 4. Generic OAuth2 Bearer (`oauth2_bearer`)\nFor non-Azure OAuth2 providers (Google, GitHub, custom identity providers):\n\n```json\n{\n  \"mcpServers\": {\n    \"github-tools\": {\n      \"command\": \"uvx\",\n      \"args\": [\"github-mcp-server\"],\n      \"auth\": {\n        \"method\": \"oauth2_bearer\",\n        \"oauth2_required_scopes\": [\n          \"repo:read\",\n          \"user:read\"\n        ],\n        \"oauth2_issuer\": \"https://github.com\",\n        \"forward_user_token\": true\n      }\n    }\n  }\n}\n```\n\n**Environment Variables Set for MCP Server:**\n```bash\nOAUTH_ACCESS_TOKEN=user-provided-token\nOAUTH_USER_ID=extracted-user-id\nOAUTH_SCOPES=repo:read user:read\n```\n\n### Client-Side Authentication\n\n#### HTTP Headers Required\n\nAll authenticated requests must include the `Authorization` header:\n\n```http\nPOST /api/mcp HTTP/1.1\nHost: your-function-app.azurewebsites.net\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...\nmcp-session-id: session-12345\n\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools/list\",\n  \"id\": 1\n}\n```\n\n#### MCP Client Configuration\n\nWhen using the MCP SDK, configure HTTP transport with authentication:\n\n```python\nfrom mcp import ClientSession\nfrom mcp.client.stdio import StdioServerParameters\nfrom mcp.client.sse import SseServerParameters\n\n# For HTTP streaming with auth\nserver = SseServerParameters(\n    url=\"https://your-function-app.azurewebsites.net/api/mcp\",\n    headers={\n        \"Authorization\": f\"Bearer {user_token}\",\n        \"Content-Type\": \"application/json\"\n    }\n)\n\nasync with ClientSession(server) as session:\n    # Use authenticated session\n    result = await session.call_tool(\"list_files\", {\"path\": \"/\"})\n```\n\n### Azure Active Directory Integration\n\n#### App Registration Setup\n\n1. **Create App Registration** in Azure Portal\n2. **Configure API Permissions** for target services:\n   ```text\n   - Microsoft Graph: User.Read\n   - Azure Service Management: user_impersonation  \n   - Power BI Service: Dataset.Read.All (for Fabric)\n   ```\n3. **Generate Client Secret**\n4. **Configure Application Settings**:\n   ```bash\n   AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012\n   AZURE_CLIENT_SECRET=your-secret-value\n   ```\n\n#### Token Acquisition Flow\n\n```typescript\n// Client-side token acquisition (JavaScript example)\nimport { PublicClientApplication } from \"@azure/msal-browser\";\n\nconst msalConfig = {\n    auth: {\n        clientId: \"your-client-id\",\n        authority: \"https://login.microsoftonline.com/your-tenant\"\n    }\n};\n\nconst pca = new PublicClientApplication(msalConfig);\n\n// Get token for MCP server access\nconst tokenRequest = {\n    scopes: [\n        \"https://management.azure.com/.default\",\n        \"https://fabric.microsoft.com/.default\"\n    ]\n};\n\nconst response = await pca.acquireTokenSilent(tokenRequest);\nconst accessToken = response.accessToken;\n\n// Use token with MCP client\nconst mcpClient = new McpClient({\n    url: \"https://your-function.azurewebsites.net/api/mcp\",\n    headers: {\n        \"Authorization\": `Bearer ${accessToken}`\n    }\n});\n```\n\n### Error Handling\n\n#### Authentication Errors\n\nThe adapter returns standard HTTP status codes for auth failures:\n\n```json\n// 401 Unauthorized - Missing or invalid token\n{\n  \"error\": {\n    \"code\": \"authentication_required\",\n    \"message\": \"Missing or invalid Authorization header\"\n  }\n}\n\n// 403 Forbidden - Insufficient scopes  \n{\n  \"error\": {\n    \"code\": \"insufficient_scopes\", \n    \"message\": \"Token missing required scopes: repo:write\"\n  }\n}\n```\n\n#### Debugging Authentication\n\nEnable debug logging to troubleshoot auth issues:\n\n```python\nimport logging\nlogging.getLogger(\"azurefunctions.extensions.mcp_server.auth\").setLevel(logging.DEBUG)\n```\n\n### Security Considerations\n\n#### Token Validation\n- Bearer tokens are parsed for claims extraction\n- **Production deployments should implement proper JWT signature verification**\n- Tokens are validated for required scopes before processing\n\n#### Token Storage\n- User tokens are only stored in memory during request processing\n- Tokens are passed to MCP servers via environment variables\n- No persistent token storage in the adapter\n\n#### Environment Isolation\n- Each session gets isolated environment variables\n- Authentication credentials are scoped to individual MCP server processes\n- No credential sharing between sessions\n\n### Best Practices\n\n#### For Azure MCP Servers\n```json\n{\n  \"auth\": {\n    \"method\": \"azure_obo\",\n    \"azure_scopes\": [\n      \"https://management.azure.com/.default\"  // Be specific about scopes\n    ],\n    \"forward_user_token\": true  // Enable for user context\n  }\n}\n```\n\n#### For Non-Azure MCP Servers\n```json\n{\n  \"auth\": {\n    \"method\": \"oauth2_bearer\", \n    \"oauth2_required_scopes\": [\"read:data\"],  // Validate required scopes\n    \"forward_user_token\": true\n  }\n}\n```\n\n#### Environment Variables\n```bash\n# Use Azure App Settings for secrets\nAZURE_CLIENT_SECRET=\"@Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/client-secret/)\"\n\n# Reference environment variables in config\n\"azure_client_id\": \"${AZURE_CLIENT_ID}\"\n```\n\nThis authentication architecture ensures secure, scalable access to MCP servers while supporting both Azure-native and generic OAuth2 authentication patterns.\n\n## Installation\n\n```bash\n# Install with UV (recommended)\nuv add azurefunctions-mcp-stdio-adapter\n\n# Or with pip\npip install azurefunctions-mcp-stdio-adapter\n```\n\n## Quick Start\n\n### Configuration-Only Usage\n\n1. Create a configuration file `mcp_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"git-tools\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-server-git\"],\n      \"env\": {\n        \"GIT_REPO_PATH\": \"/path/to/your/repo\"\n      }\n    }\n  }\n}\n```\n\n2. Create your Azure Function app:\n\n```python\nfrom azurefunctions.extensions.mcp_server import MCPFunctionApp, MCPMode\n\n# Load configuration from file\napp = MCPFunctionApp(\n    mode=MCPMode.STDIO,\n    config_file=\"mcp_config.json\"\n)\n```\n\n### Programmatic Usage\n\n```python\nimport azure.functions as func\nfrom azurefunctions.extensions.mcp_server import (\n    MCPFunctionApp,\n    MCPMode,\n    MCPStdioConfiguration,\n    MCPServerStdioParams\n)\n\n# Define MCP server configuration\ngit_mcp = MCPStdioConfiguration(\n    name=\"git-tools\",\n    params=MCPServerStdioParams(\n        command=\"uvx\",\n        args=[\"mcp-server-git\"],\n        env={\"GIT_REPO_PATH\": \"/path/to/repo\"}\n    )\n)\n\n# Create MCP Function App\napp = MCPFunctionApp(\n    mode=MCPMode.STDIO,\n    mcp_server=git_mcp\n)\n```\n\n## Configuration Formats\n\nThe adapter supports JSON configuration files with the following format:\n\n### Standard Configuration Format\n```json\n{\n  \"mcpServers\": {\n    \"mssql\": {\n      \"command\": \"python\",\n      \"args\": [\"server.py\"],\n      \"env\": {\n        \"MSSQL_SERVER\": \"your_server\",\n        \"MSSQL_DATABASE\": \"your_database\"\n      }\n    }\n  }\n}\n```\n\n### Example: MySQL Configuration\n```json\n{\n  \"mcpServers\": {\n    \"mysql\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"mysql-mcp-server\", \"mysql_mcp_server\"],\n      \"env\": {\n        \"MYSQL_HOST\": \"localhost\",\n        \"MYSQL_PORT\": \"3306\",\n        \"MYSQL_USER\": \"your_username\",\n        \"MYSQL_PASSWORD\": \"your_password\",\n        \"MYSQL_DATABASE\": \"your_database\"\n      }\n    }\n  }\n}\n```\n\n### Example: Fabric RTI Configuration  \n```json\n{\n  \"mcpServers\": {\n    \"fabric-rti-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"microsoft-fabric-rti-mcp\"],\n      \"env\": {\n        \"KUSTO_SERVICE_URI\": \"https://help.kusto.windows.net/\",\n        \"KUSTO_SERVICE_DEFAULT_DB\": \"Samples\"\n      }\n    }\n  }\n}\n```\n\n## API Reference\n\n### MCPFunctionApp\n\nThe main class for creating Azure Function apps with MCP STDIO adapter functionality.\n\n```python\nclass MCPFunctionApp:\n    def __init__(\n        self,\n        mode: MCPMode = MCPMode.STDIO,\n        mcp_server: Optional[MCPStdioConfiguration] = None,\n        config_file: Optional[str] = None,\n        auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION,\n        **kwargs\n    ):\n        \"\"\"\n        Initialize MCP Function App\n        \n        Args:\n            mode: Operating mode (currently only STDIO supported)\n            mcp_server: Programmatic MCP server configuration\n            config_file: Path to JSON configuration file\n            auth_level: Azure Functions authorization level\n        \"\"\"\n```\n\n### MCPStdioConfiguration\n\nConfiguration container for MCP STDIO servers.\n\n```python\nclass MCPStdioConfiguration:\n    def __init__(\n        self,\n        name: str,\n        params: MCPServerStdioParams\n    ):\n        \"\"\"\n        MCP STDIO server configuration\n        \n        Args:\n            name: Unique name for the MCP server\n            params: Server execution parameters\n        \"\"\"\n```\n\n### MCPServerStdioParams\n\nParameters for STDIO server execution.\n\n```python\nclass MCPServerStdioParams:\n    def __init__(\n        self,\n        command: str,\n        args: List[str] = None,\n        env: Dict[str, str] = None,\n        working_dir: Optional[str] = None\n    ):\n        \"\"\"\n        STDIO server execution parameters\n        \n        Args:\n            command: Command to execute (e.g., \"uvx\", \"python\")\n            args: Command arguments\n            env: Environment variables\n            working_dir: Working directory for the process\n        \"\"\"\n```\n\n## Deployment\n\n### Local Development\n\n```bash\n# Clone and setup\ngit clone <your-repo>\ncd azurefunctions-mcp-stdio-adapter\n\n# Install dependencies\nuv sync\n\n# Run tests\nuv run pytest\n\n# Format code\nuv run black .\nuv run isort .\n```\n\n### Azure Deployment\n\n1. Ensure your `function_app.py` uses the MCP adapter:\n\n```python\nfrom azurefunctions.extensions.mcp_server import MCPFunctionApp, MCPMode\n\napp = MCPFunctionApp(\n    mode=MCPMode.STDIO,\n    config_file=\"mcp_config.json\"\n)\n```\n\n2. Deploy using Azure Functions Core Tools:\n\n```bash\nfunc azure functionapp publish <your-function-app-name>\n```\n\n## Error Handling\n\nThe adapter includes comprehensive error handling:\n\n- **UVX Detection**: Automatically detects missing `uvx` and provides helpful error messages\n- **Process Recovery**: Handles MCP server crashes with automatic restart\n- **Connection Management**: Manages STDIO connections with proper cleanup\n- **Timeout Handling**: Configurable timeouts for process startup and communication\n\n## Logging and Monitoring\n\nEnable detailed logging by setting the log level:\n\n```python\nimport logging\nlogging.basicConfig(level=logging.INFO)\n\napp = MCPFunctionApp(\n    mode=MCPMode.STDIO,\n    config_file=\"mcp_config.json\"\n)\n```\n\n## Troubleshooting\n\n### Common Issues\n\n1. **UVX not found**: Ensure `uvx` is installed and available in PATH\n2. **Process startup timeout**: Increase timeout in configuration or check MCP server startup time\n3. **STDIO communication errors**: Verify MCP server implements proper Content-Length framing\n\n### Debug Mode\n\nEnable debug logging for detailed troubleshooting:\n\n```python\nimport logging\nlogging.basicConfig(level=logging.DEBUG)\n```\n\n## References\n\n- [MCP Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports) - Official MCP transport specification\n- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) - STDIO and Streamable HTTP support\n- [Azure Functions Python Streaming](https://docs.microsoft.com/azure/azure-functions/functions-reference-python#http-streaming) - Azure Functions HTTP streaming documentation\n- [UVX Documentation](https://docs.astral.sh/uv/guides/tools/) - UV tool runner documentation\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Run the test suite: `uv run pytest`\n6. Format code: `uv run black . && uv run isort .`\n7. Submit a pull request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Support\n\nFor issues and questions:\n\n- [GitHub Issues](https://github.com/Azure/azure-functions-python-extensions/issues)\n- [Azure Functions Documentation](https://docs.microsoft.com/azure/azure-functions/)\n- [MCP Community](https://github.com/modelcontextprotocol)\n",
    "bugtrack_url": null,
    "license": "MIT License\n        \n        Copyright (c) 2025 Microsoft Corporation\n        \n        Permission is hereby granted, free of charge, to any person obtaining a copy\n        of this software and associated documentation files (the \"Software\"), to deal\n        in the Software without restriction, including without limitation the rights\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n        copies of the Software, and to permit persons to whom the Software is\n        furnished to do so, subject to the following conditions:\n        \n        The above copyright notice and this permission notice shall be included in all\n        copies or substantial portions of the Software.\n        \n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n        SOFTWARE.",
    "summary": "Azure Functions Python extension for MCP STDIO adapter - converts STDIO MCP servers to streamable HTTP endpoints",
    "version": "0.1.0a1",
    "project_urls": {
        "Bug Reports": "https://github.com/Azure/azure-functions-python-extensions/issues",
        "Changelog": "https://github.com/Azure/azure-functions-python-extensions/blob/main/azurefunctions-mcp-stdio-adapter/CHANGELOG.md",
        "Documentation": "https://docs.microsoft.com/azure/azure-functions/",
        "Funding": "https://github.com/sponsors/Azure",
        "Homepage": "https://github.com/Azure/azure-functions-python-extensions",
        "Repository": "https://github.com/Azure/azure-functions-python-extensions.git",
        "Source Code": "https://github.com/Azure/azure-functions-python-extensions/tree/main/azurefunctions-mcp-stdio-adapter"
    },
    "split_keywords": [
        "authentication",
        " azure",
        " azure-ad",
        " azure-functions",
        " functions",
        " mcp",
        " model-context-protocol",
        " oauth2",
        " stdio"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a19ec1736838a52dd77f6371098a8b51cb43a367c1caf155f5558eab5cbc8627",
                "md5": "b51bf50a671c75c781cab95222563ab8",
                "sha256": "b12010f302a3a1f58ac3e7b35bb6f2df6e6fbb354d312dec5f45636814d268b2"
            },
            "downloads": -1,
            "filename": "azurefunctions_mcp_stdio_adapter-0.1.0a1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b51bf50a671c75c781cab95222563ab8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 47469,
            "upload_time": "2025-08-04T18:42:43",
            "upload_time_iso_8601": "2025-08-04T18:42:43.027617Z",
            "url": "https://files.pythonhosted.org/packages/a1/9e/c1736838a52dd77f6371098a8b51cb43a367c1caf155f5558eab5cbc8627/azurefunctions_mcp_stdio_adapter-0.1.0a1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "43339845d49fa34846d78c4628a239f4b50ecd6de4c3baf0786273ca5e783542",
                "md5": "42789aa8689d47ff7f80064045dc7986",
                "sha256": "862580def3714453bd6499c6bdf50a9fb408c0a625a3c726ae4efeb9663db506"
            },
            "downloads": -1,
            "filename": "azurefunctions_mcp_stdio_adapter-0.1.0a1.tar.gz",
            "has_sig": false,
            "md5_digest": "42789aa8689d47ff7f80064045dc7986",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 49294,
            "upload_time": "2025-08-04T18:42:44",
            "upload_time_iso_8601": "2025-08-04T18:42:44.389256Z",
            "url": "https://files.pythonhosted.org/packages/43/33/9845d49fa34846d78c4628a239f4b50ecd6de4c3baf0786273ca5e783542/azurefunctions_mcp_stdio_adapter-0.1.0a1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-04 18:42:44",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Azure",
    "github_project": "azure-functions-python-extensions",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "azurefunctions-mcp-stdio-adapter"
}
        
Elapsed time: 0.59375s