@vaultclaw/vaultclaw-mcp-approval-handoff
v0.1.10
Published
OpenClaw plugin that auto-waits Vaultclaw MCP approvals
Readme
Vaultclaw MCP Approval Handoff Plugin
OpenClaw plugin that auto-handles Vaultclaw MCP approval handoff during agent tool runs.
Primary supported backend path: OpenClaw Gateway POST /tools/invoke against direct vaultclaw_*
tools exposed by plugin id vaultclaw-openclaw-bridge.
When a tool returns MCP_APPROVAL_REQUIRED, the plugin:
- extracts
error.details.approval.next_action.arguments.handle - notifies the user to approve/deny in Vaultclaw UI
- asynchronously invokes
vaultclaw_approval_wait - posts a single terminal update for
ALLOW,DENY, or timeout - on
ALLOW, first runs a fastvaultclaw_job_getcompletion probe and posts an immediate final success callback when the job is already terminal; if inconclusive, falls back to one follow-upagentrun for the samesessionKey
No second manual CLI command is required.
Responsibility Split
| Component | Responsibility |
| --- | --- |
| vaultclaw-openclaw-bridge | Exposes direct vaultclaw_* tools inside OpenClaw. |
| vaultclaw-mcp-approval-handoff | Handles MCP_APPROVAL_REQUIRED, waits, posts terminal outcome, and auto-resumes on ALLOW. |
Install
Option A: npm package
openclaw plugins install @vaultclaw/vaultclaw-mcp-approval-handoffOption B: one-shot installer script (local checkout)
./scripts/install.shThis installer also applies OpenClaw core hotfixes (Telegram slash-command reload + plugin command session context passthrough for async follow-ups) and restarts the gateway automatically.
Optional npm/package override:
./scripts/install.sh @vaultclaw/vaultclaw-mcp-approval-handoffConfig
Plugin id: vaultclaw-mcp-approval-handoff
{
"plugins": {
"entries": {
"vaultclaw-mcp-approval-handoff": {
"enabled": true,
"config": {
"enabled": true,
"pollIntervalMs": 1500,
"maxWaitMs": 600000,
"commandTimeoutMs": 720000,
"maxConcurrentWaits": 10,
"allowMcporterFallback": false,
"reconcileOnValidationError": true,
"reconcileOnUnknownTerminal": true,
"reconcileOnWaitError": true,
"reconcileTimeoutMs": 15000,
"vaultCommand": {
"enabled": true,
"defaultEnabled": true,
"defaultMode": "hybrid",
"autoDisableTelegramNativeCommands": true,
"sessionModeTtlMs": 604800000,
"maxConcurrentRuns": 5,
"enableCoreFallback": true,
"coreFallbackTimeoutMs": 30000,
"resolverTool": "vaultclaw_route_resolve",
"resolverTimeoutMs": 8000,
"enrichmentGlobalTimeoutMs": 10000,
"enrichmentTaskTimeoutMs": 6000,
"deterministicDomains": [
"google.gmail",
"generic.http"
]
}
}
}
}
}
}Validation rules:
pollIntervalMs:250..10000maxWaitMs:1000..3600000commandTimeoutMs > maxWaitMsmaxConcurrentWaits >= 1reconcileTimeoutMs:1000..60000vaultCommand.enrichmentGlobalTimeoutMs:1000..60000vaultCommand.enrichmentTaskTimeoutMs:1000..60000and<= enrichmentGlobalTimeoutMs
Legacy note:
allowMcporterFallbackis a deprecated escape hatch for older stacks and is not recommended.- Keep
allowMcporterFallback=falsefor the standard bridge-based runtime path.
Deterministic /vault Command
When enabled, the plugin registers /vault:
/vault on [hybrid|strict]/vault off/vault status/vault update token <ses_...>/vault <natural language request>
Mode semantics:
HYBRID(default): vault-eligible requests use deterministic route/execute; non-eligible requests auto-fallback to normal OpenClaw flow.STRICT: vault-eligible requests only; non-eligible requests are rejected with guidance.
Resolver requirement:
/vaultdeterministic path requires MCP toolvaultclaw_route_resolve(from updatedaccords-mcp).- During missing-input enrichment flows, the plugin shows a short progress update based on MCP
progress_hintbefore auto-enrichment tasks begin. - For Telegram deployments, the plugin can auto-set
channels.telegram.commands.native=falseat startup (vaultCommand.autoDisableTelegramNativeCommands=true) to avoid intermittent native slash-command misses that can surface asCommand not found.before plugin routing.
Behavior
- Scope: MCP tool results in OpenClaw agent runs.
- Non-blocking: wait worker runs async from
after_tool_call. - Supported handles:
JOBandPLAN_RUN. - Dedupe key:
(session_id, challenge_id, pending_id, run_id/job_id). - Session lifecycle: pending waits are canceled on
before_resetandsession_end. - Retries: transient transport failures retry with backoff (
1s, 2s, 4s, 8s, 16s, max 5 attempts). - No-retry terminal categories: validation/auth/timeouts.
- Reconciliation: when wait payloads are malformed or terminal status is unknown, plugin attempts read-only reconciliation through
vaultclaw_approvals_pending_getandvaultclaw_job_get. - Reconciliation on wait failure: transient wait transport failures can trigger a read-only reconciliation check before surfacing terminal error guidance.
- ALLOW completion callback: after ALLOW, plugin probes
vaultclaw_job_getwith a short timeout to post deterministic completion updates without waiting for an extra model turn. - Legacy mcporter fallback remains opt-in (
allowMcporterFallback=true) but is deprecated; standard behavior uses Gateway/tools/invokeonly. - Unknown terminal outcomes are surfaced explicitly (not as timeout) with retry guidance.
- If
ALLOWis confirmed but auto-resume fails, plugin posts a manual fallback instruction (reply approvedor rerun request).
Operational Limits
- Wait calls are executed through the local Gateway HTTP route:
POST /tools/invoke. - Gateway auth must allow that route (
token/passwordvia config or env, ornone/trusted-proxymode). - Status updates are posted through system events + heartbeat wake and require a valid
sessionKey. - At most
maxConcurrentWaitsapproval workers run in parallel.
Observability
Structured plugin logs include:
approval_detectedwait_startedwait_completedwait_failedwait_canceledwait_retryterminal_outcomecompletion_probe_succeededcompletion_probe_inconclusivecompletion_probe_failedresume_startedresume_completedresume_failedcleanup
Each log includes correlation keys when available:
session_idchallenge_idpending_idrun_id/job_id
Example Transcript
- User: "Trash the newsletter in Gmail from yesterday."
- Tool result: approval challenge returned (
MCP_APPROVAL_REQUIRED). - Plugin post: "Approval required in Vaultclaw UI. Waiting up to 10 minutes... (challenge_id=..., pending_id=..., run_id=...)"
- User approves in Vaultclaw UI.
- Plugin post: "Approval allowed in Vaultclaw UI. Continuing automatically. (...ids...)"
Development
npm install
npm test