secure-actions
An MCP server that lets Claude, Claude Code, and other AI agents call authenticated APIs — without exposing raw API tokens, keys, or credentials to the LLM.
The Problem
When an AI agent needs to call an authenticated API, most MCP setups put the secret directly in the client configuration:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_actual_secret_value_here"
}
}
}
}
This means the raw credential lives in mcp.json, .claude.json, or shell environment — visible to the agent's configuration layer, potentially logged, and exposed if the configuration is shared or leaked.
The secure-actions Approach
secure-actions keeps credentials inside a trusted execution boundary. The AI agent references a secret by name using a placeholder (<<secret:github-pat>>). The actual credential is resolved, decrypted, and injected at request time — inside the MCP server process — and never returned to the model's context.
flowchart LR
A[Claude / AI Agent] -->|"Action request with placeholder"| B[secure-actions MCP Server]
B -->|Resolve secret internally| C[Encrypted Secret Store]
B -->|Authenticated request| D[External API]
C -.->|"Credential never returned to model"| B
The agent sees <<secret:github-pat>> in tool inputs and outputs. The decrypted token value exists only transiently during HTTP request execution or MCP tool forwarding, and is never logged or included in responses.
How It Works
-
Store a secret — The MCP client (e.g., Claude Code) presents a secure input form via MCP elicitation. The user enters the credential directly. The value is encrypted with AES-256-GCM and stored in MongoDB. The LLM never sees it.
-
Use a secret in HTTP requests — The agent calls
http_requestwith placeholders likeAuthorization: Bearer <<secret:github-pat>>. secure-actions decrypts and injects the credential at request time. -
Use a secret to call other MCP tools — The agent calls
mcp_tool_requestto invoke any MCP server, with secrets injected into the spawned process environment. This lets you securely use tools like@modelcontextprotocol/server-githubwithout putting tokens in your MCP configuration files. -
Manage secrets — List stored identifiers (values are never exposed), delete secrets with confirmation prompts.
Quick Start
Prerequisites
- Docker (for MongoDB)
- macOS, Linux, or Windows
Install
curl -sSL https://raw.githubusercontent.com/Kota-Karthik/secure-actions/main/scripts/install.sh | sh
Or install from source:
go install github.com/kotakarthik/secure-actions/cmd/secure-actions@latest
Start MongoDB
docker compose -f deployments/docker-compose.yml up -d
Register in Claude Code
Add to your MCP configuration (.claude.json, project settings, or Claude Code UI):
{
"mcpServers": {
"secure-actions": {
"type": "stdio",
"command": "secure-actions",
"env": {
"MONGO_URI": "mongodb://localhost:27018"
}
}
}
}
On first run, secure-actions automatically generates a master encryption key at ~/.secure-actions/master.key and creates the required database collections.
MCP Tools
request_secret
Securely collect and store a secret from the user via an interactive form (MCP elicitation). The secret value is encrypted before storage and never enters the LLM context.
If the identifier already exists, the user is prompted to confirm before updating.
http_request
Execute an authenticated HTTP request with automatic secret injection.
Example — call the GitHub API without exposing your token:
{
"method": "GET",
"url": "https://api.github.com/user/repos",
"headers": {
"Authorization": "Bearer <<secret:github-pat>>",
"Accept": "application/vnd.github+json"
}
}
mcp_tool_request
Call any MCP tool on a remote MCP server with secret injection into the spawned process environment. This is a universal MCP-to-MCP gateway — secure-actions acts as a proxy that injects credentials without exposing them in configuration files.
Example — create a GitHub issue via @modelcontextprotocol/server-github without tokens in your config:
{
"mcpConfig": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<<secret:github-pat>>"
}
},
"tool": "create_issue",
"parameters": {
"owner": "my-org",
"repo": "my-repo",
"title": "Bug: login page broken",
"body": "Steps to reproduce..."
}
}
Features: connection pooling (reuses MCP processes), automatic retries on transient errors, idle timeout eviction.
list_secrets
Returns all stored secret identifiers and count. Never exposes actual secret values.
delete_secret
Permanently delete a stored secret. Requires explicit user confirmation via MCP elicitation before deletion.
ping
Health check — returns pong to verify the server is running.
Usage Examples
Store and use a GitHub token
You: "Store my GitHub personal access token"
→ secure-actions shows a secure input form (MCP elicitation)
→ You enter the token — it's encrypted, never seen by the LLM
You: "List my repos"
→ http_request: GET https://api.github.com/user/repos
Authorization: Bearer <<secret:github-pat>>
→ The actual token is injected server-side, invisible to the model
Use MCP tools without tokens in configuration
You: "Create an issue in my repo via GitHub MCP"
→ mcp_tool_request spawns the GitHub MCP server
with GITHUB_PERSONAL_ACCESS_TOKEN=<<secret:github-pat>>
→ The PAT is decrypted and injected into the process environment
→ The LLM never sees the credential value
Manage stored secrets
You: "What secrets do I have?"
→ list_secrets: ["github-pat", "slack-webhook", "openai-key"]
You: "Remove the slack webhook"
→ delete_secret prompts: "Are you sure?" → confirmed → deleted
Security Model
What secure-actions protects against
- Credentials in LLM context — Secrets are collected via MCP elicitation (client-side form), not chat messages. Values never appear in tool responses.
- Credentials in configuration files — Instead of
"GITHUB_TOKEN": "ghp_abc123"inmcp.jsonor.claude.json, you use<<secret:github-pat>>and secure-actions resolves it at runtime. - Credentials in logs — Only identifiers are logged, never plaintext values.
- Credentials at rest — Stored encrypted with AES-256-GCM. A per-installation 256-bit random master key is auto-generated at
~/.secure-actions/master.key(file permissions0600).
Trust boundary
The credential exists in plaintext only:
- When the user types it into the MCP elicitation form (client-side)
- Transiently in the secure-actions process memory during request execution
Limitations
- Not a vault — The master key is a local file. Anyone with access to the machine can decrypt stored secrets. This protects against LLM-context exposure, not against a compromised host.
- Transport — MCP stdio transport is local IPC. Credentials pass through local pipes, not network.
- Model behavior — If the model asks the user to paste a secret directly in chat instead of using
request_secret, that bypasses the protection. The security depends on using the tools correctly. - Response content — If an API returns the credential in its response body (unlikely but possible), that response will be visible to the model.
Configuration
All data (MongoDB, master key, encrypted secrets) lives entirely on your local machine. No data leaves your system unless you explicitly make an HTTP request with http_request or mcp_tool_request.
Project Structure
cmd/secure-actions/ Entry point
internal/
actions/
ping/ Health check tool
request_secret/ Secret collection via MCP elicitation
list_secrets/ List stored identifiers
delete_secret/ Delete with confirmation
http_request/ HTTP client with secret injection
mcp_tool_request/ MCP-to-MCP gateway with secret injection and pooling
app/ Application wiring
config/ Configuration loading
elicit/ MCP elicitation interface
mcp/ MCP server and tool registration
mcp_config/ MCP server config types
secrets/ AES-256-GCM encryption, master key management
storage/mongo/ MongoDB client and secret repository
deployments/
docker-compose.yml Local MongoDB setup
Dockerfile Container build
scripts/
install.sh macOS/Linux installer
Development
# Start MongoDB
docker compose -f deployments/docker-compose.yml up -d
# Run from source
go run ./cmd/secure-actions
# Build binary
go build -o secure-actions ./cmd/secure-actions
# Run tests
go test ./internal/...
Releasing
Releases are automated via GitHub Actions and GoReleaser. Tag and push to create a release with binaries for all platforms (linux/darwin/windows, amd64/arm64):
git tag v0.1.0
git push origin v0.1.0
Comparison: Traditional MCP vs secure-actions
License
Apache License 2.0 — see LICENSE.