@@ -0,0 +1,42 @@
|
||||
# ADR-2026-09-16-injected-mcp-approval: Approve the injected Kandev server through ACP
|
||||
|
||||
**Status:** accepted
|
||||
**Date:** 2026-09-16
|
||||
**Area:** backend, protocol
|
||||
|
||||
## Context
|
||||
|
||||
Issue #3729 reports repeated Claude ACP permission prompts for Kandev plan and task tools.
|
||||
Codex already receives server-wide approval through its launch configuration.
|
||||
The issue explicitly offers server-wide Claude parity as its minimum fix.
|
||||
|
||||
## Decision
|
||||
|
||||
The proposed repair adds a server-specific decision before ACP creates a pending permission request.
|
||||
It requires a provider tool identity and host-owned injection provenance.
|
||||
It approves every tool on the injected Kandev server, not only bookkeeping tools.
|
||||
It does not enable blanket approval or change task authorization.
|
||||
|
||||
Provider naming compatibility belongs in pure adapter dialect hooks.
|
||||
The process manager owns policy and choice selection.
|
||||
Unknown identities retain normal permission handling.
|
||||
The flattened `mcp__server__tool` form is accepted only when it has one
|
||||
unambiguous separator. Delimiter collisions and adjacent underscores remain
|
||||
pending because the server/tool boundary cannot be trusted.
|
||||
|
||||
The [requirements](../specs/agents/requirements/injected-mcp-approval.md)
|
||||
and [design](../specs/agents/system-design/injected-mcp-approval.md) define the implemented boundary.
|
||||
|
||||
## Consequences
|
||||
|
||||
Claude can update plans and task titles without repeated prompts.
|
||||
The same policy also approves task creation, deletion, and session-management calls on the injected server.
|
||||
Existing server-side authorization and user-input barriers still apply.
|
||||
No approval history, new profile field, or database migration is necessary.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- Blanket profile approval also permits shell and third-party operations. It exceeds the requested boundary.
|
||||
- A selective allowlist and a restore-prompting setting need a different policy across Claude and Codex. They are outside this minimum package.
|
||||
- CLI-only allow flags depend on provider behavior and do not resolve the confirmed host-side pending-request path.
|
||||
- A generic title-prefix match cannot distinguish provider presentation from programmatic identity. The design restricts legacy title interpretation to Claude.
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
created: 2026-09-16
|
||||
status: complete
|
||||
requirements:
|
||||
- REQ-AGENTS-INJECTED-MCP-APPROVAL-001
|
||||
system_design:
|
||||
- ../../specs/agents/system-design/injected-mcp-approval.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Fix plan: Claude injected MCP approval
|
||||
|
||||
## Overview
|
||||
|
||||
Resolve [issue #3729](https://github.com/kdlbs/kandev/issues/3729) through its minimum server-wide parity option.
|
||||
The issue is assigned to `carlosflorencio`.
|
||||
One sequential work order implements the complete permission path and its regression coverage.
|
||||
Implementation is complete through the single work order below.
|
||||
|
||||
## Evidence and root cause
|
||||
|
||||
Investigated commit: `4c6e80091d82b4302e9dfc0a17b80965f1d4c62d`.
|
||||
The canonical issue has no comments or image attachments at investigation time.
|
||||
|
||||
The process manager checks only blanket `AutoApprovePermissions` before it stores a pending request.
|
||||
There is no injected-server exception. The ACP client also discards the programmatic tool name.
|
||||
Codex's separate passthrough strategy already emits a server-wide approval override.
|
||||
|
||||
A temporary `TestIssue3729Repro` used `Config.NewInstanceConfig(43210, nil)` and the real manager permission handler.
|
||||
It submitted `mcp__kandev__update_task_plan_kandev`, kind `other`, with allow-once and reject-once choices.
|
||||
Blanket approval remained false. The handler emitted `permission_request` and waited until context cancellation.
|
||||
|
||||
Command run:
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/agentctl/server/process -run '^TestIssue3729Repro$' -count=1 -v)
|
||||
```
|
||||
|
||||
Result: PASS, with the unwanted permission event observed. The temporary test was removed after execution.
|
||||
This proves the host permission path, not a live Claude or desktop session.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Preserve ACP programmatic tool identity and normalize legacy Claude identity.
|
||||
- Approve the host-injected server before pending-request creation.
|
||||
- Preserve unrelated permissions and normal tool events.
|
||||
- Document the server-wide policy and cover fresh and resumed configurations.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Per-tool allowlists, new settings, persistence, and Claude terminal passthrough.
|
||||
- Frontend changes, provider upgrades, and unverified provider dialects.
|
||||
- Changes to Codex policy or server-side authorization.
|
||||
|
||||
## Technical approach
|
||||
|
||||
Follow the [system design](../../specs/agents/system-design/injected-mcp-approval.md).
|
||||
The implementation crosses the existing ACP client, adapter, instance configuration, and process manager.
|
||||
Use new focused helper and test files instead of expanding large manager files.
|
||||
|
||||
## Tests
|
||||
|
||||
| Criteria | Permanent regression evidence |
|
||||
| --- | --- |
|
||||
| 001.1, 001.3, 001.8 | `client_permission_identity_test.go:TestPermissionProgrammaticName` and `dialect_claude_test.go:TestClaudePermissionIdentity` |
|
||||
| 001.2, 001.4, 001.7 | `config_test.go:TestInjectedKandevMCPProvenance` and `manager_permission_policy_test.go:TestInjectedKandevPermissionPolicy` |
|
||||
| 001.5, 001.6 | `manager_permission_policy_test.go:TestInjectedKandevPermissionOptions` |
|
||||
| 001.1, 001.3, 001.7, 001.8 | `manager_permission_acp_test.go:TestInjectedKandevPermissionACPFlow` |
|
||||
|
||||
The first policy regression must fail on current code because the manager emits a pending request.
|
||||
Tests must include mixed server lists, spoofed names, a Bash title that resembles an MCP name, and reversed option ordering.
|
||||
|
||||
## End-to-end evidence
|
||||
|
||||
The Go protocol integration test connects the real ACP conversion, adapter, and process manager through an in-memory ACP peer.
|
||||
It emits a Kandev permission request and verifies the selected wire response without a pending permission event.
|
||||
It then emits Bash and third-party requests and verifies that both remain pending until explicit resolution.
|
||||
Run the same sequence with fresh and resumed session identities and with task and Quick Chat instance contexts.
|
||||
Verify normal tool-call/result events remain present.
|
||||
This protocol boundary is the deterministic end-to-end evidence. No artificial browser test or UI redraw is required.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Implement injected server approval](task-01-injected-server-approval.md)
|
||||
|
||||
## Verification results
|
||||
|
||||
Investigation reproduction passed as described above. Implementation and verification passed.
|
||||
|
||||
- `(cd apps/backend && go test -race ./internal/agentctl/server/acp ./internal/agentctl/server/adapter/transport/acp ./internal/agentctl/server/config ./internal/agentctl/server/process ./internal/agent/mcpconfig -count=1)`: passed.
|
||||
- `node --test scripts/validate-public-docs.test.mjs`: passed.
|
||||
- `node scripts/validate-public-docs.mjs`: passed.
|
||||
- `python3 scripts/list-docs.py validate`: passed.
|
||||
- `python3 scripts/lint-spec-files.test.py`: passed.
|
||||
- `python3 scripts/lint-spec-files.py --all`: passed.
|
||||
- `git diff --check`: passed.
|
||||
- Catalog discovery found both new agent specification files.
|
||||
- GitHub assignment readback confirmed `carlosflorencio`.
|
||||
|
||||
## Risks
|
||||
|
||||
- The minimum policy approves all injected Kandev tools, including destructive and work-spawning tools.
|
||||
- Legacy Claude title interpretation requires exact provider and kind checks. It must not become a generic title heuristic.
|
||||
- Installed provider formats can differ. Unsupported shapes retain prompts, and compatibility claims require fixtures.
|
||||
- No live provider session was run during investigation.
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: "01-injected-server-approval"
|
||||
title: "Implement injected server approval"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-AGENTS-INJECTED-MCP-APPROVAL-001
|
||||
acceptance_criteria:
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.1
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.2
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.3
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.4
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.5
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.6
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.7
|
||||
- AC-AGENTS-INJECTED-MCP-APPROVAL-001.8
|
||||
system_design:
|
||||
- ../../specs/agents/system-design/injected-mcp-approval.md
|
||||
---
|
||||
|
||||
# Task 01: Implement injected server approval
|
||||
|
||||
## Summary
|
||||
|
||||
Add a permission decision for the host-injected Kandev server without enabling blanket approval.
|
||||
Preserve identity through the ACP conversion and use strict provider normalization.
|
||||
|
||||
## In scope
|
||||
|
||||
- Start with a failing manager regression for an injected Kandev plan update with blanket approval disabled.
|
||||
- Add identity fields, Claude dialect normalization, injection provenance, and offered-option selection through the documented path.
|
||||
- Add the unit and protocol integration tests named in the plan.
|
||||
- Update the permission sections in `docs/public/agents-and-profiles.md` and scoped agentctl guidance.
|
||||
- Mark the ADR accepted only after explicit implementation authorization for this package.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- New permission settings, storage changes, UI controls, and unrelated approval cleanup.
|
||||
- Changes to blanket approval's existing first-option fallback.
|
||||
- Removing Codex's existing launch override.
|
||||
|
||||
## Acceptance
|
||||
|
||||
1. All listed criteria pass through real production seams, including the protocol integration test.
|
||||
2. Unknown identity, forged title, unrelated server, missing provenance, and missing allow choices never receive approval through the new policy.
|
||||
3. Public reference text explains the server-wide exception, its destructive-tool scope, and its independence from blanket approval.
|
||||
|
||||
## Test matrix
|
||||
|
||||
- Names: programmatic qualified name, Claude metadata, legacy Claude title, empty name, malformed metadata, conflicting fields, wrong server, suffix-only name.
|
||||
- Operations: plan creation/update, title update, task deletion/creation, Bash, file edit, third-party MCP.
|
||||
- Injection: actual constructor, zero port, user-supplied reserved name, wrong port/path/transport, mixed server inventory, recreated instance.
|
||||
- Options: reject first, allow-always first with allow-once later, allow-always only, reject only, empty, unknown kinds.
|
||||
- Lifecycle: fresh/resumed session, task/Quick Chat context, cancellation of a remaining prompt, blanket approval on/off.
|
||||
- Streams: normal tool-call/result events, no automatic-path permission card, normal explicit resolution for unrelated tools.
|
||||
|
||||
Use channel synchronization and cleanup registration before assertions.
|
||||
Do not use arbitrary sleeps or a real user instance.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test -race ./internal/agentctl/server/acp ./internal/agentctl/server/adapter/transport/acp ./internal/agentctl/server/config ./internal/agentctl/server/process ./internal/agent/mcpconfig -count=1)
|
||||
node --test scripts/validate-public-docs.test.mjs
|
||||
node scripts/validate-public-docs.mjs
|
||||
python3 scripts/list-docs.py validate
|
||||
python3 scripts/lint-spec-files.test.py
|
||||
python3 scripts/lint-spec-files.py --all
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Record the initial failing regression and each final command result.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
Paths below are repository-relative. New files are marked `(new)`.
|
||||
|
||||
- `apps/backend/internal/agentctl/types/types.go`
|
||||
- `apps/backend/internal/agentctl/types/permission_identity.go` (new)
|
||||
- `apps/backend/internal/agentctl/types/permission_identity_test.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/acp/client.go`
|
||||
- `apps/backend/internal/agentctl/server/acp/client_permission_identity_test.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/adapter/transport/acp/dialect.go`
|
||||
- `apps/backend/internal/agentctl/server/adapter/transport/acp/dialect_claude.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/adapter/transport/acp/dialect_claude_test.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/adapter/transport/acp/adapter_permissions.go`
|
||||
- `apps/backend/internal/agentctl/server/config/config.go`
|
||||
- `apps/backend/internal/agentctl/server/config/config_test.go`
|
||||
- `apps/backend/internal/agentctl/server/process/manager.go`
|
||||
- `apps/backend/internal/agentctl/server/process/manager_permission_policy.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/process/manager_permission_policy_test.go` (new)
|
||||
- `apps/backend/internal/agentctl/server/process/manager_permission_acp_test.go` (new)
|
||||
- `apps/backend/internal/agentctl/AGENTS.md`
|
||||
- `docs/public/agents-and-profiles.md`
|
||||
- `docs/decisions/2026-09-16-injected-mcp-approval.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Risks
|
||||
|
||||
Server-wide approval includes task deletion and creation.
|
||||
The implementation must not infer trust from raw input or a display title from an unknown provider.
|
||||
Public permission snapshots must not expose the newly preserved provider metadata.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/agents/requirements/injected-mcp-approval.md)
|
||||
- [System design](../../specs/agents/system-design/injected-mcp-approval.md)
|
||||
- [Plan and evidence](plan.md)
|
||||
- Existing `client_test.go` permission conversion tests.
|
||||
- Existing `manager_permission_test.go` pending-request and cancellation tests.
|
||||
- Existing `config_test.go` injected HTTP/SSE ordering tests.
|
||||
- Repository `/tdd` skill and its backend test reference.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the Claude ACP injected-server permission path. ACP conversion now
|
||||
preserves internal programmatic identity and metadata, the Claude dialect
|
||||
normalizes only verified identity forms, and instance construction records
|
||||
host-injection provenance. The process manager approves every qualified tool
|
||||
on the exact injected Kandev HTTP or SSE server, preferring allow-once and then
|
||||
allow-always, while blanket approval and all unrelated pending flows remain
|
||||
unchanged. Flattened names with delimiter collisions fail closed to the
|
||||
pending flow. Permanent unit and in-memory ACP protocol tests cover fresh and
|
||||
resumed task and Quick Chat contexts, destructive and planning tools, spoofed
|
||||
identities, malformed metadata, option ordering, normal tool/result events, and
|
||||
explicit unrelated-tool resolution.
|
||||
|
||||
The public permissions reference and scoped agentctl guidance document the
|
||||
server-wide exception and its independent authorization boundaries. The ADR is
|
||||
accepted, and the paired requirement and system design are active/current.
|
||||
|
||||
Verification passed:
|
||||
|
||||
- `(cd apps/backend && go test -race ./internal/agentctl/server/acp ./internal/agentctl/server/adapter/transport/acp ./internal/agentctl/server/config ./internal/agentctl/server/process ./internal/agent/mcpconfig -count=1)`
|
||||
- `node --test scripts/validate-public-docs.test.mjs`
|
||||
- `node scripts/validate-public-docs.mjs`
|
||||
- `python3 scripts/list-docs.py validate`
|
||||
- `python3 scripts/lint-spec-files.test.py`
|
||||
- `python3 scripts/lint-spec-files.py --all`
|
||||
- `git diff --check`
|
||||
@@ -383,6 +383,8 @@ Literal values remain in profile configuration. A secret reference avoids copyin
|
||||
|
||||
In a structured ACP session, the agent can present a permission request and its available responses. With **Auto-approve all permissions** disabled, a person chooses a response in the session. With it enabled, the runtime selects the first allow-once or allow-always response without waiting. If the agent supplies no allow response, Kandev selects its first response even when that response is not approval; with no responses, it cancels.
|
||||
|
||||
Claude ACP also has a narrower built-in rule. When the agent uses the host-injected `kandev` MCP server, Kandev automatically selects an offered allow-once response, or allow-always when allow-once is not offered, even when **Auto-approve all permissions** is disabled. This covers every tool on that server, including task creation, task deletion, and plan changes. It is not a saved approval decision and is recreated for each task or Quick Chat session. Kandev still enforces MCP authentication, task and session authorization, user-question barriers, and workflow gates. Shell commands, file operations, third-party tools, and ambiguous requests keep the normal permission flow.
|
||||
|
||||
An external MCP client can also list live pending requests for an authorized task and submit one
|
||||
exact option originally offered by the agent. The request-generation ID prevents an old approval
|
||||
from targeting a replacement prompt that reused a provider pending ID. Kandev records who selected
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
status: active
|
||||
system: agents
|
||||
created: 2026-09-16
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
|
||||
# Injected MCP approval requirements
|
||||
|
||||
## Overview
|
||||
|
||||
Claude ACP sessions require repeated approval for Kandev task and plan tools.
|
||||
Codex already receives automatic approval for the injected Kandev server.
|
||||
The agent system owns this provider permission contract.
|
||||
|
||||
This package adopts the minimum server-wide parity option in
|
||||
[issue #3729](https://github.com/kdlbs/kandev/issues/3729).
|
||||
It does not adopt the issue's separate proposal for selective approval and a new setting.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-AGENTS-INJECTED-MCP-APPROVAL-001: Approval for the injected Kandev server
|
||||
|
||||
**Intent:** Users can use Kandev tools through Claude ACP without enabling blanket approval for the agent.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.1:** With blanket approval disabled, identifiable calls to the injected Kandev server shall proceed without permission prompts in Claude ACP sessions.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.2:** This policy shall apply to every tool on that server, including task creation and deletion. Tool authorization shall remain enforced.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.3:** Shell commands, file operations, third-party tools, and ambiguous requests shall retain their existing permission behavior.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.4:** A user-configured server with a similar or identical name shall not receive approval through this policy.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.5:** Automatic approval shall select an offered allow-once choice. If none exists, it shall use an offered allow-always choice.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.6:** Without an offered allow choice, the request shall retain its normal permission behavior. A request without choices shall cancel.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.7:** Fresh and resumed task sessions, including Quick Chat, shall use the same policy without a saved approval decision.
|
||||
- **AC-AGENTS-INJECTED-MCP-APPROVAL-001.8:** Existing Codex approval and blanket approval behavior shall remain unchanged. Unknown provider naming formats shall retain normal permission behavior.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Selective tool lists, persisted approval decisions, and new profile or workspace settings.
|
||||
- Claude terminal passthrough, which does not use ACP permission frames.
|
||||
- Automatic support claims for unverified provider naming formats.
|
||||
- Changes to question barriers, workflow gates, or server-side task authorization.
|
||||
|
||||
## Implementation plans
|
||||
|
||||
- [Issue 3729 fix package](../../../plans/claude-injected-mcp-approval/plan.md)
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
status: current
|
||||
system: agents
|
||||
requirements:
|
||||
- REQ-AGENTS-INJECTED-MCP-APPROVAL-001
|
||||
---
|
||||
|
||||
# Injected MCP approval design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
The process manager owns the automatic permission decision.
|
||||
The ACP client preserves provider identity fields, and the adapter normalizes provider-specific names.
|
||||
The MCP server continues to enforce task and session authorization.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Acceptance criteria | Design section |
|
||||
| --- | --- |
|
||||
| 001.1, 001.3, 001.8 | Identity normalization |
|
||||
| 001.2, 001.4 | Injection provenance |
|
||||
| 001.5, 001.6 | Permission decision |
|
||||
| 001.7 | Lifecycle and observability |
|
||||
|
||||
All references belong to `REQ-AGENTS-INJECTED-MCP-APPROVAL-001`.
|
||||
|
||||
## Current path and defect
|
||||
|
||||
`internal/agent/mcpconfig/passthrough.go:codexServerArgs` adds
|
||||
`default_tools_approval_mode=approve` for the `kandev` server.
|
||||
ACP uses a different path:
|
||||
|
||||
1. `server/acp/client.go:forwardPermissionRequest` converts the permission frame.
|
||||
2. `transport/acp/adapter_permissions.go:handlePermissionRequest` forwards it.
|
||||
3. `server/process/manager.go:handlePermissionRequest` checks only `AutoApprovePermissions`.
|
||||
4. Without blanket approval, the manager creates a pending request and waits.
|
||||
|
||||
The ACP conversion currently drops the programmatic `ToolCall.Name` and its metadata.
|
||||
The pinned Go SDK already supports both fields. No SDK upgrade is necessary.
|
||||
The shared adapter's `AutoApprove` field does not implement the permission decision.
|
||||
|
||||
## Identity normalization
|
||||
|
||||
Extend the internal `types.PermissionRequest` with optional `ToolName` and `ToolMeta` fields.
|
||||
Copy `ToolCall.Name` and `ToolCall.Meta` in `forwardPermissionRequest`.
|
||||
These fields remain internal. Do not expose metadata in public permission snapshots or logs.
|
||||
|
||||
Use a strict qualified-name parser for `mcp__kandev__<tool>`.
|
||||
Because this flattened format uses `__` as its boundary, accept only one
|
||||
unambiguous separator. Reject a separator next to another underscore and
|
||||
reject another `__` in the remaining name. This keeps names such as
|
||||
`mcp__kandev__external__execute` and `mcp__kandev___execute` out of the
|
||||
automatic path, even when the tool identifier itself could contain `__`.
|
||||
Require the exact server segment and a nonempty tool identifier with letters,
|
||||
digits, underscores, or hyphens.
|
||||
Do not match substrings, descriptions, raw arguments, or the `_kandev` suffix alone.
|
||||
|
||||
A supplied programmatic name is authoritative, including a nonmatching name.
|
||||
Never replace a nonmatching name with a matching display title.
|
||||
For `claude-acp` frames without a name, use a pure compatibility hook in `dialect_claude.go`.
|
||||
The hook first reads `_meta.claudeCode.toolName` when present.
|
||||
Malformed or conflicting metadata produces no eligible identity.
|
||||
Only when both identity fields are absent can the hook use an exact qualified title with kind `other`.
|
||||
This fallback is specific to Claude's observed MCP presentation, not a generic ACP rule.
|
||||
Other provider formats retain the normal prompt path until a tested dialect supports them.
|
||||
|
||||
The upstream [Claude tool formatter](https://github.com/agentclientprotocol/claude-agent-acp/blob/v0.75.1/src/tools.ts)
|
||||
uses the tool name as the default MCP title.
|
||||
Its [permission presentation](https://github.com/agentclientprotocol/claude-agent-acp/blob/v0.75.1/src/permissions/presentation.ts)
|
||||
also supplies a programmatic name.
|
||||
Implementation fixtures must cover both shapes because installed versions can differ.
|
||||
|
||||
## Injection provenance
|
||||
|
||||
Add an internal `InjectedKandevMCP` boolean with `json:"-"` to `config.InstanceConfig`.
|
||||
Only `Config.NewInstanceConfig` sets it, immediately after local server injection with a positive instance port.
|
||||
Do not add it to `InstanceOverrides`, public DTOs, persisted profiles, or incoming JSON.
|
||||
The marker is false for configurations without host injection.
|
||||
|
||||
The permission predicate requires this marker and the exact injected server configuration.
|
||||
Require a URL for the current instance port at `http://localhost:<port>/mcp` or `/sse`.
|
||||
Require no stdio command and the corresponding supported HTTP/SSE transport.
|
||||
The current injector replaces user entries named `kandev`, so those entries cannot retain the reserved slot.
|
||||
Cover a mixed list containing both the injected server and unrelated servers.
|
||||
The existence of unrelated entries must not grant them approval or disable the injected entry.
|
||||
|
||||
## Permission decision
|
||||
|
||||
Keep the existing blanket approval branch first.
|
||||
Before pending-request allocation, evaluate the injected-server predicate.
|
||||
Select an offered `allow_once`, then an offered `allow_always`.
|
||||
Return its exact option ID. Never invent a choice or fall back to a reject option.
|
||||
If no allow choice exists, continue through the existing pending-request path.
|
||||
The ACP client's existing empty-options cancellation remains intact.
|
||||
|
||||
Use a small helper in `server/process/manager_permission_policy.go`.
|
||||
Do not reuse `autoApprovePermission` for this branch: that helper falls back to the first option, including rejection.
|
||||
Keep all existing pending-request identity, cancellation, and exactly-once resolution rules unchanged.
|
||||
|
||||
## Lifecycle and observability
|
||||
|
||||
The policy has no persistence or migration. Instance construction recreates provenance after restart or resume.
|
||||
The adapter retains normal tool-call and result events on the automatic path.
|
||||
Automatic approval does not create a pending permission card on desktop or phone.
|
||||
Log the policy reason, tool identifier, and selected option kind without arguments, headers, or credentials.
|
||||
No frontend layout or copy changes are required.
|
||||
|
||||
## Security and compatibility
|
||||
|
||||
This policy trusts the configured agent's protocol identity, as the existing permission flow does.
|
||||
It does not defend against a malicious agent process that fabricates protocol frames.
|
||||
Raw MCP arguments cannot establish identity or injection provenance.
|
||||
Unknown and malformed names fail closed to the normal permission flow.
|
||||
|
||||
Server-wide parity also approves destructive Kandev tools at the provider permission layer.
|
||||
Task reachability, ownership, explicit user-question answers, and workflow completion rules remain separate enforcement points.
|
||||
The external permission-resolution specification remains authoritative for requests that become pending.
|
||||
Its unchanged-auto-approval statement describes that feature's scope, not this proposed policy addition.
|
||||
|
||||
## Related decisions
|
||||
|
||||
- [Injected server approval policy](../../../decisions/2026-09-16-injected-mcp-approval.md)
|
||||
- [Live permission authority](../../../decisions/2026-08-11-live-agent-permission-authority.md)
|
||||
Reference in New Issue
Block a user