googleapis/mcp-toolbox · error

error in User Agent retrieval

Error message

error in User Agent retrieval: %s

What it means

Serverless Spark source Initialize first extracts a user agent string from the incoming context via util.UserAgentFromContext. If the context does not carry a valid user agent (missing or malformed), initialization fails before creating any Dataproc clients. This is a context/metadata plumbing error, not a network error.

Solutions

  1. Create the source through the normal toolbox server request path so the user agent metadata is injected into the context.
  2. If calling Initialize directly (tests/custom code), add the expected user agent to the context the way the server does (check util.UserAgentFromContext for the metadata key/format).
  3. Ensure clients send a non-empty, well-formed User-Agent header.
  4. Check the toolbox version for changes in the user agent contract between client and server.

Example fix

// before (direct init in test)
src, err := cfg.Initialize(ctx, tracer) // ctx has no user agent
// after
ctx = metadata.AppendToOutgoingContext(ctx, "user-agent", "opencode/1.0")
src, err := cfg.Initialize(ctx, tracer)
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the user agent is present in the outgoing context before source init
ua, err := util.UserAgentFromContext(ctx)
if err != nil || ua == "" {
    return fmt.Errorf("user agent missing from context: %w", err)
}

Try / catch

src, err := cfg.Initialize(ctx, tracer)
if err != nil {
    if strings.Contains(err.Error(), "User Agent") {
        // re-init with a context carrying the user agent metadata
        ctx = util.NewContextWithUserAgent(ctx, "my-client/1.0")
        src, err = cfg.Initialize(ctx, tracer)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: Config.Initialize runs util.UserAgentFromContext(ctx); the error branch fires when the context lacks the user agent header/metadata that the utility requires, or the metadata value fails the utility's parsing/format checks.

Common situations: Invoking the source programmatically with a bare context.Context instead of going through the toolbox server, which injects the user agent; constructing the source in unit tests without the expected metadata key; a client sending an empty or malformed User-Agent header.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/1830f037f4e6eaff. Report an issue: GitHub.

Appendix: source

Thrown at internal/sources/serverlessspark/serverlessspark.go:70

	}
	return actual, nil
}

type Config struct {
	Name     string `yaml:"name" validate:"required"`
	Type     string `yaml:"type" validate:"required"`
	Project  string `yaml:"project" validate:"required"`
	Location string `yaml:"location" validate:"required"`
}

func (r Config) SourceConfigType() string {
	return SourceType
}

func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
	ua, err := util.UserAgentFromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("error in User Agent retrieval: %s", err)
	}
	endpoint := fmt.Sprintf("%s-dataproc.googleapis.com:443", r.Location)
	batchClient, err := dataproc.NewBatchControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))
	if err != nil {
		return nil, fmt.Errorf("failed to create dataproc batch client: %w", err)
	}
	sessionTemplateClient, err := dataproc.NewSessionTemplateControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))
	if err != nil {
		batchClient.Close()
		return nil, fmt.Errorf("failed to create dataproc session template client: %w", err)
	}
	opsClient, err := longrunning.NewOperationsClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))
	if err != nil {
		batchClient.Close()
		sessionTemplateClient.Close()
		return nil, fmt.Errorf("failed to create longrunning client: %w", err)
	}
	sessionClient, err := dataproc.NewSessionControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))

View on GitHub (pinned to 8cc6e09de2)