Skip to content

feat(mcp): server module foundation + compatibility spike - #539

Merged
yacosta738 merged 23 commits into
mainfrom
feature/mcp-server-01-foundation
Aug 3, 2026
Merged

feat(mcp): server module foundation + compatibility spike#539
yacosta738 merged 23 commits into
mainfrom
feature/mcp-server-01-foundation

Conversation

@yacosta738

Copy link
Copy Markdown
Contributor

Summary

PR 1 of the stacked PRs strategy for the MCP server feature (issue #157).

This PR delivers the compatibility spike + module skeleton that unblocks PR 2 (security + OAuth discovery).

What's in this PR

1. Compatibility spike outcome (SPIKE_OUTCOME.md)

Comprehensive documentation of the technical spike validating:

  • Spring AI 2.0 GA @McpTool annotation API with Kotlin coroutines
  • Keycloak 26 DCR (Dynamic Client Registration) is supported
  • Keycloak 26 CIMD (Client ID Metadata Documents) is NOT supported — fallback to pre-registered clients
  • RFC 8707 resource parameter handling verified
  • Workspace injection mechanism chosen: Option A (signed JWS + protocol mapper)
  • MCP Inspector end-to-end validation

2. Spring AI 2.0.0 integration

  • Added springAi = "2.0.0" to gradle/libs.versions.toml
  • Added spring-ai-bom and spring-ai-starter-mcp-server-webflux dependencies
  • Configured module skeleton in server/smp/build.gradle.kts

3. mcp bounded context

  • Hexagonal package structure: domain / application / infrastructure / infrastructure/oauth
  • McpConfiguration (placeholder, gated by SMP_MCP_ENABLED)
  • McpSecurityConfiguration (placeholder — returns 401 for /api/mcp)
  • McpBoundedContext + ModuleMetadata markers for Spring Modulith discovery

4. Configuration

spring:
  ai:
    mcp:
      server:
        enabled: ${SMP_MCP_ENABLED:false}
        protocol: STATELESS
        type: ASYNC
        streamable-http:
          mcp-endpoint: /api/mcp
app:
  mcp:
    resource-uri: ${SMP_MCP_RESOURCE_URI:https://api.profiletailors.com/api/mcp}
    required-audience: ${SMP_MCP_AUDIENCE:https://api.profiletailors.com/api/mcp}

5. Acceptance test: McpWiringTest

Verifies that POST /api/mcp returns 401 + WWW-Authenticate: Bearer realm="mcp" when the server is enabled.

What's NOT in this PR (deferred to PR 2)

  • JWT validation chain (placeholder security config)
  • OAuth discovery endpoints (RFC 9728)
  • Workspace context resolver
  • Any actual @McpTool beans
  • Server-to-client scope enforcement

Pre-merge checklist

  • just backend-check passes
  • just backend-test passes
  • just backend-bdd-fast passes
  • just ci-local passes (gitleaks, lint, tests, build)
  • No @McpTool beans registered (no tools yet)
  • Feature flag SMP_MCP_ENABLED=false by default (safe to deploy)

Verification

# Server boots, MCP endpoint returns 401
SMP_MCP_ENABLED=true ./gradlew :server:smp:bootRun
curl -X POST http://localhost:8080/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","id":1}' \
  -i
# Expect: HTTP 401 + WWW-Authenticate: Bearer realm="mcp"

Stacked PRs

This PR is the foundation. Subsequent PRs will branch from it:

  • PR 2 (security): feature/mcp-server-02-security → base PR 1
  • PR 3 (tools): feature/mcp-server-03-tools → base PR 2
  • PR 4 (verification): feature/mcp-server-04-verification → base PR 3

Each PR's base branch must be re-retargeted to main after the previous PR merges.

Watchpoints for PR 2

  1. McpSecurityConfiguration is a placeholder — PR 2 must replace with full JWT chain
  2. JWT validation must be scoped to /api/mcp/** only (don't leak into REST endpoints)
  3. CIMD compatibility re-test in staging with real Keycloak 26

References

@github-actions github-actions Bot added area:backend Changes in backend code (server/smp/** or shared/**) area:docs Documentation changes (docs/**, *.md, *.mdx) type:test Test files or test infrastructure changes type:dependency Dependency updates (Renovate or manual) labels Jul 30, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploying profiletailors with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0b72134
Status: ✅  Deploy successful!
Preview URL: https://c2534ce4.profiletailors-com.pages.dev
Branch Preview URL: https://feature-mcp-server-01-founda.profiletailors-com.pages.dev

View logs

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added foundational MCP server support behind a feature flag, with configurable resource URI and required audience.
    • Enabled a protected, stateless Streamable HTTP MCP endpoint at /api/mcp.
    • Unauthenticated requests now return 401 Unauthorized with a Bearer authentication challenge.
  • Documentation

    • Added comprehensive MCP documentation covering OAuth, workspace isolation, scope enforcement, error handling, and staged rollout guidance.
  • Tests

    • Added integration coverage for MCP enablement, application wiring, and unauthenticated endpoint behavior.

Walkthrough

This change establishes the MCP server foundation with Spring AI dependencies, feature-gated WebFlux transport, a Modulith-aligned bounded context, authenticated /api/mcp access, wiring tests, and specifications for OAuth, workspace isolation, scopes, tools, and errors.

Changes

MCP Server Foundation

Layer / File(s) Summary
Architecture and security contracts
openspec/changes/mcp-server/*.md, openspec/changes/mcp-server/specs/*
Defines stateless /api/mcp transport, Keycloak OAuth ownership, workspace-bound JWT validation, tool scope enforcement, read-only tools, error handling, and client registration behavior.
Spring AI and bounded-context wiring
gradle/libs.versions.toml, server/smp/build.gradle.kts, server/smp/src/main/.../mcp/*, server/smp/src/main/resources/application.yaml, .env.example
Adds Spring AI 2.0 dependencies, feature-gated MCP properties, resource and audience configuration, and the initial MCP package structure.
MCP security boundary and tests
server/smp/src/main/kotlin/.../mcp/infrastructure/McpSecurityConfiguration.kt, server/smp/src/test/kotlin/.../McpWiringTest.kt
Protects /api/mcp with authentication, adds a Bearer challenge for unauthenticated requests, and verifies module registration, conditional beans, and HTTP 401 behavior.
Spike outcomes and delivery plan
openspec/changes/mcp-server/spikes/*, openspec/changes/mcp-server/tasks.md, openspec/changes/mcp-server/state.yaml
Records Spring AI and Keycloak compatibility decisions, workspace-context findings, staged tasks, acceptance gates, and workflow state.
Scheduled publication fixture updates
server/smp/src/test/kotlin/.../PublishingBddSteps.kt, server/smp/src/test/resources/features/publishing-publications.feature
Changes scheduled publication fixture timestamps from August 2026 to August 2027.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant McpSecurityConfiguration
  participant MCPEndpoint
  MCPClient->>McpSecurityConfiguration: POST /api/mcp
  McpSecurityConfiguration->>MCPEndpoint: authenticated request
  MCPEndpoint-->>MCPClient: MCP response
  McpSecurityConfiguration-->>MCPClient: 401 with Bearer challenge
Loading

Suggested labels: architecture, security

Poem

Spring configures MCP’s gate,
Tokens meet the endpoint state.
Workspaces bind to claims and scope,
Tests confirm the security rope.

🚥 Pre-merge checks | ✅ 7 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Coverage (Reliability) ⚠️ Warning McpWiringTest covers enabled wiring and one unauthenticated POST, but no unit tests cover filter branches or disabled behavior; implementation defd7f9 preceded test ec599f7. Add focused tests for 401 header branches, path scoping, and the disabled flag. Assert transport and tool absence. Commit failing tests before implementation.
Readability Review ⚠️ Warning McpWiringTest contains a redundant unused SpringBootApplication::class.java.let and reflective class-name lookup, while its KDoc claims transport and tool checks that have no assertions. Import SmpApplication and call ApplicationModules.of(SmpApplication::class.java); add the missing assertions or remove the unverified KDoc claims.
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits format and accurately describes the MCP foundation and compatibility spike.
Description check ✅ Passed The description clearly explains the MCP foundation, compatibility findings, tests, deferred work, and feature-flagged rollout.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Hexagonal Architecture Compliance ✅ Passed MCP domain and application layers have no imports; infrastructure contains only Spring security/configuration code, with no reverse imports, cycles, controllers, handlers, commands, queries, or ser...
Security Review ✅ Passed No SQL, HTML, or MCP tool code was added; MCP is disabled by default, enabled requests require authentication, and only placeholder values are committed. CSRF is disabled for the stateless bearer-o...
Resilience Review ✅ Passed MCP code adds only inbound WebFlux wiring; no outbound calls require timeouts, retries, or circuit breakers, and the reactive filter propagates chain errors while the feature flag provides safe deg...
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/mcp-server-01-foundation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedmaven/​org.springframework.ai/​spring-ai-bom@​2.0.010010090100100

View full report

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploying app-profile-tailors with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0b72134
Status: ✅  Deploy successful!
Preview URL: https://eb7a5fab.app-profile-tailors.pages.dev
Branch Preview URL: https://feature-mcp-server-01-founda.app-profile-tailors.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openspec/changes/mcp-server/design.md`:
- Around line 299-307: Update the ApplicationError mapping in
openspec/changes/mcp-server/design.md:299-307 to use the canonical uppercase
codes, including WORKSPACE_ACCESS_DENIED, and align the corresponding documented
error-code names in openspec/changes/mcp-server/spec.md:51-67 and
openspec/changes/mcp-server/specs/mcp-server/spec.md:40-77 with that mapper
contract.
- Around line 256-280: The workspace_context flow must bind and consume each
context before token issuance. Update the Keycloak protocol-mapper behavior
described in the flow to require matching authenticated sub, validate issuer,
audience, and expiration, reject already-consumed jti values, and atomically
record valid jti values as single-use before emitting workspace_id.

In `@openspec/changes/mcp-server/proposal.md`:
- Around line 1-5: Update openspec/changes/mcp-server/proposal.md (lines 1-5),
openspec/changes/mcp-server/design.md (lines 1-5),
openspec/changes/mcp-server/spec.md (lines 1-5),
openspec/changes/mcp-server/specs/mcp-server/spec.md (lines 1-4),
openspec/changes/mcp-server/specs/iam/spec.md (lines 1-4), and
openspec/changes/mcp-server/specs/oauth-mcp-client-registration/spec.md (lines
1-4) to use the mandated section sequence: Overview, Changes, Usage,
Troubleshooting, References; preserve each document’s existing content under the
appropriate sections.
- Line 50: Correct the configuration filename references: in
openspec/changes/mcp-server/proposal.md lines 50-50, replace application.yml
with application.yaml; in openspec/changes/mcp-server/design.md lines 137-137,
update the section label to application.yaml.

In `@openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md`:
- Around line 62-68: Update the “Authentication Failures” requirement and
missing-token scenario to specify the exact RFC 9728 401 contract: require a
WWW-Authenticate header with Bearer realm="mcp" and resource_metadata="<url>",
and state that the referenced Protected Resource Metadata identifies Keycloak.
- Around line 8-19: Update the “Pre-Flow Workspace Injection” requirement to
define replay-resistant validation for signed workspace context or pre-flow
tokens: specify the trusted issuer and signing key, audience, expiry, nonce with
one-time use, and binding to the OAuth client and authorization request. Require
Keycloak to verify all claims and reject invalid, expired, replayed, or
cross-client contexts before emitting workspace_id, while preserving the
existing authorized-workspace requirement.
- Line 3: Restructure the document using the required heading order: Overview,
Changes, Usage, Troubleshooting, and References, replacing the current
Purpose/Requirements structure. Add blank lines before and after every Markdown
heading to satisfy the MD022 requirements, while preserving the existing content
under the appropriate sections.

In `@openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md`:
- Line 328: Add the text language tag to the fenced Keycloak mapper
configuration block in SPIKE_OUTCOME.md, preserving its existing contents so the
Markdown satisfies MD040.
- Around line 443-450: Update the T11 entry in the PR task inheritance table to
reference the existing Section 1.4 instead of nonexistent Section 1.5; do not
add a new section.
- Around line 1-16: Rename openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
to a lowercase kebab-case Markdown filename, update every reference to the
renamed file, and organize its content into Overview, Changes, Usage,
Troubleshooting, and References. In openspec/changes/mcp-server/tasks.md, add or
map the same five required sections; keep both documents in English and follow
the repository documentation rules.
- Around line 371-373: Update the workspace-context flow description near the
SPA JWS forwarding text to call workspace_context a parameter added to
Keycloak’s authorization request, not an authorization request parameter. Align
the validation description with the selected authenticator/session-note
validation path and preserve the existing JWS verification and workspace_id
binding behavior.
- Around line 339-346: Update the workspace context flow around the
`workspaceContext` block so `workspace_id` is never copied from parsed,
unverified input. Have the authenticator validate the JWS using the Profile
Tailors JWKS, issuer, expiry, audience/workspace binding, and replay checks,
then store the validated workspace ID in `session.note`; make the mapper copy
claims only from those verified results.
- Around line 163-179: Record CIMD as experimental in the MCP spike outcome and
status state: update the CIMD section of SPIKE_OUTCOME.md to document Keycloak
26 support behind --features=cimd, remove the unsupported/fallback-only
conclusion, and revise state.yaml’s keycloak_cimd value from
not_supported_fallback_to_preregistered to an experimental status that reflects
feature-gated support.

In `@openspec/changes/mcp-server/tasks.md`:
- Around line 39-40: Update every task heading in the task list, including “Task
1,” to include one blank line before its following list content, resolving the
markdownlint MD022 violations consistently throughout the document.
- Around line 79-87: Align the PR1 gate with the staged implementation: in
openspec/changes/mcp-server/tasks.md lines 79-87, move authenticated Inspector
coverage and full RFC 9728 discovery-header acceptance to PR2/PR3, retaining
only startup, endpoint exposure, and placeholder unauthenticated 401 validation
for PR1; update openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md lines
404-417 to state the same reduced PR1 acceptance criteria.
- Around line 49-57: Update Task 2 in tasks.md and the related MCP
client-registration documentation to use Keycloak’s actual
`/realms/{realm}/clients-registrations/default` endpoint instead of
`/oauth2/register`. If retaining `/oauth2/register`, document concrete
deployment-proxy evidence showing how it maps to the Keycloak endpoint, and
ensure the DCR verification and recorded request/response paths match.

In
`@server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt`:
- Around line 44-45: Update mcpPathMatcher in McpSecurityConfiguration to derive
its patterns from the configured Spring AI MCP endpoint property instead of
hardcoding "/api/mcp" and "/api/mcp/**". Ensure the matcher protects both the
configured endpoint and its subpaths.

In `@server/smp/src/main/resources/application.yaml`:
- Around line 82-87: The MCP configuration in
server/smp/src/main/resources/application.yaml lines 82-87 must enforce a single
canonical resource/audience value: derive mcp.required-audience from
mcp.resource-uri or add startup validation that rejects mismatches. Update
.env.example lines 120-123 to document one canonical environment variable, or
explicitly document the equality requirement and ensure the application
validates it.

In
`@server/smp/src/test/kotlin/com/profiletailors/smp/mcp/infrastructure/McpWiringTest.kt`:
- Around line 103-120: Add mandatory Cucumber BDD coverage for the
unauthenticated POST /api/mcp behavior alongside the existing McpWiringTest.
Create a feature under the test resources features directory and matching BDD
step definitions, tagging the scenario with the MCP domain tag, `@smoke`, and
`@fast`; verify a 401 response with a WWW-Authenticate header beginning with
Bearer.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e94d9216-dedd-4f3f-aae4-92c01936c323

📥 Commits

Reviewing files that changed from the base of the PR and between 8930c37 and a3f2d77.

📒 Files selected for processing (22)
  • .env.example
  • gradle/libs.versions.toml
  • openspec/changes/mcp-server/design.md
  • openspec/changes/mcp-server/proposal.md
  • openspec/changes/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/iam/spec.md
  • openspec/changes/mcp-server/specs/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/oauth-mcp-client-registration/spec.md
  • openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md
  • openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
  • openspec/changes/mcp-server/state.yaml
  • openspec/changes/mcp-server/tasks.md
  • server/smp/build.gradle.kts
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/McpBoundedContext.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/ModuleMetadata.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/application/McpApplicationMarker.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/domain/McpDomainMarker.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpConfiguration.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/oauth/.gitkeep
  • server/smp/src/main/resources/application.yaml
  • server/smp/src/test/kotlin/com/profiletailors/smp/mcp/infrastructure/McpWiringTest.kt

Comment thread openspec/changes/mcp-server/design.md
Comment thread openspec/changes/mcp-server/design.md
Comment thread openspec/changes/mcp-server/proposal.md
Comment thread openspec/changes/mcp-server/proposal.md
Comment thread openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md
Comment thread openspec/changes/mcp-server/tasks.md
Comment thread openspec/changes/mcp-server/tasks.md
Comment thread server/smp/src/main/resources/application.yaml
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.95652% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...smp/mcp/infrastructure/McpSecurityConfiguration.kt 86.36% 0 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

❌ Failed to clone repository into sandbox. Please try again.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 13 file(s) based on 19 unresolved review comments.

Files modified:

  • openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
  • .env.example
  • openspec/changes/mcp-server/design.md
  • openspec/changes/mcp-server/proposal.md
  • openspec/changes/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/iam/spec.md
  • openspec/changes/mcp-server/specs/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/oauth-mcp-client-registration/spec.md
  • openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md
  • openspec/changes/mcp-server/state.yaml
  • openspec/changes/mcp-server/tasks.md
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt
  • server/smp/src/main/resources/application.yaml

Commit: 5c04c4a276da8365786b2540e577f63db63fac32

The changes have been pushed to the feature/mcp-server-01-foundation branch.

Time taken: 15m 54s

@yacosta738
yacosta738 force-pushed the feature/mcp-server-01-foundation branch from 5c04c4a to 7358be1 Compare August 1, 2026 12:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gradle/libs.versions.toml`:
- Line 65: Remove the standalone “Spring AI — MCP server (PR 1)” comment from
the dependency catalog, leaving the following aliases unchanged; do not replace
it unless a concise, English rationale documents a non-obvious dependency
constraint.

In `@openspec/changes/mcp-server/design.md`:
- Around line 256-269: Update the OAuth flow description around the
workspace_context exchange so the signed JWS is never placed in the
authorization URL or other front-channel browser parameters. Replace the direct
workspace_context query parameter with an opaque, single-use context reference
or Pushed Authorization Request, while preserving Keycloak mapper validation and
workspace_id propagation into the token.
- Around line 194-195: Define the security-boundary workspace-access denial
contract: in openspec/changes/mcp-server/design.md lines 194-195, specify that
the access-denied handler returns HTTP 403 with a body containing the canonical
workspace-access error code. In openspec/changes/mcp-server/spec.md lines 51-52
and openspec/changes/mcp-server/specs/mcp-server/spec.md lines 40-41, exclude
pre-dispatch workspace denials from the tool error taxonomy and restrict
ApplicationError failures to post-dispatch tool failures. In
openspec/changes/mcp-server/specs/mcp-server/spec.md lines 63-66, require this
security-boundary 403 response instead of a tool-level CallToolResult.

In `@openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md`:
- Around line 120-161: Align the DCR documentation and tracking with one
verified Keycloak contract: in
openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md:120-161, select the tested
endpoint and make its payload representation consistent; remove the stale
/oauth2/register ownership claim at
openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md:189-191; update Task 2 at
openspec/changes/mcp-server/tasks.md:54-57 and the removed-item table at
openspec/changes/mcp-server/tasks.md:403-411; mark DCR supported in
openspec/changes/mcp-server/state.yaml:21 only after an executable test passes
against that exact endpoint and payload.
- Around line 202-264: Update
openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md:202-264 to remove any
“rfc8707: verified” status and state that verification requires inspecting a
real access token for the MCP URI in aud; retain the audience-mapper fallback
and explicitly limit PR 2 to enforcing the configured app.mcp.resource-uri when
applicable. Update openspec/changes/mcp-server/tasks.md:59-67 so Task 3
acceptance and verification require the same configured-resource-uri scope and
real-token evidence. Update openspec/changes/mcp-server/state.yaml:23 to remove
the verified RFC 8707 status until that evidence exists.
- Around line 349-355: The documented mcp browser flow must define a real
Keycloak authenticator provider rather than a “SPI-free” authenticator. Update
the flow description and implementation guidance to use either a Java
AuthenticatorFactory-based provider or a deployed script provider, and configure
the protocol mapper to read workspace_id from the user session note
(session.note), not user session attributes.

In `@openspec/changes/mcp-server/state.yaml`:
- Line 18: Update the spike_document value in state.yaml to reference the
renamed lowercase kebab-case file, replacing SPIKE_OUTCOME.md with
spike-outcome.md while preserving the existing directory path.

In `@openspec/changes/mcp-server/tasks.md`:
- Around line 95-97: Update the verification tasks in the MCP backend plan to
route all repository checks and Gradle invocations through the appropriate just
recipes instead of direct ./gradlew commands. Apply this consistently to the
TDD, Acceptance, and Verification entries, documenting an approved exception
only where no suitable just recipe exists.
- Around line 319-327: Add a minimal PR1 Cucumber feature for the /api/mcp
endpoint covering endpoint exposure, feature-gate behavior, and unauthenticated
401 responses with the WWW-Authenticate header. Update the relevant BDD task or
feature scope while keeping detailed tool, workspace-isolation, and OAuth
discovery scenarios deferred to PR4.
- Around line 179-187: Keep McpWorkspaceContextResolver and its tests free of
ServerWebExchange, Jwt, and direct RequestContextStore dependencies by moving
HTTP/JWT extraction and context-store writes into an infrastructure adapter.
Pass the validated workspace value through a framework-independent application
port or CQRS boundary, while preserving JWT-derived workspace resolution and
silently ignoring X-Workspace-Id for /api/mcp traffic. Update tests to target
the adapter and application boundary separately.
- Around line 329-337: Update the Task 27 `McpToolsBddSteps.kt` WebTestClient
request configuration for `POST /api/mcp` to use `Accept: application/json,
text/event-stream` and `Content-Type: application/json` when sending JSON-RPC
bodies. Remove the JSON:API media type while preserving the existing
authorization, response capture, database reset, and workspace seeding behavior.

In
`@server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt`:
- Around line 55-79: Replace HttpStatusServerEntryPoint and
PlaceholderWwwAuthenticateFilter with a single ServerAuthenticationEntryPoint
configured in exceptionHandling. Have its commence implementation set the
WWW-Authenticate Bearer realm header before assigning HttpStatus.UNAUTHORIZED
and completing the response, then remove the filter registration and nested
filter class.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1667225e-07ab-4d1b-a293-0d0b5676b4e7

📥 Commits

Reviewing files that changed from the base of the PR and between b328486 and 4f6471f.

📒 Files selected for processing (22)
  • .env.example
  • gradle/libs.versions.toml
  • openspec/changes/mcp-server/design.md
  • openspec/changes/mcp-server/proposal.md
  • openspec/changes/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/iam/spec.md
  • openspec/changes/mcp-server/specs/mcp-server/spec.md
  • openspec/changes/mcp-server/specs/oauth-mcp-client-registration/spec.md
  • openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md
  • openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
  • openspec/changes/mcp-server/state.yaml
  • openspec/changes/mcp-server/tasks.md
  • server/smp/build.gradle.kts
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/McpBoundedContext.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/ModuleMetadata.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/application/McpApplicationMarker.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/domain/McpDomainMarker.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpConfiguration.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt
  • server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/oauth/.gitkeep
  • server/smp/src/main/resources/application.yaml
  • server/smp/src/test/kotlin/com/profiletailors/smp/mcp/infrastructure/McpWiringTest.kt

Comment thread gradle/libs.versions.toml
Comment thread openspec/changes/mcp-server/design.md
Comment thread openspec/changes/mcp-server/design.md
Comment thread openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
Comment thread openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md
Comment thread openspec/changes/mcp-server/tasks.md
Comment thread openspec/changes/mcp-server/tasks.md
Comment thread openspec/changes/mcp-server/tasks.md
Comment thread openspec/changes/mcp-server/tasks.md
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

❌ Failed to clone repository into sandbox. Please try again.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Note

Docstrings generation - SUCCESS
Generated docstrings and committed to branch feature/mcp-server-01-foundation (commit: fcd8117c29c508079d5845543427d10fbadc2631)

@coderabbitai coderabbitai Bot added backend and removed backend labels Aug 2, 2026
yacosta738 and others added 15 commits August 3, 2026 11:39
Slice test proving:
1. The mcp bounded context is registered as a Spring Modulith module.
2. McpConfiguration + McpSecurityConfiguration beans load when
   spring.ai.mcp.server.enabled=true.
3. POST /api/mcp without an Authorization header returns 401 with a
   WWW-Authenticate: Bearer ... header (placeholder contents; the RFC 9728
   resource_metadata URL lands in PR 2 via ResourceMetadataController).

Spring AI's STATELESS WebFlux transport bean is wired automatically by
auto-configuration; no @mcptool beans exist yet so tools/list returns an
empty array (verified via WARN log 'No tool methods found' on startup).

Tagged @tag("postgres"); uses Testcontainers PostgreSQL since the test
boots the full SMP application context. Marked
@testcontainers(disabledWithoutDocker=true) so the test gracefully skips
when Docker is unavailable.
Captures the design decisions and acceptance criteria for the mcp-server
change. Mirrors the stacked-PR strategy (PR1 foundation, PR2 security,
PR3 tools, PR4 verification) and the OAuth split (SMP = Resource Server,
Keycloak = Authorization Server).

These artifacts travel with PR 1 to preserve traceability between design
and implementation.
Docstrings generation was requested by @yacosta738.

The following files were modified:

* `server/smp/src/main/kotlin/com/profiletailors/smp/mcp/infrastructure/McpSecurityConfiguration.kt`

These files were ignored:
* `server/smp/src/test/kotlin/com/profiletailors/smp/mcp/infrastructure/McpWiringTest.kt`

These file types are not supported:
* `.env.example`
* `gradle/libs.versions.toml`
* `openspec/changes/mcp-server/design.md`
* `openspec/changes/mcp-server/proposal.md`
* `openspec/changes/mcp-server/spec.md`
* `openspec/changes/mcp-server/specs/iam/spec.md`
* `openspec/changes/mcp-server/specs/mcp-server/spec.md`
* `openspec/changes/mcp-server/specs/oauth-mcp-client-registration/spec.md`
* `openspec/changes/mcp-server/specs/workspace-scoped-oauth/spec.md`
* `openspec/changes/mcp-server/spikes/SPIKE_OUTCOME.md`
* `openspec/changes/mcp-server/state.yaml`
* `openspec/changes/mcp-server/tasks.md`
* `server/smp/src/main/resources/application.yaml`
The listing query uses a 30-day forward window. Hardcoded dates far in
the future fell outside this range, causing 'expected 2 but was 1' in
the List scenario. Now seeds and feature files use relative offsets
(+7days, +14days) resolved at runtime.
@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@yacosta738
yacosta738 merged commit 2895992 into main Aug 3, 2026
42 checks passed
@yacosta738
yacosta738 deleted the feature/mcp-server-01-foundation branch August 3, 2026 13:27
@dallay-bot dallay-bot Bot mentioned this pull request Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:backend Changes in backend code (server/smp/** or shared/**) area:docs Documentation changes (docs/**, *.md, *.mdx) type:chore Code maintenance and configuration changes type:dependency Dependency updates (Renovate or manual) type:test Test files or test infrastructure changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants