Skip to Content
HomeBuild toolsCreate a tool with secrets

Create an MCP tool with secrets

Outcomes

Build an tool that can read a secret from and return a masked confirmation string. Jump to Example Code to see the complete code.

You will Learn

  • How to read secrets from environment and .env files securely using a tool’s .
  • How to configure secrets in the Arcade Dashboard.

Secrets are sensitive strings like passwords, , or other tokens that grant access to a protected resource or API. You can also use secrets to provide other static configuration values your needs, such as parameters for calling a remote API.

Why use secrets in your tools?

Secrets enable you to securely deploy a function that requires sensitive information at runtime. And while these can be consumed directly from the runtime environment inside your function, this becomes very inconvenient, expensive, hard to maintain, and insecure when deploying at scale.

For example, if your tool requires an to use an external service, but only after doing some computationally expensive work, you need to ensure that the API key is present before the computationally expensive work is done. The function below would fail if the API key is not present.

Python
import os def my_tool(task: str) -> str: result = expensive_computation(task) API_KEY = os.getenv("API_KEY") # The line below will fail if the API key is not present success = upload_result_to_service(result, API_KEY) if success: return "Result uploaded successfully" else: return "Failed to upload result"

We can work around this by carefully checking for the before doing the computationally expensive work, of course, but this is error prone and difficult to maintain, and you may only become aware of the issue after deploying multiple instances of your server.

Arcade provides a way to securely store and access secrets inside your tools in a way that is easy to manage across multiple instances of your servers, and that will prevent the from running if the secret is not provided. In this guide, you’ll learn how to use secrets in your custom Arcade tools.

Store your secret

Depending on where you’re running your server, you can store your secret in a few different ways.

You can create a .env file in the same directory as your (typically server.py by default) and add your secret:

ENV
.env
MY_SECRET_KEY="my-secret-value"

The includes a .env.example file with the secret key name and example value. You can rename it to .env to start using it.

Terminal
mv .env.example .env

Using a .env file is okay for local development, but you should use the Arcade Dashboard or Arcade CLI for production deployments.

Using secrets with stdio transport

When using the stdio transport, clients typically launch the as a subprocess. Because of this, the server may run in a different environment and not have access to secrets defined in your local .env file or your terminal environment variables.

To ensure your stdio server has access to the secrets, you can either

  1. Utilize the arcade configure CLI command to configure your client to pass the secrets to your , or

  2. Manually configure your client to pass the secrets to your . For example, if you are using Cursor IDE, you can add the following to your mcp.json file:

    JSON
    { "mcpServers": { "simple": { "command": "uv", "args": [ "run", "--directory", "/absoulute/path/to/your/entrypoint/file/parent/directory", "python", "server.py" ], "env": { "MY_SECRET_KEY": "my-secret-value" } } } }

This will make the secret available to your server when the MCP client starts the subprocess. Note that the specific key name may vary depending on the MCP client you are using.

Define your tool and access the secret

This is only an illustrative example of how Arcade will ensure that the secret is present before the tool is executed. In a real world application, you would use this secret to store sensitive information like , database credentials, etc, and not to simply print a confirmation string.

In your MCP Server, create a new that uses the secret:

  • Use the requires_secrets parameter to declare which secrets your needs ("SECRET_KEY" in this example).
  • The tool’s object has a get_secret method that you can use to access the secret value.
Python
secrets.py
@app.tool( requires_secrets=["SECRET_KEY"], # declare we need SECRET_KEY ) def use_secret(context: Context) -> str: """Read SECRET_KEY from context and return a masked confirmation string.""" try: value = context.get_secret("SECRET_KEY") masked = value[:2] + "***" if len(value) >= 2 else "***" return f"Got SECRET_KEY of length {len(value)} -> {masked}" except ValueError as e: return f"Error getting secret: {e}"

When your is executed, it will return: "Got SECRET_KEY of length...". In a real world application, you would use this secret to connect to a remote database, API, etc.

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 , 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

Example Code

Environment Variables

ENV
.env
SECRET_KEY="supersecret"

For the code to work, you must define your environment variables locally or in a .env file.

Python
secrets.py
#!/usr/bin/env python3 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=["SECRET_KEY"], # declare we need SECRET_KEY ) def use_secret(context: Context) -> str: """Read SECRET_KEY from context and return a masked confirmation string.""" try: value = context.get_secret("SECRET_KEY") masked = value[:2] + "***" if len(value) >= 2 else "***" return f"Got SECRET_KEY of length {len(value)} -> {masked}" except ValueError as e: return f"Error getting secret: {e}" if __name__ == "__main__": # Get transport from command line argument, default to "stdio" transport = sys.argv[1] if len(sys.argv) > 1 else "stdio" # Run the server app.run(transport=transport, host="127.0.0.1", port=8000)

Run your MCP server

Terminal
uv run secrets.py stdio
Last updated on

Create an MCP tool with secrets | Arcade Docs