Janee π
Secrets management for AI agents via MCP
Your AI agents need API access to be useful. But they shouldn't have your raw API keys.Janee sits between your agents and your APIs β injecting credentials, enforcing policies, and logging everything.
β¨ Features
| π Zero-knowledge agents | Agents call APIs without ever seeing keys |
| π Full audit trail | Every request logged with timestamp, method, path, status |
| π‘οΈ Request policies | Allow/deny rules per capability (e.g., read-only Stripe) |
| β±οΈ Session TTLs | Time-limited access with instant revocation |
| π Works with any MCP client | Claude Desktop, Cursor, OpenClaw, and more |
| π Local-first | Keys encrypted on your machine, never sent to a cloud |
The Problem
AI agents need API access to be useful. The current approach is to give them your keys and hope they behave.
- π Agents have full access to Stripe, Gmail, databases
- π No audit trail of what was accessed or why
- π« No kill switch when things go wrong
- π One prompt injection away from disaster
The Solution
Janee is an MCP server that manages API secrets for AI agents:
- Store your API keys β encrypted locally in
~/.janee/ - Run
janee serveβ starts MCP server - Agent requests access β via
executeMCP tool - Janee injects the real key β agent never sees it
- Everything is logged β full audit trail
Your keys stay on your machine. Agents never see them. You stay in control.
Configure Once, Use Everywhere
Set up your APIs in Janee once:
services:
stripe:
baseUrl: https://api.stripe.com
auth: { type: bearer, key: sk_live_xxx }
github:
baseUrl: https://api.github.com
auth: { type: bearer, key: ghp_xxx }
openai:
baseUrl: https://api.openai.com
auth: { type: bearer, key: sk-xxx }
Now every agent that connects to Janee can use them:
- Claude Desktop β access your APIs
- Cursor β access your APIs
- OpenClaw β access your APIs
- Any MCP client β access your APIs
No more copying keys between tools. No more "which agent has which API configured?" Add a new agent? It already has access to everything. Revoke a key? Update it once in Janee.
One config. Every agent. Full audit trail.
Quick Start
Install
npm install -g @true-and-useful/janee
Initialize
janee init
This creates ~/.janee/config.yaml with example services.
Add Services
Option 1: Interactive (recommended for first-time users)
janee add
Janee will guide you through adding a service:
Service name: stripe
Base URL: https://api.stripe.com
Auth type: bearer
API key: sk_live_xxx
β Added service "stripe"
Create a capability for this service? (Y/n): y
Capability name (default: stripe):
TTL (e.g., 1h, 30m): 1h
Auto-approve? (Y/n): y
β Added capability "stripe"
Done! Run 'janee serve' to start.
Using an AI agent? See Non-interactive Setup for flags that skip prompts, or the agent-specific guides below.
Option 2: Edit config directly
Edit ~/.janee/config.yaml:
services:
stripe:
baseUrl: https://api.stripe.com
auth:
type: bearer
key: sk_live_xxx
capabilities:
stripe:
service: stripe
ttl: 1h
autoApprove: true
Start the MCP server
janee serve
Use with your agent
Agents that support MCP (Claude Desktop, Cursor, OpenClaw) can now call the execute tool to make API requests through Janee:
// Agent calls the execute tool
execute({
capability: "stripe",
method: "GET",
path: "/v1/balance",
reason: "User asked for account balance"
})
Janee decrypts the key, makes the request, logs everything, and returns the response.
Integrations
Works with any agent that speaks MCP:
- OpenClaw β Native plugin (
@true-and-useful/janee-openclaw)- Containerized agents? See Container setup guide
- Cursor β Setup guide
- Claude Code β Setup guide
- Codex CLI β Setup guide
- Any MCP client β just point at
janee serve
OpenClaw Integration
If you're using OpenClaw, install the plugin for native tool support:
npm install -g @true-and-useful/janee
janee init
# Edit ~/.janee/config.yaml with your services
# Install the OpenClaw plugin
openclaw plugins install @true-and-useful/janee-openclaw
Enable in your agent config:
{
agents: {
list: [{
id: "main",
tools: { allow: ["janee"] }
}]
}
}
Your agent now has these tools:
janee_list_servicesβ Discover available APIsjanee_executeβ Make API requests through Janee
The plugin spawns janee serve automatically. All requests are logged to ~/.janee/logs/.
MCP Tools
Janee exposes three MCP tools:
| Tool | Description |
|---|---|
list_services |
Discover available APIs and their policies |
execute |
Make an API request through Janee |
reload_config |
Reload config from disk after adding/removing services (available when started with janee serve) |
Agents discover what's available, then call APIs through Janee. Same audit trail, same protection.
Configuration
Config lives in ~/.janee/config.yaml:
server:
host: localhost
services:
stripe:
baseUrl: https://api.stripe.com
auth:
type: bearer
key: sk_live_xxx # encrypted at rest
github:
baseUrl: https://api.github.com
auth:
type: bearer
key: ghp_xxx
capabilities:
stripe:
service: stripe
ttl: 1h
autoApprove: true
stripe_sensitive:
service: stripe
ttl: 5m
requiresReason: true
Services = Real APIs with real keys Capabilities = What agents can request, with policies
Request Policies
Control exactly what requests each capability can make using rules:
capabilities:
stripe_readonly:
service: stripe
ttl: 1h
rules:
allow:
- GET *
deny:
- POST *
- PUT *
- DELETE *
stripe_billing:
service: stripe
ttl: 15m
requiresReason: true
rules:
allow:
- GET *
- POST /v1/refunds/*
- POST /v1/invoices/*
deny:
- POST /v1/charges/* # Can't charge cards
- DELETE *
How rules work:
denypatterns are checked first β explicit deny always wins- Then
allowpatterns are checked β must match to proceed - No rules defined β allow all (backward compatible)
- Rules defined but no match β denied by default
Pattern format: METHOD PATH
GET *β any GET requestPOST /v1/charges/*β POST to /v1/charges/ and subpaths* /v1/customersβ any method to /v1/customersDELETE /v1/customers/*β DELETE any customer
This makes security real: Even if an agent lies about its "reason", it can only access the endpoints the policy allows. Enforcement happens server-side.
CLI Reference
janee init # Set up ~/.janee/ with example config
janee add # Add a service (interactive)
janee add stripe -u https://api.stripe.com -k sk_xxx # Add with args
janee remove <service> # Remove a service
janee remove <service> --yes # Remove without confirmation
janee list # List configured services
janee list --json # Output as JSON (for integrations)
janee search [query] # Search service directory
janee search stripe --json # Search with JSON output
janee cap list # List capabilities
janee cap list --json # List capabilities as JSON
janee cap add <name> --service <service> # Add capability
janee cap edit <name> # Edit capability
janee cap remove <name> # Remove capability
janee serve # Start MCP server (stdio, default)
janee serve --transport http --port 9100 # Start with HTTP transport (for containers)
janee logs # View audit log
janee logs -f # Tail audit log
janee logs --json # Output as JSON
janee sessions # List active sessions
janee sessions --json # Output as JSON
janee revoke <id> # Kill a session
Non-interactive Setup (for AI agents)
AI agents can't respond to interactive prompts. Use --*-from-env flags to read credentials from environment variables β this keeps secrets out of the agent's context window:
# Bearer auth (Stripe, OpenAI, etc.)
janee add stripe -u https://api.stripe.com --auth-type bearer --key-from-env STRIPE_KEY
# HMAC auth (Bybit)
janee add bybit --auth-type hmac-bybit --key-from-env BYBIT_KEY --secret-from-env BYBIT_SECRET
# HMAC auth with passphrase (OKX)
janee add okx --auth-type hmac-okx --key-from-env OKX_KEY --secret-from-env OKX_SECRET --passphrase-from-env OKX_PASS
When all required credentials are provided via flags, Janee:
- Never opens readline (no hanging on stdin)
- Auto-creates a capability with sensible defaults (1h TTL, auto-approve)
You can also edit ~/.janee/config.yaml directly if you prefer.
How It Works
βββββββββββββββ ββββββββββββ βββββββββββ
β AI Agent βββββββΆβ Janee βββββββΆβ Stripe β
β β MCP β MCP β HTTP β API β
βββββββββββββββ ββββββββββββ βββββββββββ
β β
No key Injects key
+ logs request
- Agent calls
executeMCP tool with capability, method, path - Janee looks up service config, decrypts the real key
- Makes HTTP request to real API with key
- Logs: timestamp, service, method, path, status
- Returns response to agent
Agent never touches the real key.
Security
- Encryption: Keys stored with AES-256-GCM
- Local only: MCP server over stdio (no network exposure)
- Audit log: Every request logged to
~/.janee/logs/ - Sessions: Time-limited, revocable
- Kill switch:
janee revokeor delete config
Docker
Run Janee as a container β no local Node.js required:
# Build
docker build -t janee .
# Run in HTTP mode
docker run -d -p 3000:3000 \
-v ~/.janee:/root/.janee:ro \
janee --transport http --port 3000 --host 0.0.0.0
Or use Docker Compose:
mkdir -p config && cp ~/.janee/config.yaml config/
docker compose up -d
For Claude Desktop with Docker, see Docker docs.
Contributing
We welcome contributions! Please read CONTRIBUTING.md before submitting a PR β it includes the required PR checklist (tests, changelog, version bump, etc.).
License
MIT β Built by True and Useful LLC
Stop giving AI agents your keys. Start controlling access. π