Skip to main content

Model Context Protocol Python SDK with ETDI security enhancements

Project description

Model Context Protocol Python SDK with ETDI Security

A Python implementation of the Model Context Protocol (MCP) with Enhanced Tool Definition Interface (ETDI) security extensions that seamlessly integrates with existing MCP infrastructure.

Overview

This SDK provides a secure implementation of MCP with OAuth 2.0-based security enhancements to prevent Tool Poisoning and Rug Pull attacks. ETDI adds cryptographic verification, immutable versioned definitions, and explicit permission management to the MCP ecosystem while maintaining full compatibility with existing MCP servers and clients.

🔄 Seamless MCP Integration

ETDI is designed for zero-friction adoption with existing MCP infrastructure:

✅ Backward Compatibility

  • Existing MCP servers work unchanged - ETDI clients can discover and use any MCP server
  • Existing MCP clients work unchanged - ETDI servers are fully MCP-compatible
  • Gradual migration path - Add security incrementally without breaking existing workflows
  • Optional security - ETDI features are opt-in, not mandatory

🔌 Drop-in Integration

# Existing FastMCP server becomes ETDI-secured with decorator
from mcp.server.fastmcp import FastMCP

app = FastMCP("My Server")

# Standard tool (no security)
@app.tool()
def standard_tool(data: str) -> str:
    return f"Processed: {data}"

# ETDI-secured tool with OAuth + Request Signing
@app.tool(
    etdi=True,
    etdi_permissions=["data:read", "data:write"],
    etdi_oauth_scopes=["tools:execute"],
    etdi_require_request_signing=True
)
def secure_tool(sensitive_data: str) -> str:
    return f"Securely processed: {sensitive_data}"

🌐 Universal Discovery

# ETDI client discovers ALL MCP servers (ETDI and non-ETDI)
from mcp.etdi.client import ETDIClient

client = ETDIClient(config)
await client.connect_to_server(["python", "-m", "any_mcp_server"], "server-name")
tools = await client.discover_tools()  # Works with any MCP server!

Features

Core MCP Functionality

  • Client/Server Architecture: Full MCP client and server implementations
  • Tool Management: Register, discover, and invoke tools
  • Resource Access: Secure access to external resources
  • Prompt Templates: Reusable prompt templates for LLM interactions
  • 🔄 Full MCP Compatibility: Works with any existing MCP server or client

ETDI Security Enhancements

  • OAuth 2.0 Integration: Support for Auth0, Okta, Azure AD, and custom providers
  • Tool Verification: Cryptographic verification of tool authenticity
  • Permission Management: Fine-grained permission control with OAuth scopes
  • Version Control: Automatic detection of tool changes requiring re-approval
  • Approval Management: Encrypted storage of user tool approvals
  • Request Signing: RSA/ECDSA cryptographic signing for enhanced security
  • Security Inspector Tools: Built-in tools for security analysis and debugging

Security Features

  • Tool Poisoning Prevention: Cryptographic verification prevents malicious tool impersonation
  • Rug Pull Protection: Version and permission change detection prevents unauthorized modifications
  • Multiple Security Levels: Basic, Enhanced, and Strict security modes
  • Audit Logging: Comprehensive security event logging
  • Call Stack Verification: Prevents unauthorized nested tool calls
  • 🛡️ Non-Breaking Security: Security features don't break existing MCP workflows

Installation

pip install mcp[etdi]

For development:

pip install mcp[etdi,dev]

Quick Start

ETDI Client

import asyncio
from mcp.etdi import ETDIClient, OAuthConfig, SecurityLevel

async def main():
    # Configure OAuth provider
    oauth_config = OAuthConfig(
        provider="auth0",
        client_id="your-client-id",
        client_secret="your-client-secret",
        domain="your-domain.auth0.com",
        audience="https://your-api.example.com",
        scopes=["read:tools", "execute:tools"]
    )
    
    # Initialize ETDI client
    async with ETDIClient({
        "security_level": SecurityLevel.ENHANCED,
        "oauth_config": oauth_config.to_dict(),
        "allow_non_etdi_tools": True,
        "show_unverified_tools": False
    }) as client:
        
        # Connect to MCP servers
        await client.connect_to_server(["python", "-m", "my_server"], "my-server")
        
        # Discover and verify tools
        tools = await client.discover_tools()
        
        for tool in tools:
            if tool.verification_status.value == "verified":
                # Approve tool for usage
                await client.approve_tool(tool)
                
                # Invoke tool
                result = await client.invoke_tool(tool.id, {"param": "value"})
                print(f"Result: {result}")

asyncio.run(main())

ETDI Secure Server

import asyncio
from mcp.etdi.server import ETDISecureServer
from mcp.etdi import OAuthConfig

async def main():
    # Configure OAuth
    oauth_configs = [
        OAuthConfig(
            provider="auth0",
            client_id="your-client-id",
            client_secret="your-client-secret",
            domain="your-domain.auth0.com",
            audience="https://your-api.example.com",
            scopes=["read:tools", "execute:tools"]
        )
    ]
    
    # Create secure server
    server = ETDISecureServer(oauth_configs)
    
    # Register secure tool
    @server.secure_tool(permissions=["read:data", "write:data"])
    async def secure_calculator(operation: str, a: float, b: float) -> float:
        """A secure calculator with OAuth protection"""
        if operation == "add":
            return a + b
        elif operation == "multiply":
            return a * b
        else:
            raise ValueError(f"Unknown operation: {operation}")
    
    await server.initialize()
    print("Secure server running with OAuth protection")

asyncio.run(main())

OAuth Provider Configuration

Auth0

from mcp.etdi import OAuthConfig

auth0_config = OAuthConfig(
    provider="auth0",
    client_id="your-auth0-client-id",
    client_secret="your-auth0-client-secret",
    domain="your-domain.auth0.com",
    audience="https://your-api.example.com",
    scopes=["read:tools", "execute:tools"]
)

Okta

okta_config = OAuthConfig(
    provider="okta",
    client_id="your-okta-client-id",
    client_secret="your-okta-client-secret",
    domain="your-domain.okta.com",
    scopes=["etdi.tools.read", "etdi.tools.execute"]
)

Azure AD

azure_config = OAuthConfig(
    provider="azure",
    client_id="your-azure-client-id",
    client_secret="your-azure-client-secret",
    domain="your-tenant-id",
    scopes=["https://graph.microsoft.com/.default"]
)

Security Inspector Tools

ETDI includes built-in security analysis and debugging tools:

Security Analyzer

from mcp.etdi.inspector import SecurityAnalyzer

analyzer = SecurityAnalyzer()

# Analyze tool security
result = await analyzer.analyze_tool(tool_definition)
print(f"Security Score: {result.security_score}")
print(f"Vulnerabilities: {result.vulnerabilities}")

Token Debugger

from mcp.etdi.inspector import TokenDebugger

debugger = TokenDebugger()

# Debug JWT tokens
debug_info = await debugger.debug_token(jwt_token)
print(f"Token valid: {debug_info.valid}")
print(f"Claims: {debug_info.claims}")
print(f"Issues: {debug_info.issues}")

OAuth Validator

from mcp.etdi.inspector import OAuthValidator

validator = OAuthValidator()

# Validate OAuth configuration
result = await validator.validate_provider("auth0", oauth_config)
print(f"Configuration valid: {result.configuration_valid}")
print(f"Provider reachable: {result.is_reachable}")

CLI Tools

ETDI provides command-line tools for configuration and debugging:

# Initialize ETDI configuration
python -m mcp.etdi.cli init --provider auth0

# Validate OAuth configuration
python -m mcp.etdi.cli validate-oauth --config etdi-config.json

# Debug JWT tokens
python -m mcp.etdi.cli debug-token --token "eyJ..."

# Analyze tool security
python -m mcp.etdi.cli analyze-tool --tool-id "my-tool"

Security Levels

Basic

  • Simple cryptographic verification
  • No OAuth requirements
  • Suitable for development and testing

Enhanced (Recommended)

  • OAuth 2.0 token verification
  • Permission-based access control
  • Tool change detection
  • Suitable for production use

Strict

  • Full OAuth enforcement
  • Request signing required
  • No unverified tools allowed
  • Maximum security for sensitive environments

Architecture

Client-Side Components

  • ETDIClient: Main client interface with security verification
  • ETDIVerifier: OAuth token verification and change detection
  • ApprovalManager: Encrypted storage of user approvals
  • SecureSession: Enhanced MCP client session with security

Server-Side Components

  • ETDISecureServer: OAuth-protected MCP server
  • SecurityMiddleware: Security middleware for tool protection
  • TokenManager: OAuth token lifecycle management
  • ToolProvider: Secure tool registration and management

OAuth Providers

  • Auth0Provider: Auth0 integration with JWKS validation
  • OktaProvider: Okta integration with custom scopes
  • AzureADProvider: Azure AD integration with tenant support
  • OAuthManager: Multi-provider management and failover

Inspector Tools

  • SecurityAnalyzer: Tool security analysis and scoring
  • TokenDebugger: JWT token debugging and validation
  • OAuthValidator: OAuth configuration validation
  • CallStackVerifier: Call stack verification and analysis

Request Signing

ETDI supports cryptographic request signing with RSA-SHA256 signatures embedded directly in MCP protocol messages:

Client-Side Request Signing

from mcp.etdi.client import ETDIClient
from mcp.etdi.types import SecurityLevel

# Enable automatic request signing
client = ETDIClient(ETDIClientConfig(
    security_level=SecurityLevel.STRICT,
    enable_request_signing=True
))

await client.initialize()

# All tool invocations to tools requiring signatures will be automatically signed
result = await client.invoke_tool("secure-tool", {"data": "sensitive"})

Server-Side Request Verification

from mcp.server.fastmcp import FastMCP

app = FastMCP("Secure Server")

# Tool requiring cryptographic request signatures
@app.tool(
    etdi=True,
    etdi_require_request_signing=True,
    etdi_permissions=["banking:transfer"]
)
def transfer_funds(amount: float, to_account: str) -> str:
    """High-security tool requiring signed requests"""
    return f"Transferred ${amount} to {to_account}"

# Initialize request signing verification
app.initialize_request_signing()

How It Works

  1. Client generates RSA key pair automatically
  2. Signs tool invocation with private key
  3. Embeds signature in MCP request parameters (not transport headers)
  4. Server extracts signature from MCP request
  5. Verifies signature using client's public key
  6. Enforces in STRICT mode only

Protocol Integration

Request signing extends the MCP protocol itself using the extra="allow" feature:

# Standard MCP request
{
  "method": "tools/call",
  "params": {
    "name": "my_tool",
    "arguments": {"param": "value"}
  }
}

# ETDI signed request (backward compatible)
{
  "method": "tools/call",
  "params": {
    "name": "my_tool",
    "arguments": {"param": "value"},
    "etdi_signature": "base64-encoded-signature",
    "etdi_timestamp": "2024-01-01T12:00:00Z",
    "etdi_key_id": "client-key-id",
    "etdi_algorithm": "RS256"
  }
}

This approach ensures full compatibility with all MCP transports (stdio, websocket, SSE) without requiring transport-layer modifications.

Examples

See the examples/etdi/ directory for comprehensive examples:

  • basic_usage.py: Basic ETDI client usage
  • oauth_providers.py: OAuth provider configurations
  • secure_server_example.py: Secure server implementation
  • inspector_example.py: Security analysis tools
  • call_stack_example.py: Call stack verification
  • caller_callee_authorization_example.py: Authorization between tools
  • protocol_call_stack_example.py: Protocol-level call stack analysis
  • e2e_secure_client.py: End-to-end secure client
  • e2e_secure_server.py: End-to-end secure server
  • comprehensive_request_signing_example.py: Complete request signing demo
  • request_signing_example.py: Request signing implementation details
  • request_signing_server_example.py: Server-side request verification
  • clean_api_example.py: Clean API usage patterns
  • test_complete_security.py: Complete security testing

Testing

Run the test suite:

pytest tests/etdi/

Run with coverage:

pytest tests/etdi/ --cov=src/mcp/etdi --cov-report=html

Run specific test categories:

# OAuth provider tests
pytest tests/etdi/test_oauth_providers.py

# Security inspector tests
pytest tests/etdi/test_inspector.py

# Integration tests
pytest tests/etdi/test_integration.py

# Request signing tests
pytest tests/etdi/test_request_signing.py

# Request signing fix tests (protocol extension)
pytest tests/etdi/test_request_signing_fix.py

# ETDI client tests
pytest tests/etdi/test_etdi_client.py

# ETDI implementation tests
pytest tests/etdi/test_etdi_implementation.py

# ETDI-only functionality tests
pytest tests/etdi/test_etdi_only.py

Deployment

Docker Deployment

# Build ETDI-enabled container
docker build -f deployment/docker/Dockerfile -t my-etdi-server .

# Run with configuration
docker run -v $(pwd)/deployment/config:/config my-etdi-server

Docker Compose

# Start complete ETDI environment
docker-compose -f deployment/docker/docker-compose.yml up

Security Considerations

Tool Verification

  • Always verify tools before approval
  • Monitor for version and permission changes
  • Use appropriate security levels for your environment
  • Implement proper call stack depth limits

OAuth Configuration

  • Store OAuth credentials securely
  • Use appropriate scopes for your tools
  • Implement proper token rotation
  • Validate OAuth provider configurations

Permission Management

  • Follow principle of least privilege
  • Regularly audit tool permissions
  • Monitor approval and usage patterns
  • Use fine-grained permission scopes

Request Signing

  • Use strong cryptographic algorithms (RS256, ES256)
  • Implement proper key rotation
  • Validate signatures on all requests
  • Monitor for signature validation failures

Troubleshooting

Common Issues

  1. OAuth Token Validation Failures

    python -m mcp.etdi.cli debug-token --token "your-token"
    
  2. Provider Configuration Issues

    python -m mcp.etdi.cli validate-oauth --config etdi-config.json
    
  3. Tool Security Analysis

    python -m mcp.etdi.cli analyze-tool --tool-id "problematic-tool"
    

Debug Mode

Enable debug logging for detailed troubleshooting:

import logging
logging.getLogger('mcp.etdi').setLevel(logging.DEBUG)

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
  6. Submit a pull request

License

MIT License - see LICENSE file for details.

Documentation

Support

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

mcp_etdi-1.0.0.tar.gz (397.3 kB view details)

Uploaded Source

Built Distribution

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

mcp_etdi-1.0.0-py3-none-any.whl (216.2 kB view details)

Uploaded Python 3

File details

Details for the file mcp_etdi-1.0.0.tar.gz.

File metadata

  • Download URL: mcp_etdi-1.0.0.tar.gz
  • Upload date:
  • Size: 397.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.6

File hashes

Hashes for mcp_etdi-1.0.0.tar.gz
Algorithm Hash digest
SHA256 26fa4945b68acb91fa7f562388bf3ef1391e61648d118954935660397b2841de
MD5 b80cbef44f0152bd6f272089dbafdafc
BLAKE2b-256 47b92993aafb33a1b9fb6925c8616869d17c78fd1b4d49edfa5ca53fddf862d4

See more details on using hashes here.

File details

Details for the file mcp_etdi-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_etdi-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 216.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.6

File hashes

Hashes for mcp_etdi-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43284913a10503511fe28baec295d9487527ad9c25ccde2094c4471a17250d27
MD5 36d831957894df432e33825a202dbec7
BLAKE2b-256 a6d04e7dddcc8c3426794c5a3e5a9b7e3e12e249d1a98c1f1beec3f836a97500

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