Skip to content

feat: add op_run and op_check_ref (use secrets without revealing plaintext)#12

Open
u2giants wants to merge 2 commits into
CakeRepository:masterfrom
u2giants:feat/op-run-op-check-ref
Open

feat: add op_run and op_check_ref (use secrets without revealing plaintext)#12
u2giants wants to merge 2 commits into
CakeRepository:masterfrom
u2giants:feat/op-run-op-check-ref

Conversation

@u2giants

@u2giants u2giants commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What & why

Adds two tools that let an agent use a 1Password secret without ever placing its plaintext into the model context or transcript — closing the gap between "read a secret" and "safely act with it."

op_run

The MCP equivalent of op run -- <command>. Runs a local command with op://vault/item/field references (supplied in env) resolved into the child process's environment variables. The resolved plaintext is:

  • injected into the child process env only,
  • redacted from all returned stdout/stderr and error messages (literal string replacement, so values with regex-special characters are handled), and
  • never logged.

Supports command (via shell) or argv (no shell, safer against quoting), plus cwd, stdin, timeout_ms, and a custom shell. Output is size-capped per stream.

op_check_ref

Validates an op://vault/item/field reference and returns only non-secret metadata (vault name, item title, field label/type) confirming it resolves. The field value is deliberately never returned — so a reference can be sanity-checked before use instead of reaching for password_read/item_get with reveal.

Why bulk secret resolution is needed

An op_run command can require several secret environment variables: for example, an API key, database URL, webhook token, and service credential. The original implementation resolved each op:// reference independently. That was safe, but it meant one command generated one serial 1Password SDK request per environment value. Repeated agent calls and multiple MCP sessions can therefore consume request capacity unnecessarily.

This change collects every op:// reference needed by one op_run request, validates the vault allow-list first, then calls the SDK's secrets.resolveAll(...) once. The individual results are mapped back to the requested environment names only after the bulk response succeeds; the child process is never started on a resolution failure.

This is deliberately a narrow, low-complexity improvement:

  • it reduces a command's repeated per-variable SDK resolution calls to one bulk SDK call;
  • it does not cache plaintext secret values;
  • it does not add a daemon, local broker, or background process; and
  • it does not coordinate independent MCP subprocesses or make a claim about account-wide rate limiting.

Resolved values remain in memory only for the active request and child-process environment, and are still redacted from returned output.

Optional vault allow-list

Both tools accept an optional OP_MCP_ALLOWED_VAULTS env var (or --allowed-vaults), a comma-separated list of vault names/IDs. When unset (the default), any accessible vault is permitted, matching the existing tools' behavior — so this is purely additive and non-breaking. Setting it restricts op:// resolution to the listed vaults.

Implementation notes

  • New shared helper src/secret-ref.ts parses/validates op:// references (reused by both tools).
  • op_run now calls client.secrets.resolveAll(references) once per secret-bearing command rather than looping through individual resolutions.
  • Registered in registerAllTools(); README tool table updated to 15.
  • Follows existing conventions: no any on public surfaces, errorResult/log/logError, conceal-by-default, no secrets in logs.

Tests

Adds coverage for redaction, literal-passthrough, allow-list enforcement, metadata-only guarantees, and bulk environment resolution. npm run build && npm test were green when the change was prepared.


🤖 Generated with Claude Code

…vealing plaintext

op_run executes a local command with op://vault/item/field references
resolved into environment variables. The resolved plaintext is injected
into the child process env only, redacted from all returned stdout/stderr
and error messages, and never logged — the MCP equivalent of `op run`.
This lets an agent USE a secret in a command/API call without ever placing
the plaintext in the model context or transcript.

op_check_ref validates an op:// reference and returns only non-secret
metadata (vault, item, field label/type) confirming it resolves, so a
reference can be checked before use without revealing the value.

Both accept an optional OP_MCP_ALLOWED_VAULTS / --allowed-vaults
allow-list; when unset (the default) any accessible vault is permitted,
matching existing tool behavior. Adds a shared secret-ref parser and 19
tests (build + 98 tests green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
u2giants added a commit to u2giants/1Password-MCP that referenced this pull request Jul 16, 2026
…sitory#11; CakeRepository#12/CakeRepository#13 open)

PR CakeRepository#7 is closed — the maintainer merged its item tools upstream through his
own PR CakeRepository#11 (2026-07-04), so feat/item-get-edit-list is now historical, not the
base for an open PR. Adds an "Upstream contributions" section documenting how
new contributions are cut from fresh branches off upstream/master (genericizing
fork-only defaults like the vibe_coding vault allow-list) and tracking the two
currently-open PRs: CakeRepository#12 (op_run/op_check_ref) and CakeRepository#13 (reveal-default hardening).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant