Skip to content

Feature Proposal: Secure Tool/Resource/Prompt Decorators with Auth + Encrypted I/OΒ #1305

@wenhuizhang

Description

@wenhuizhang

Description

πŸš€ Feature Request

I would like to propose adding a secure wrapper layer to @mcp.tool, @mcp.resource, and @mcp.prompt that supports:

  1. Authentication (Auth)

Ability to pass an auth function (e.g. verify_identity()) that can validate JWT, Certs, or TEE Attestation before executing the function.

Authentication should be bidirectional - we need to verify both:

  1. Client authentication - Is the client authorized to use the tool?
  2. Tool/Server authentication - Is the tool legitimate and trustworthy?

If authentication fails, return a proper MCP Error (e.g. 403 Forbidden).

  1. Key Negotiation Mechanism

Client provides a public key (PK) or session token.

Server performs Diffie-Hellman (ECDH) or TLS/mTLS handshake to derive a session key.

Session key is stored in context and used for symmetric encryption/decryption of I/O.

  1. Unified Secure Interface

Developers could write secure MCP functions like this:

@mcp.secure_tool(auth=verify_identity, encrypt=True)
async def trade(symbol: str, amount: float) -> str:
    return f"Trade {amount} {symbol} executed"

And the same approach could apply to resource and prompt.

πŸ”Ή Example Implementation

import functools
from mcp.server.fastmcp import FastMCP, tool, resource, prompt
from mcp.server.models import Error
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os, base64

mcp = FastMCP("SecureApp")

# ========== Simple Key Management ==========
SESSION_KEY = AESGCM.generate_key(bit_length=128)
aesgcm = AESGCM(SESSION_KEY)
NONCE_SIZE = 12

def encrypt(data: str) -> str:
    nonce = os.urandom(NONCE_SIZE)
    ct = aesgcm.encrypt(nonce, data.encode(), None)
    return base64.b64encode(nonce + ct).decode()

def decrypt(token: str) -> str:
    raw = base64.b64decode(token)
    nonce, ct = raw[:NONCE_SIZE], raw[NONCE_SIZE:]
    pt = aesgcm.decrypt(nonce, ct, None)
    return pt.decode()

# ========== Auth Function ==========
def verify_identity() -> bool:
    # TODO: implement JWT / CERT / Attestation validation
    return True

# ========== Decorator Factory ==========
def secure_wrapper(deco, auth=None, encrypt_io=False, *args, **kwargs):
    def decorator(func):
        @deco(*args, **kwargs)   # wrap original MCP decorator
        @functools.wraps(func)
        async def wrapper(*f_args, **f_kwargs):
            # Auth check
            if auth and not auth():
                raise Error(code=403, message="Authentication failed")

            # Decrypt inputs
            if encrypt_io:
                f_kwargs = {k: decrypt(v) if isinstance(v, str) else v 
                            for k, v in f_kwargs.items()}

            # Execute
            result = await func(*f_args, **f_kwargs) if callable(func) else func

            # Encrypt outputs
            if encrypt_io and isinstance(result, str):
                result = encrypt(result)

            return result
        return wrapper
    return decorator

# Three secure variants
def secure_tool(auth=None, encrypt_io=False, *args, **kwargs):
    return secure_wrapper(tool, auth, encrypt_io, *args, **kwargs)

def secure_resource(auth=None, encrypt_io=False, *args, **kwargs):
    return secure_wrapper(resource, auth, encrypt_io, *args, **kwargs)

def secure_prompt(auth=None, encrypt_io=False, *args, **kwargs):
    return secure_wrapper(prompt, auth, encrypt_io, *args, **kwargs)

# ========== Usage Example ==========
@secure_tool(auth=verify_identity, encrypt_io=True)
async def add(a: int, b: int) -> str:
    return f"sum={a+b}"

@secure_resource("secure://greet/{name}", auth=verify_identity, encrypt_io=True)
def greeting(name: str) -> str:
    return f"Hello, {name}!"

@secure_prompt(auth=verify_identity, encrypt_io=True)
def greet_user(name: str) -> str:
    return f"Write a secure greeting for {name}"

πŸ”Ή Encrypted I/O Flow

Input: client encrypts arguments with session key β†’ sends

Server: decrypts args β†’ executes function

Output: result encrypted β†’ returned to client

Client: decrypts result with the same session key

βœ… Summary

tool, resource, and prompt can all uniformly support auth + encrypted I/O.

Implemented via decorator factory pattern, keeping code clean.

Supports pluggable JWT, Cert, TEE Attestation validation.

Session key negotiation can use TLS/mTLS or ECDH.

This would make MCP safer to use in environments where sensitive data and secure tool execution are required.

References

MR #1309

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions