Skip to content

04 - Tool Secrets

Read secrets from environment and .env files securely via Context.

Running the Example

  • Run: uv run 04_secrets.py
  • Run (stdio): uv run 04_secrets.py stdio
  • Create .env: Add API_KEY=supersecret to a .env file

Source Code

#!/usr/bin/env python3
"""04: Read secrets from .env via Context

Run:
  uv run 04_secrets.py           # HTTP transport (default)
  uv run 04_secrets.py stdio     # stdio transport for Claude Desktop

Environment:
  # Create a .env in the working directory with:
  #   API_KEY=supersecret
"""

import sys

from arcade_mcp_server import Context, MCPApp

# Create the MCP application
app = MCPApp(
    name="secrets_example",
    version="1.0.0",
    instructions="Example server demonstrating secrets usage",
)


@app.tool(
    requires_secrets=["API_KEY"],  # declare we need API_KEY
)
def use_secret(context: Context) -> str:
    """Read API_KEY from context and return a masked confirmation string."""
    try:
        value = context.get_secret("API_KEY")
        masked = value[:2] + "***" if len(value) >= 2 else "***"
        return f"Got API_KEY of length {len(value)} -> {masked}"
    except Exception as e:
        return f"Error getting secret: {e}"


if __name__ == "__main__":
    # Check if stdio transport was requested
    transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http"

    print(f"Starting {app.name} v{app.version}")
    print(f"Transport: {transport}")

    # Run the server
    app.run(transport=transport, host="127.0.0.1", port=8000)

Working with Secrets

1. Environment Variables

Secrets can be provided via environment variables:

export API_KEY="your-secret-key"
export DATABASE_URL="postgresql://localhost/mydb"

2. Using .env Files

Create a .env file in the directoryof your server:

API_KEY=supersecret
DATABASE_URL=postgresql://user:pass@localhost/db
GITHUB_TOKEN=ghp_xxxxxxxxxxxx

3. Declaring Required Secrets

Use the requires_secrets parameter to declare which secrets your tool needs:

@tool(requires_secrets=["API_KEY", "DATABASE_URL"])
def my_secure_tool(context: Context) -> str:
    api_key = context.get_secret("API_KEY")
    db_url = context.get_secret("DATABASE_URL")

4. Security Best Practices

  • Never log secret values: Always mask or truncate when displaying
  • Declare requirements: Use requires_secrets to document dependencies
  • Handle missing secrets: Use try/except when accessing secrets
  • Use descriptive names: Make it clear what each secret is for

Key Concepts

  • Secure Access: Secrets are accessed through context, not imported directly
  • Environment Integration: Works with both environment variables and .env files
  • Error Handling: Always handle the case where a secret might be missing
  • Masking: Never expose full secret values in logs or return values
  • Declaration: Use requires_secrets to make dependencies explicit