Feature Request: OAuth Authentication Support for MCP Registry Queries
Feature Request: OAuth Authentication Support for MCP Registry Queries
Summary
Add OAuth authentication support for MCP (Model Context Protocol) registry queries to enable organizations to deploy private, authenticated MCP server registries
Problem Statement
Currently, VS Code's MCP client does not implement OAuth authentication flows when querying MCP registries for server discovery. This prevents organizations from deploying OAuth-protected MCP registries for internal use as specified by RFC 9728 (OAuth 2.0 Protected Resource Metadata).
Current Behavior (What VS Code Does Today)
When VS Code queries an OAuth-protected registry, it makes a single unauthenticated request and stops after receiving 401:
GET /v0.1/servers?limit=50 HTTP/2
Host: internal-registry.company.com
User-Agent: VSCode/1.95.0
Accept: application/json
# ❌ No Authorization header
Registry Response:
HTTP/2 401 Unauthorized
WWW-Authenticate: Bearer realm="MCP Registry",
resource="https://internal-registry.company.com",
resource_metadata="https://internal-registry.company.com/.well-known/oauth-protected-resource"
VS Code Behavior:
- ❌ Logs error: "Server returned 401"
- ❌ Does not parse
WWW-Authenticateheader - ❌ Does not fetch OAuth metadata
- ❌ Does not retry with authentication
- ❌ User sees no servers in MCP registry
Desired Behavior (RFC 9728 OAuth Flow)
To support OAuth-protected registries, VS Code could implement the standard OAuth Protected Resource discovery flow:
Step 1: Initial Request (No Token)
GET /v0.1/servers?limit=50 HTTP/2
Host: internal-registry.company.com
User-Agent: VSCode/1.95.0
Step 2: Parse 401 Response and Fetch Metadata
GET /.well-known/oauth-protected-resource HTTP/2
Host: internal-registry.company.com
Response:
{
"resource": "https://internal-registry.company.com",
"authorization_servers": ["https://login.microsoftonline.com/.../v2.0"],
"scopes_supported": ["mcpregistry.read"],
"bearer_methods_supported": ["header"]
}
Step 3: Acquire Token and Retry
GET /v0.1/servers?limit=50 HTTP/2
Host: internal-registry.company.com
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGci...
User-Agent: VSCode/1.95.0
Response: HTTP/2 200 OK
{
"servers": [ /* server list */ ]
}
✅ User sees servers from authenticated registry
Use Case
Enterprise Scenario
Organizations want to:
- Deploy internal MCP registries with curated, approved MCP servers
- Restrict access to organization members only (Azure AD, Okta, etc.)
- Use GitHub Copilot's "Registry only" policy to enforce approved tools
- Maintain audit trails of who accesses which servers
Current Blocker: OAuth-protected registries cannot be used with VS Code because the client doesn't authenticate registry queries.
Technical Context
OAuth Standards for Protected Resources
RFC 9728 (OAuth 2.0 Protected Resource Metadata) is the standard way for OAuth-protected HTTP APIs to advertise their authentication requirements. While the MCP Authorization specification mandates RFC 9728 for MCP servers (the tools/execution layer), it would be good to be able to apply this for registries too.
RFC 9728 defines a discovery flow:
- Protected endpoints return
401 UnauthorizedwithWWW-Authenticateheader - Header includes
resource_metadataparameter pointing to/.well-known/oauth-protected-resource - Clients fetch OAuth metadata from that endpoint
- Clients acquire token from the authorization server
- Clients retry request with
Authorization: Bearer <token>
Our Implementation
We adopted RFC 9728 for our MCP registry to test if VS Code would work with OAuth-protected registries. Our implementation follows the standard OAuth discovery flow:
- ✅ Registry returns
401withWWW-Authenticate: Bearer resource_metadata="..." - ✅ Metadata endpoint (
/.well-known/oauth-protected-resource) returns valid OAuth configuration - ✅ Token validation works correctly when
Authorization: Bearer <token>is provided - ✅ All responses follow RFC 7807 Problem Details format
Verification: Our registry is RFC 9728 compliant and works correctly when tested with curl/PowerShell. However, VS Code's MCP client does not implement RFC 9728 OAuth discovery for registry queries.
Current Architecture Gap
VS Code's MCP client distinguishes between:
-
Registry/Gallery Queries (server discovery) - ❌ No OAuth support
- Used to fetch server metadata from registries
- Does NOT send custom headers from
mcp.json - Assumes registries are public endpoints (as far as I can see!)
-
MCP Server Connections (tool execution) - ✅ OAuth support exists
- Used to connect to individual MCP servers
- DOES send custom headers from
mcp.json - OAuth authentication works correctly
Organizations need OAuth for both scenarios.
Evidence
Server Logs (OAuth-Protected Registry)
[10:21:10 INF] Request starting HTTP/2 GET https://localhost:5001/v0.1/servers?limit=50
[10:21:10 INF] Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
[10:21:10 INF] API Request: GET /v0.1/servers?limit=50 -> 401 | User: anonymous | Tenant: N/A
Indicator: User: anonymous confirms no bearer token received.
VS Code Error
2025-12-10 10:21:10.428 [error] [Window] Server returned 401: Error: Server returned 401
Working Verification (Direct API Access)
# Same registry works perfectly with OAuth when called directly
$token = az account get-access-token --resource "api://..." --query accessToken -o tsv
$headers = @{ Authorization = "Bearer $token" }
Invoke-WebRequest -Uri "https://localhost:5001/v0.1/servers" -Headers $headers
# Result: 200 OK with server data ✅
Proposed Solution
I could imagine a couple of solutions
Option 1: Static Token Support (Simpler)
Allow users to configure bearer tokens for registry authentication in mcp.json:
{
"registries": [
{
"url": "https://internal-registry.company.com",
"headers": {
"Authorization": "Bearer <token>"
}
}
]
}
This would enable basic authentication but requires users to manually manage token refresh.
Option 2: Full RFC 9728 OAuth Flow (Preferred)
Implement the standard OAuth discovery flow for registry queries:
- VS Code queries registry without token
- Registry returns
401withWWW-Authenticate: Bearer resource_metadata="..." - VS Code fetches OAuth metadata from
/.well-known/oauth-protected-resource - VS Code redirects user to authorization server for authentication
- VS Code retries request with acquired token
This is the most desirable approach as it provides seamless authentication with automatic token refresh, following the same OAuth flow already supported for MCP server connections. Users would be redirected to their organization's authentication provider (Azure AD for instance) and tokens would be managed automatically.
Workarounds (Current)
Organizations currently must choose between:
- Deploy public (unauthenticated) registries - Security risk
- Use local proxy to add auth headers - Additional complexity
- Implement Gateway pattern - Transform registry into MCP gateway (high effort, different architecture)
- Wait for this feature - Blocks registry adoption
None of these workarounds are ideal for enterprise scenarios.
Impact
Who Benefits
- Enterprise organizations deploying internal MCP registries
- Organizations using GitHub Copilot with "Registry only" policy
- Security teams requiring authentication and audit trails
- Any organization with compliance requirements (GDPR, SOC2, etc.)
Related Projects
The MCP Gateway Registry project implements OAuth for MCP servers using a Gateway pattern (transforming the registry into an MCP server itself) as a workaround for this limitation.
I agree in principle that OAuth auth support for MCP Registries would be nice, but we only want to do something here when the MCP Spec calls out that MCP Registries can be behind auth. Otherwise we are going off-spec.
@TylerLeonhardt thanks for getting back to me. Looks like I should be raising something similar here first then! https://github.com/modelcontextprotocol/modelcontextprotocol