Skip to content

MCP OAuth auth fails when server allows anonymous initialization #2123

Description

@baronfel

Summary

netclaw mcp auth <server> fails for Google Workspace MCP servers when the server permits unauthenticated MCP initialization and catalog discovery.

Instead of opening an OAuth authorization URL, Netclaw initializes the candidate connection, discovers the tools, then calls McpOAuthFlowBroker.BeginCommit. Because no OAuth callback occurred and no authorization code was delivered, TryBeginCommit rejects the flow with:

Authorization can no longer publish. Start a new MCP authorization attempt.

The CLI then reports only:

Starting OAuth authorization for 'google-docs'...
Error: MCP OAuth connection initialization failed. Check daemon logs for details.

This was reproduced with both Google Docs and Google Drive MCP servers, so it appears to be a generic explicit-reauthorization lifecycle issue rather than a Docs-specific failure.

Environment

netclaw 0.27.0-beta.2
commit 124f7a1263214f55c10ce01dbf422dfe96e93a0f
Windows / PowerShell 7

netclaw update reports this as the current release.

Configuration shape

Google Docs:

Transport: http
URL: https://docsmcp.googleapis.com/mcp/v1
OAuthClientId: configured
OAuthScope: https://www.googleapis.com/auth/documents https://www.googleapis.com/auth/documents.readonly

Google Drive is similarly configured with https://drivemcp.googleapis.com/mcp/v1 and the same pre-registered client ID.

Both servers report connected before explicit authorization:

google-docs   connected (2 tools)
google-drive  connected (8 tools)

Reproduction

  1. Configure either Google Workspace MCP endpoint as an HTTP server with OAuthClientId.

  2. Start Netclaw. The server connects and its tool catalog is discovered.

  3. Run:

    netclaw mcp auth google-docs
    
  4. Observe that no browser authorization flow starts and the CLI reports connection initialization failure.

  5. The same result occurs with:

    netclaw mcp auth google-drive
    

Daemon log

MCP server 'google-docs' does not declare catalog notification support; catalog polling remains active
MCP server 'google-docs' exposes 2 tool(s) not granted to any audience: read_doc, update_doc.
MCP server 'google-docs' replacement failed; generation 1 remains connected
Netclaw.Daemon.Mcp.McpOAuthOperationException: Authorization can no longer publish. Start a new MCP authorization attempt.
   at Netclaw.Daemon.Mcp.McpOAuthFlowBroker.BeginCommit(McpOAuthFlow flow)
   at Netclaw.Daemon.Mcp.McpClientManager.BuildAndPublishCandidateAsync(...)

Explicit MCP OAuth candidate failed for server 'google-docs' during connection initialization (provider status (null))

Root cause analysis

In the installed source, BuildAndPublishCandidateAsync performs the following sequence:

  1. Creates the OAuth-enabled MCP client.
  2. Initializes the connection and reads the tool/prompt catalogs.
  3. Calls _flowBroker.BeginCommit(authorizationFlow).

Source: McpClientManager.cs.

TryBeginCommit requires _codeDelivered == true. That flag is set only when the local OAuth callback delivers an authorization code.

Source: McpOAuthFlowBroker.cs and TryBeginCommit.

Google's MCP endpoint permits initialization/catalog discovery without first producing an OAuth challenge. Consequently, the SDK never invokes the interactive authorization callback, _codeDelivered remains false, and BeginCommit rejects the otherwise successfully initialized candidate.

Google interoperability gaps discovered during diagnosis

These are related and may warrant either inclusion in this fix or separate issues.

Pre-registered client secret cannot be configured

Google documents creating a Web application OAuth client and configuring both its client ID and client secret for the Google Docs MCP server:

https://developers.google.com/workspace/docs/api/guides/configure-mcp-server#configure-mcp-client

McpServerEntry currently exposes OAuthClientId but no configured OAuth client-secret field:

https://github.com/netclaw-dev/netclaw/blob/124f7a1263214f55c10ce01dbf422dfe96e93a0f/src/Netclaw.Configuration/McpServerEntry.cs

Moreover, when OAuthClientId is configured, BuildOAuthOptions explicitly supplies a null client secret:

ClientId = entry.OAuthClientId ?? identity.ClientId,
ClientSecret = entry.OAuthClientId is null ? identity.ClientSecret : null,

Source:

private ClientOAuthOptions BuildOAuthOptions(
McpServerEntry entry,
McpOAuthTokenCache cache,
McpOAuthFlow? authorizationFlow)
{
var identity = _credentialStore.GetIdentity(cache);
return new ClientOAuthOptions
{
RedirectUri = BuildRedirectUri(),
ClientId = entry.OAuthClientId ?? identity.ClientId,
ClientSecret = entry.OAuthClientId is null ? identity.ClientSecret : null,
Scopes = ParseScopes(entry.OAuthScope),
TokenCache = cache,
AuthorizationCallbackHandler = CreateAuthorizationCallbackHandler(authorizationFlow),
// DynamicClientRegistration is deliberately left unset. McpOAuthClientRegistrar
// owns registration because the SDK hard-codes client_secret_post and cannot
// register against public-client-only servers (csharp-sdk#1611). A non-null
// ClientId here short-circuits the SDK's registration path entirely.
};

This means Netclaw cannot currently represent Google's documented confidential-client configuration.

Redirect URI

Netclaw uses:

http://127.0.0.1:<daemon-port>/api/mcp/oauth/callback

Source:

private Uri BuildRedirectUri()
=> new($"http://127.0.0.1:{_daemonConfig.Port}/api/mcp/oauth/callback");

That exact URI must be added to the Google Web application's authorized redirect URIs.

Documented scopes

Google currently documents four scopes for Docs MCP:

https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/documents.readonly
https://www.googleapis.com/auth/documents

Source: https://developers.google.com/workspace/docs/api/guides/configure-mcp-server#configure-consent-screen

The missing Drive scopes do not cause the immediate BeginCommit failure, but may affect document discovery/access after OAuth succeeds.

Expected behavior

netclaw mcp auth should proactively perform OAuth discovery and produce an authorization request even when MCP initialization/catalog discovery succeeds anonymously. It should not treat successful anonymous initialization as completion of an explicit authorization attempt.

For Google Workspace compatibility, a pre-registered confidential client should also support securely configured client-secret material.

Suggested acceptance criteria

  • Explicit authorization opens/prints an OAuth authorization URL when the protected resource requires OAuth, even if MCP initialization succeeds without a challenge.
  • Candidate publication occurs only after the explicit flow has delivered and exchanged an authorization code.
  • Reauthorization works when the currently published generation remains connected.
  • Google Docs and Google Drive MCP endpoints complete authentication successfully.
  • Pre-registered OAuth clients can securely provide both client ID and client secret where required.
  • Regression coverage includes an MCP endpoint that allows anonymous initialization/catalog discovery but requires OAuth for protected operations.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpModel context protocol server / client issues.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions