@wyattjoh/op-remote
v0.5.3
Published
CLI and MCP server for remote 1Password secret access with Telegram-based approval. Designed for AI agents (Claude Code, etc.) that need secrets at runtime without exposing them in plaintext config files or conversation context.
Readme
@wyattjoh/op-remote
CLI and MCP server for remote 1Password secret access with Telegram-based approval. Designed for AI agents (Claude Code, etc.) that need secrets at runtime without exposing them in plaintext config files or conversation context.
How it works
- At startup, the MCP server (
op-remote serve --env-file=.env.tpl) reads the project's.env.tpland usesop runto resolve everyop://reference into its own process environment. This happens once, while the user is present to authenticate with 1Password. No.env.tplmeans no secrets are loaded and the pipeline is inert, so each project that needs remote secret access must provide one. - The server exposes a
request_tokenMCP tool that returns a one-time token and Unix socket path. - The CLI (
op-remote run) is called by the agent with the token, the same.env.tpl, and the command to run. It connects to the MCP server's Unix socket to request the secrets named in the file. - The MCP server sends a Telegram approval request with inline buttons (Approve, Reject, Auto-Approve, Stop). The approver can also reply with a reason when rejecting.
- On approval, secrets are injected into the subprocess environment. All stdout/stderr output is masked to prevent secret leakage.
Install
Claude Code Plugin (Recommended)
Install via the plugin marketplace:
/plugin marketplace add wyattjoh/claude-code-marketplace
/plugin install op-remote@wyattjoh-marketplaceThen configure the Telegram credentials via the plugin's user config. The
plugin's MCP config is pre-wired with --env-file=.env.tpl, so each project
that uses op-remote only needs a .env.tpl at its root listing the project's
op:// secret references (see Project .env.tpl
below).
npm (global)
npm install -g @wyattjoh/op-remoteOr with Bun:
bun install -g @wyattjoh/op-remoteConfiguration
Environment variables
| Variable | Required | Description |
| --------------------------------- | -------- | -------------------------------------------------------------------------------- |
| REMOTE_OP_TELEGRAM_BOT_TOKEN | Yes | Telegram bot token for sending approval requests |
| REMOTE_OP_TELEGRAM_CHAT_ID | Yes | Telegram chat ID to send approval messages to |
| REMOTE_OP_TELEGRAM_APPROVER_IDS | No | Comma-separated Telegram user IDs allowed to approve/reject (all users if unset) |
| REMOTE_OP_TIMEOUT | No | Approval timeout in seconds (default: 120) |
When installed as the Claude Code plugin, the Telegram variables above are supplied via the plugin's user config and do not need to be set manually.
Project .env.tpl (required)
Every project that wants remote secret access must have a .env.tpl file at
its root. The plugin's MCP config passes --env-file=.env.tpl to
op-remote serve, so at server startup the file is read and all op://
references are resolved via op run into the server's process environment.
The resolved secrets are what later requests from op-remote run draw from.
# Plain values are passed through directly
DATABASE_HOST=localhost
DATABASE_PORT=5432
# op:// references are resolved once at server startup
DATABASE_PASSWORD=op://Development/my-app-db/password
API_KEY=op://Development/my-app-api/credentialThe same file format is consumed in two places:
- MCP server startup reads it to resolve
op://references up front (requires an interactiveopsession, so this happens while the user is present). op-remote runreads it to know which variable names to request from the server and which plain values to pass through directly.
Lines with op:// values become secret requests. All other key-value pairs
are injected as plain environment variables. Comments and blank lines are
ignored. If .env.tpl is missing, the server starts normally but has no
secrets to serve, so no op-remote run invocation will succeed.
MCP client configuration
If you are not using the Claude Code plugin, add the server to your
.mcp.json or ~/.claude/.mcp.json. Pass --env-file=.env.tpl so the server
loads the project's secrets at startup:
{
"mcpServers": {
"op-remote": {
"command": "op-remote",
"args": ["serve", "--env-file=.env.tpl"],
"env": {
"REMOTE_OP_TELEGRAM_BOT_TOKEN": "your-bot-token",
"REMOTE_OP_TELEGRAM_CHAT_ID": "your-chat-id"
}
}
}
}The server will shell out to op run --env-file=.env.tpl internally to
resolve the project's op:// references, so op must be installed and
authenticated at server start.
To keep the Telegram credentials out of plaintext config as well, wrap the
whole command in op run and point the Telegram env vars at 1Password
references:
{
"mcpServers": {
"op-remote": {
"command": "op",
"args": ["run", "--no-masking", "--", "op-remote", "serve", "--env-file=.env.tpl"],
"env": {
"REMOTE_OP_TELEGRAM_BOT_TOKEN": "op://Development/op-remote-telegram/bot-token",
"REMOTE_OP_TELEGRAM_CHAT_ID": "op://Development/op-remote-telegram/chat-id"
}
}
}
}Here the outer op run resolves the Telegram references in env before
spawning op-remote serve, and the server then performs its own
op run --env-file=.env.tpl pass to load the project's secrets at startup.
--no-masking is required because the MCP server speaks JSON-RPC over stdio,
and op run's default stdout masking would corrupt that stream if any
resolved secret happened to match a protocol byte sequence.
Usage
Agent workflow
The agent calls the request_token MCP tool, then uses the returned token and
socket path to run commands with secrets:
op-remote run \
--token=TOKEN \
--sock=SOCKET_PATH \
--env-file=.env.tpl \
--reason="Running database migration" \
-- npm run migrateMCP tools
| Tool | Description |
| ---------------------- | ----------------------------------------------------------------------------- |
| request_token | Returns a one-time token and Unix socket path for authenticating with the CLI |
| resume | Request to resume a stopped session (requires Telegram approval) |
| disable_auto_approve | Turn off auto-approval, requiring Telegram approval for future requests |
Telegram approval buttons
When a secret access request is sent to Telegram, the approver sees:
- Approve - allow this single request
- Reject - deny the request (prompts for a reason via reply)
- Auto-Approve - approve this and all future requests in the session
- Stop - reject and halt the session entirely (the agent is instructed to stop)
Security
- One-time tokens prevent replay attacks. Each token can only be used once.
- Unix socket permissions are set to
0600, restricting access to the current user. - Output masking replaces secret values in stdout/stderr with
<redacted>. - Token reservation prevents concurrent use of the same token.
- Approver restrictions optionally limit who can approve requests via Telegram user IDs.
- Timeout ensures abandoned requests don't hang indefinitely.
Development
bun install
bun run build # transpile to dist/ (Node.js target)
bun run lint # oxlint
bun run fmt # oxfmt
bun run typecheck # tsc --noEmit
bun test # run testsLicense
MIT
