Skip to content

bug: Looker type:unquoted parameter values containing _ or % are rejected as wildcard patterns #3288

@anandnalya

Description

@anandnalya

Prerequisites

  • I've searched the current open issues
  • I've updated to the latest version of Toolbox

Toolbox version

Built from main (module github.com/googleapis/mcp-toolbox); the affected code path is unchanged on the latest release and the quote-stripping fix from #3273 does not address this case.

Environment

  1. OS type and version: macOS (Darwin); reproducible on any platform — the bug is in filter-expression encoding, not OS-specific.
  2. How are you running Toolbox: Compiled from source (go build).

Client

  1. Client: MCP client driving the Looker tools (e.g. an LLM-backed MCP host).
  2. Version: n/a — any client that passes a bare type: unquoted allowed_value containing _, %, or , triggers it.
  3. Example filter payload that triggers the bug:
{"cohort_marketing_performance.attribution_model_selector": "first_touch"}

Expected Behavior

When a looker-query (or any tool that goes through the shared lookercommon.ProcessQueryArgs helper) filters on a LookML parameter field declared type: unquoted, the bare allowed_value (e.g. first_touch) should reach Looker so it is substituted into SQL exactly as written. This matches the URL form that works in the Looker UI and the documented allowed_value semantics in LookML.

Current Behavior

Looker's filter-expression parser treats _ as a single-character wildcard and % as a multi-character wildcard. For type: unquoted parameters the substituted SQL must match [A-Za-z0-9_.$] literally, so the parser expands first_touch into a wildcard pattern, finds non-identifier characters in the result, and 400s with:

The filter "first_touch" is not allowed.
Filter on unquoted field <field> must contain only underscores, numbers, letters

Same failure for signup_date, paid_social, and any other allowed_value that contains _, %, or ,. PR #3273 fixed the wrapping-quote case but the value still reaches Looker un-escaped, so identifiers containing _ continue to fail.

Looker's own default_filter_value is stored already escaped (first^_touch), which confirms that filter-expression escape — not bare allowed_value — is the correct wire format for the /queries/run API. The explore URL parser used by the UI applies different escaping rules, which is why the same value works in the browser and 400s through the API.

Affects every tool built on the shared helper: looker-query, looker-query-sql, looker-query-url, looker-make-look, and looker-add-dashboard-element.

Steps to reproduce?

  1. Define a LookML parameter field with type: unquoted and an allowed_value whose value contains _ (e.g. first_touch).
  2. Run a looker-query against the explore with a bare filter value: {"view.field": "first_touch"}.
  3. Looker returns 400 The filter "first_touch" is not allowed. instead of substituting first_touch into the SQL.

Additional Details

Proposed fix: in internal/tools/looker/lookercommon/lookercommon.go, add a helper that fetches the explore's parameter metadata via sdk.LookmlModelExplore and escapes ^/_/%/, with a ^ prefix in any filter value targeting a type: unquoted parameter. Idempotent — values containing ^ are assumed pre-escaped and pass through unchanged, so callers can keep using the raw default_filter_value form. Metadata-lookup failures degrade to a no-op so users without explore-read permission still get non-parameter queries through. Wire into all five WriteQuery-building tools. Unit tests cover escape, idempotence, mixed filters, non-string values, and the nil/empty guards. End-to-end-verified against the live Looker API. Happy to send a PR.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions