Tencent/WeKnora · error

principal context is required to connect to OAuth MCP servic

Error message

principal context is required to connect to OAuth MCP service %s

What it means

For OAuth-enabled MCP services, GetOrCreateClient requires a valid principal in the request context (from types.PrincipalFromContext / MCPOAuthPrincipalFromContext) so each identity can use its own token. If the principal is missing or invalid (Principal.Valid() == false), it returns "principal context is required to connect to OAuth MCP service %s".

Source

Thrown at internal/mcp/manager.go:76

func (m *MCPManager) GetOrCreateClient(ctx context.Context, service *types.MCPService) (MCPClient, error) {
	// Check if service is enabled
	if !service.Enabled {
		return nil, fmt.Errorf("MCP service %s is not enabled", service.Name)
	}

	// Stdio transport is disabled for security reasons
	if service.TransportType == types.MCPTransportStdio {
		return nil, fmt.Errorf("stdio transport is disabled for security reasons; please use SSE or HTTP Streamable transport instead")
	}

	var tenantID uint64
	var principal types.Principal
	if service.AuthConfig.IsOAuth() {
		tenantID, _ = types.TenantIDFromContext(ctx)
		principal, _ = types.PrincipalFromContext(ctx)
		principal = types.MCPOAuthPrincipalFromContext(ctx)
		if !principal.Valid() {
			return nil, fmt.Errorf("principal context is required to connect to OAuth MCP service %s", service.Name)
		}
	}
	key := cacheKey(service, principal)

	// For SSE/HTTP Streamable, check if client already exists and reuse
	m.clientsMu.RLock()
	client, exists := m.clients[key]
	m.clientsMu.RUnlock()

	if exists && client.IsConnected() {
		return client, nil
	}

	// Create new client
	m.clientsMu.Lock()
	defer m.clientsMu.Unlock()

	// Double check after acquiring write lock

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Ensure the request context passes through the auth middleware that injects the principal before MCP calls
  2. Use types.WithPrincipal (or the equivalent context helper) to attach a valid types.Principal to the context
  3. If no user context exists (system job), connect as a designated service principal instead

Example fix

// before
client, err := manager.GetOrCreateClient(context.Background(), oauthSvc)
// after
ctx := types.WithPrincipal(context.Background(), principal) // principal from auth/session
client, err := manager.GetOrCreateClient(ctx, oauthSvc)
Defensive patterns

Strategy: validation

Validate before calling

principal, _ := types.PrincipalFromContext(ctx)
if !principal.Valid() {
    return errors.New("request context lacks a valid principal; required for OAuth MCP services")
}

Type guard

func hasPrincipal(ctx context.Context) bool {
    p, _ := types.PrincipalFromContext(ctx)
    return p.Valid()
}

Try / catch

client, err := manager.GetOrCreateClient(ctx, svc)
if err != nil && strings.Contains(err.Error(), "principal context is required") {
    return fmt.Errorf("attach authenticated principal to ctx before using OAuth service %q", svc.Name)
}

Prevention

When it happens

Trigger: Calling GetOrCreateClient (or GetMCPServiceTools/Resources) with a context lacking the principal when service.AuthConfig.IsOAuth() is true — e.g. background jobs, webhook handlers, or code paths that build a bare context.Background() without auth middleware.

Common situations: Calling MCP tools from a cron/worker goroutine where auth middleware never ran; forgetting to inject the principal after extracting a tenant ID; a test constructing ctx without the principal helper.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/cfaf527efb468da3. Report an issue: GitHub.