Skip to content

v0.4.252: MCP course-scoping + OAuth hardening#704

Merged
JimWallace merged 1 commit into
mainfrom
mcp-course-scoping-and-hardening
May 24, 2026
Merged

v0.4.252: MCP course-scoping + OAuth hardening#704
JimWallace merged 1 commit into
mainfrom
mcp-course-scoping-and-hardening

Conversation

@JimWallace
Copy link
Copy Markdown
Owner

Summary

Confines MCP agents to the courses their account is enrolled in (the feature requested after the audit), and closes the deferred OAuth-hardening items. Builds on the Phase-2 OAuth flow (#701#703).

Course-scoping

  • ToolContext.authorizeCourseAccess — admins act globally; every other subject (instructor browser-flow tokens and mcp service accounts) must be enrolled in the target course, else the tool returns a not authorized … not enrolled result. Wired into list_assignments and update_assignment_title.
  • Admin MCP tab course picker — enroll/unenroll a service account per course (chips + dropdown), audited (mcp.account_enrolled / mcp.account_unenrolled).
  • mcp-role accounts are excluded from the instructor and admin course roster views, so existing rosters/counts are unaffected. Students' access is untouched — gated by their own enrollment + session + RoleMiddleware, none of which changed; the unenroll path is hard-pinned to mcp-role accounts.

Hardening

  • Rate limiting + DCR caps — per-IP limit on /oauth/{token,revoke,register}; caps redirect-URIs/client and total registered clients. Env: MCP_OAUTH_RATE_LIMIT_PER_MIN (30), MCP_MAX_REGISTERED_CLIENTS (1000), MCP_MAX_REDIRECT_URIS (5).
  • Consent anti-phishing — shows the redirect host + a "you have not approved this app before" warning (DCR names are self-asserted).
  • Refresh re-authorization/oauth/token refresh re-checks isInstructor; a downgraded account's grant is revoked.
  • Origin guard fix — empty MCP_ALLOWED_ORIGINS now means "allow any" (matching the Host guard / docs).
  • OAuth-table reaper — periodic sweep deletes expired auth codes + revoked/expired grants (only when MCP enabled).

Test plan

  • swift test — full suite green (1446 tests / 129 suites)
  • swift-format lint --strict — clean
  • SwiftLint --strict — 0 violations (411 files)
  • New tests: course-scoping allow/deny/admin (tool + end-to-end), Origin empty-allowlist allow, refresh-after-downgrade revokes grant, reaper deletes dead rows
  • Verified "do no harm": student access paths unchanged; account-delete cascades enrollment rows; roster views exclude service accounts

🤖 Generated with Claude Code

Confine MCP agents to their enrolled courses and close the deferred
audit-hardening items.

Course-scoping:
- ToolContext.authorizeCourseAccess: admins act globally; every other
  subject must be enrolled in the target course (else notAuthorized).
  Wired into list_assignments and update_assignment_title.
- Admin MCP tab course picker (enroll/unenroll, audited via
  mcp.account_{en,un}rolled). mcp-role accounts are excluded from the
  instructor and admin course roster views, so rosters/counts are
  unaffected (students' access is untouched).

Hardening:
- MCPOAuthRateLimitMiddleware: per-IP limit on /oauth/{token,revoke,
  register}; register() caps redirect_uris/client and total clients.
- Consent screen shows the redirect host + a first-approval warning.
- /oauth/token refresh re-checks isInstructor and revokes the grant on
  downgrade.
- Empty MCP_ALLOWED_ORIGINS now means "allow any" (Origin guard fix).
- MCPOAuthReaperService periodically deletes expired auth codes and
  revoked/expired grants (registered only when MCP is enabled).

Full suite green (1446 tests); swift-format + SwiftLint --strict clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JimWallace JimWallace merged commit 126b97c into main May 24, 2026
10 checks passed
@JimWallace JimWallace deleted the mcp-course-scoping-and-hardening branch May 24, 2026 02:47
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