Purpose: the concrete list of MCP tools, each mapping to a Local API method. This is the agent-facing surface. Danger column drives required policy mode.
Danger: 🟢 read/safe · 🟡 mutating/normal · 🔴 dangerous (power/danger mode + audit).
Profiles
| Tool | Maps to | Danger |
|---|---|---|
vflin_profile_list |
profile.list |
🟢 |
vflin_profile_get |
profile.get |
🟢 |
vflin_profile_create |
profile.create |
🟡 |
vflin_profile_start |
profile.start |
🟡 |
vflin_profile_stop |
profile.stop |
🟡 |
vflin_profile_delete |
profile.delete (hard=🔴) |
🟡/🔴 |
Fingerprint
| vflin_fingerprint_generate | fingerprint.generate | 🟢 |
| vflin_fingerprint_validate | fingerprint.validate | 🟢 |
| vflin_fingerprint_presets | fingerprint.catalog.list | 🟢 |
| vflin_fingerprint_generate_from_host | fingerprint.generateFromHost | 🟢 |
| vflin_node_characterize | node.characterize | 🟢 |
Proxy
| vflin_proxy_list | proxy.list | 🟢 |
| vflin_proxy_test | proxy.test | 🟢 |
| vflin_proxy_bind | proxy.bind | 🟡 |
Automation
| vflin_automation_run | automation.run | 🟡 |
| vflin_automation_status | automation.status | 🟢 |
| vflin_automation_cancel | automation.cancel | 🟡 |
| vflin_automation_group_schedule | automation.group.schedule | 🟡 |
Sync
| vflin_sync_status | sync.status | 🟢 |
| vflin_sync_push / vflin_sync_pull | sync.push/pull | 🟡 |
Core & system
| vflin_core_list | core.list | 🟢 |
| vflin_core_diagnose | core.diagnose | 🟢 |
| vflin_system_health | system.health | 🟢 |
| vflin_log_tail | log.tail | 🟢 |
Dangerous (🔴 — power/danger mode, always audited)
| Tool | Maps to | Why dangerous |
|---|---|---|
vflin_vault_read |
vault.get |
exposes secrets |
vflin_cookies_export |
vault.export(scope=cookies) |
exfiltratable session material |
vflin_profile_hard_delete |
profile.delete{hard} |
irreversible |
vflin_profile_mass_update |
batched profile.* |
wide blast radius |
vflin_browser_eval |
core CDP Runtime.evaluate |
arbitrary in-page code |
vflin_migration_import |
importer | ingests untrusted external data |
vflin_profile_cdp_attach |
profile.cdp.attach |
hands a live profile’s CDP to code the daemon does not see — one client, through a revocable door (A89, ADR-0038) |
CDP through the daemon (A89, ADR-0038 Accepted)
A profile’s core speaks CDP over a pipe only the daemon holds — by default nothing on disk, no port. An agent
that needs raw CDP on a running profile calls vflin_profile_cdp_attach (danger: VFLIN_MCP_MODE=trusted,
fail-closed) and gets {wsEndpoint, expiresAt, brokered} — a loopback ws:// for ONE client, revoked by
vflin_profile_cdp_detach, by its TTL (default 15 min) or by the profile’s stop; vflin_profile_cdp_sessions
(normal) is the green read that says what is open. A profile the operator set to cdpTransport: port
answers its own public endpoint with brokered:false. Measured: a second client on a door is refused at
once; after detach the endpoint refuses the dial.
Rules
- 🔴 tools refuse unless session policy mode ≥ required; refusal explains how to elevate.
- Every 🟡/🔴 call writes an Action Log entry (tool, args-summary, mode, result).
- New tools are added here only when a backing Local API method exists.
Open questions
Whether vflin_browser_eval ships at all in v1, or stays behind a build flag → SECURITY_POLICY.md / OPEN_QUESTIONS.md.
Sessions (Feature c — ADR-0034)
No hand-written session tools exist, and none should: tools/list is built entirely from the generated
SURFACE table, so all five session operations surface automatically as
vflin_profile_session_{list,get,set,clear} and vflin_session_recipe_list, carrying the contract’s own mode
and danger level. MCP is the one surface that structurally cannot drift from the contract.
Danger gating, as enforced today:
| Tool | Danger | Needs |
|---|---|---|
vflin_session_recipe_list, vflin_profile_session_list, vflin_profile_session_get |
🟢 | read-only |
vflin_profile_session_set, vflin_profile_session_clear |
🔴 | VFLIN_MCP_MODE=trusted; refused before any daemon call |
One thing an agent author must know: vflin_profile_start is 🟡, but starting a profile whose automated
login has not run yet would submit stored credentials and a 2FA code to a third party. The daemon therefore
computes the required mode from the profile’s bindings, not from the route, and refuses with
SESSION_LOGIN_MODE_REQUIRED below danger. Cookie injection is unaffected — restoring a profile’s own saved
state stays a normal-mode start.
And the honest limit of that protection: the MCP session mode is process-wide, so a server started with
VFLIN_MCP_MODE=trusted sends x-vflin-mode: danger on every call — including the 🟡 start. The gate therefore
never fires for a trusted agent. That is consistent with mode being session-scoped (SECURITY_POLICY §1), and such
an agent could call vflin_profile_session_set anyway, so it grants nothing new — but do not read the gate as
“a trusted agent still cannot trip a credential login”. It protects the DEFAULT (read-only / normal) agent, which
is the one an untrusted prompt is most likely to be driving.