Report effective agent permissions per project #237
Description
Outcome
An authenticated agent can determine what it is allowed to do in a project without attempting a mutation and reading the resulting error.
Problem
The server derives effective permissions from AgentKey (GranularPermissions, GlobalWrite, AllProjectsWrite, AllProjectsModerate, CanCreateProjects, RestrictedProjects, plus single-project ProjectId/CanWrite/CanModerate) and AgentProjectGrant (CanWrite, CanModerate), but no MCP response exposes the result. project_list returns project rows only; memory_recall returns knowledge only; the OAuth scope mcp offline_access carries no per-project authorization.
Consequences today:
- An agent cannot tell a missing permission from a genuine failure until a write is rejected.
- Onboarding cannot report the connection's effective scope, so the operator has no confirmation that the consent screen produced the intended grants.
- Dashboards and planning have no read model for what a given connection may actually do.
Work
- Extend
project_listrows with the caller's effective permissions for that project: at least read, write, moderate, plus whether shared/public changes require review. - Expose the same derived values when a single project is queried, so a resolved
projectIdfrom.agents/conderis.jsonis sufficient without listing everything. - Include account-level capabilities that are not per-project, notably
CanCreateProjects, soproject_createcan be checked before it is called. - Return a derived, read-only view. Do not expose key hashes, prefixes, other agents' grants, other owners' permissions, or any credential material.
- Collapse the permission flags to the set actually needed while doing this. Several overlapping key shapes exist; pick one model rather than reporting on all of them.
- State the permission contract in
system_memoryso agents check capability before choosing between a direct write and a proposal.
Acceptance
- A read-only connection sees
write: falseandmoderate: falseand performs no mutation to learn it. - A restricted key reports permissions only for the projects it may access; non-granted projects are not listed or described.
- One permission model resolves effective values; no parallel legacy key path is kept alive alongside it.
- Reported permissions match what the corresponding mutation actually enforces, verified by tests that assert both together.
- Revoking a grant or a key changes the reported permissions on the next call.
- No response exposes another owner's or another agent's permissions.
Constraints
Pre-release, no live users. Simplify the model outright; no migration, no compatibility shim, no parallel versioned variant.
Evidence
src/ProjectMemory.Web/Data/Entities.cs (AgentKey, AgentProjectGrant), src/ProjectMemory.Web/Services/MemoryTools.cs (project_list). Observed on 2026-09-14 during OAuth onboarding of the agent Claude Code: read access was confirmed empirically, while write, moderate and project-creation rights could not be determined from any tool response.
Agent handoff
Planning task only. Read-only reporting of existing derived state; it must not add, widen or change any permission.