Skip to content

Conversation

@technicalpickles
Copy link
Contributor

@technicalpickles technicalpickles commented Dec 10, 2025

Summary

Enable automatic detection of the RFC 8707 resource parameter from RFC 9728 Protected Resource Metadata, eliminating manual extra_params configuration for OAuth flows with providers like Runlayer/AnySource.

Related: #165 (zero-config-oauth branch work)

Problem

Runlayer/AnySource OAuth servers require the RFC 8707 resource parameter:

{"detail":[{"type":"missing","loc":["query","resource"],"msg":"Field required","input":null}]}

Previously users had to manually configure this:

{
  "oauth": {
    "extra_params": {
      "resource": "https://oauth.runlayer.com/api/v1/proxy/UUID/mcp"
    }
  }
}

Solution

Auto-detect resource from Protected Resource Metadata and inject it into:

  1. OAuth authorization URL (query parameter)
  2. Token exchange requests (form body)
  3. Token refresh requests (form body)

After this PR (zero configuration):

{
  "name": "slack",
  "url": "https://oauth.runlayer.com/api/v1/proxy/UUID/mcp"
}

Implementation

  1. Discovery Layer: Added DiscoverProtectedResourceMetadata() returning full RFC 9728 struct
  2. Config Layer: Added CreateOAuthConfigWithExtraParams() returning extraParams with auto-detected resource
  3. Connection Layer: Inject params into auth URL after mcp-go constructs it
  4. Fallback: Use server URL as resource if metadata unavailable
  5. Override: Manual extra_params takes precedence over auto-detected values
  6. Diagnostics: mcpproxy auth status and mcpproxy doctor show resource detection status

Key Changes

  • internal/oauth/discovery.go - Added DiscoverProtectedResourceMetadata()
  • internal/oauth/config.go - Added CreateOAuthConfigWithExtraParams() and autoDetectResource()
  • internal/upstream/core/connection.go - Updated OAuth flow call sites to use new API
  • cmd/mcpproxy/auth_cmd.go - Added resource display to auth status
  • internal/management/diagnostics.go - Updated doctor resolution message
  • CLAUDE.md - Added zero-config OAuth documentation section

Planning Artifacts

Status

  • Specification complete
  • Implementation plan complete
  • Implementation complete (all 4 user stories)
  • Unit tests
  • E2E test with mock OAuth server
  • Documentation updates (CLAUDE.md)
  • Real-world validation with Runlayer/AnySource servers

Test Plan

  • Unit tests for DiscoverProtectedResourceMetadata() - discovery_test.go
  • Unit tests for resource auto-detection in CreateOAuthConfig() - config_test.go
  • E2E test with mock OAuth server requiring resource parameter - e2e_oauth_zero_config_test.go
  • Manual test with Runlayer/AnySource servers (slack, gcal, gdrive, etc.)
  • Linter clean (./scripts/run-linter.sh)
  • Full test suite passes (./scripts/run-all-tests.sh)

Related smart-mcp-proxy#165

Add comprehensive specification and implementation plan for automatic
detection of the RFC 8707 resource parameter in OAuth flows. This enables
zero-config OAuth for providers like Runlayer that require the resource
parameter.

Artifacts:
- spec.md: Feature specification with user stories and requirements
- plan.md: Implementation plan with technical context
- research.md: Technical research and implementation approach
- data-model.md: Entity definitions and state transitions
- quickstart.md: Usage guide and troubleshooting
- checklists/requirements.md: Specification quality checklist

Key Decisions:
- Extract resource from RFC 9728 Protected Resource Metadata
- Fallback to server URL if metadata unavailable
- Inject params into auth URL after mcp-go constructs it
- Manual extra_params override auto-detected values
@technicalpickles
Copy link
Contributor Author

I'm starting this early for visibilty while I work on it cc @Dumbris

Going to close #165 in favor for this

Related smart-mcp-proxy#165

Add structured task list with 39 tasks organized by user story:
- Phase 1: Setup (1 task)
- Phase 2: Foundational - discovery layer (5 tasks)
- Phase 3: US1 - Zero-config auto-detection (15 tasks) - MVP
- Phase 4: US2 - Manual override (6 tasks)
- Phase 5: US3 - Token injection (4 tasks)
- Phase 6: US4 - Diagnostic visibility (3 tasks)
- Phase 7: Polish (5 tasks)

Tasks follow TDD approach per constitution requirements.
…ection

Related smart-mcp-proxy#165

Add new function that returns the full RFC 9728 Protected Resource Metadata
struct including the 'resource' field needed for RFC 8707 compliance.
Refactor DiscoverScopesFromProtectedResource to delegate to new function.

Changes:
- Add DiscoverProtectedResourceMetadata() returning *ProtectedResourceMetadata
- Refactor DiscoverScopesFromProtectedResource() as wrapper for backward compat
- Add comprehensive unit tests for new function

Testing:
- All TestDiscoverProtectedResourceMetadata_* tests pass
- Existing DiscoverScopesFromProtectedResource tests still pass
Add automatic detection of RFC 8707 resource parameter from Protected
Resource Metadata (RFC 9728). This enables zero-config OAuth with
providers like Runlayer that require the resource parameter.

Key changes:
- Add CreateOAuthConfigWithExtraParams() that returns both OAuth config
  and auto-detected extra params including resource
- Add autoDetectResource() helper that:
  - Makes preflight HEAD request to get WWW-Authenticate header
  - Extracts resource_metadata URL
  - Fetches Protected Resource Metadata
  - Uses metadata.resource or falls back to server URL
- Update handleOAuthAuthorization() to accept extraParams and inject
  them into authorization URL
- Update all 6 call sites to use new function and pass extraParams

Tests:
- TestCreateOAuthConfig_AutoDetectsResource: verifies resource extraction
- TestCreateOAuthConfig_FallsBackToServerURL: verifies fallback behavior
- E2E tests in e2e_oauth_zero_config_test.go

Part of smart-mcp-proxy#165 (RFC 8707 resource auto-detection for zero-config OAuth)
Tests verify that:
- T022: Manual extra_params.resource overrides auto-detected value
- T023: Manual extra_params are preserved while resource is auto-detected

Implementation was already complete from US1:
- T024-T026: Merge logic and logging in CreateOAuthConfigWithExtraParams

All tests pass: go test ./internal/oauth/... -v -run TestCreateOAuthConfig
Enable auto-detected resource parameter injection into token requests:
- T029: OAuthTransportWrapper.injectFormParams() handles token exchange/refresh
- T030: createOAuthConfigInternal() accepts extraParams for wrapper injection
- T031: Existing TestInjectFormParams_TokenRequest covers token request injection

Key changes:
- CreateOAuthConfig() now delegates to createOAuthConfigInternal()
- CreateOAuthConfigWithExtraParams() passes auto-detected params to internal fn
- Transport wrapper uses passed extraParams instead of re-reading from config

This ensures zero-config OAuth flows inject resource into all OAuth requests:
- Authorization URL (via handleOAuthAuthorization)
- Token exchange (via transport wrapper)
- Token refresh (via transport wrapper)
MCP spec only requires POST support for the main endpoint. Use POST
directly for the preflight request to get WWW-Authenticate header
with resource_metadata URL.

Updated all tests to use POST method in mock handlers.
@technicalpickles technicalpickles marked this pull request as ready for review December 10, 2025 16:39
@technicalpickles
Copy link
Contributor Author

Tested and verified working with Runlayer/AnySource MCP servers (slack, gcal, gdrive, gsheets, gmail, glean). Resource parameter is auto-detected from RFC 9728 Protected Resource Metadata and correctly injected into OAuth flows - no manual extra_params.resource configuration needed.

@Dumbris
Copy link
Contributor

Dumbris commented Dec 11, 2025

@technicalpickles Thanks for looping me in early on this.
Great contribution - the zero-config OAuth is a nice UX win. Code looks solid, tests are good. Nice push! 🚀
Merging as-is.

@Dumbris Dumbris merged commit 6ccc07c into smart-mcp-proxy:main Dec 11, 2025
22 checks passed
@technicalpickles technicalpickles deleted the 011-resource-auto-detect branch December 11, 2025 12:47
@technicalpickles
Copy link
Contributor Author

@Dumbris thank you! would you mind cutting a release with it included? I'd love to share this with my coworkers also using runlayer/anysource.

@Dumbris
Copy link
Contributor

Dumbris commented Dec 11, 2025

@technicalpickles the release is now published https://github.com/smart-mcp-proxy/mcpproxy-go/releases/tag/v0.10.12
I haven’t tested it extensively yet, so feedback is welcome

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.

2 participants