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

    authIssues and PRs related to Authentication / OAuthenhancementRequest for a new feature that's not currently supported

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions