Skip to content

feat: MCP user-scope and team-scope resource providers#68

Merged
poxet merged 2 commits into
masterfrom
feature/mcp-user-and-team-scope
May 11, 2026
Merged

feat: MCP user-scope and team-scope resource providers#68
poxet merged 2 commits into
masterfrom
feature/mcp-user-and-team-scope

Conversation

@poxet
Copy link
Copy Markdown
Contributor

@poxet poxet commented May 11, 2026

Summary

Extends the Tharga.Platform.Mcp bridge beyond the system slice (PR #51) with two always-on resource providers that surface the authenticated caller's own Platform data. Closes most of the deferred work tracked in Requests.md"Tharga.Platform — MCP / MCP Provider for Team/User data".

  • PlatformUserResourceProvider (McpScope.User) — platform://me returns the caller's IUser plus a memberships array (teamKey, teamName, accessLevel, state).
  • PlatformTeamResourceProvider (McpScope.Team) — platform://team, platform://team/members, platform://team/apikeys rooted at the caller's current team via the TeamKey claim. Raw ApiKey values are redacted (the apiKey property is omitted entirely).
  • New ITeamService.GetMembersAsync(teamKey) returning IAsyncEnumerable<ITeamMember> so providers can enumerate members without knowing the consumer-specific TMember type. Default TeamServiceBase implementation reuses the existing reflection helper; AuditingTeamServiceDecorator forwards.

Both providers register automatically in AddPlatform() — no new opt-in option. They self-gate on principal claims, so anonymous and system-only callers see no resources.

Behaviour change for consumers

  • AddPlatform() now registers two additional IMcpResourceProvider instances. Consumers don't need to touch their wiring.
  • ITeamService adds GetMembersAsync. Consumers subclassing TeamServiceBase (the common path) get the default automatically. Consumers implementing ITeamService directly (rare) need to add the method.
  • No new scope constants. No new options. No new package references.

Out of scope (deferred)

  • Cross-tenant platform://teams listing in System scope — requires a new ITeamService.GetAllTeamsAsync(). The Requests.md MCP entry stays open for this last piece.
  • Tool providers (IMcpToolProvider) — read-only resources only in this feature; mutating operations are not exposed.
  • User-level personal API keys — Tharga.Team doesn't model these.

Test plan

  • `dotnet build -c Release` — 0 warnings, 0 errors
  • `dotnet test -c Release` — 313 / 313 passing (17 new)
  • `PlatformUserResourceProviderTests` (5) — empty list for anonymous; descriptor for authenticated; throws on no current user; JSON shape (user + memberships)
  • `PlatformTeamResourceProviderTests` (10) — list gates on TeamKey; ApiKey resource conditional on service registration; reads for all three URIs including the invited-flag projection and raw-key redaction
  • `TeamServiceBaseGetMembersAsyncTests` (2) — yields ordered members via the reflection default; unknown team yields empty

Documentation

  • `Tharga.Platform.Mcp/README.md` — new "User and team resources" section documenting both scopes and the three team URIs.
  • `Tharga.Team/README.md` — one-line addition for the new `GetMembersAsync` on `ITeamService`.

poxet added 2 commits May 11, 2026 14:52
Extends the Tharga.Platform.Mcp bridge beyond the system slice with two
always-on resource providers that surface the authenticated caller's own
Platform data.

- PlatformUserResourceProvider (McpScope.User) — platform://me with the
  caller's IUser + memberships across teams.
- PlatformTeamResourceProvider (McpScope.Team) — platform://team,
  platform://team/members, platform://team/apikeys rooted at the caller's
  current team via the TeamKey claim. ApiKey raw values are redacted.
- New ITeamService.GetMembersAsync(teamKey) returning
  IAsyncEnumerable<ITeamMember>, with a default TeamServiceBase
  implementation that reuses the existing reflection helper. The AuditingTeamServiceDecorator forwards the call through.

Both providers register automatically in AddPlatform(); they self-gate on
principal claims, so anonymous and system-only callers see nothing.

17 new tests, 313 / 313 passing. Cross-tenant team listing (system slice
platform://teams) remains deferred — needs ITeamService.GetAllTeamsAsync.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

@poxet poxet merged commit 69a255a into master May 11, 2026
5 of 6 checks passed
@poxet poxet deleted the feature/mcp-user-and-team-scope branch May 11, 2026 13:16
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