MCP Configuration for Looker with Codex Google Cloud has published a guide for configuring OpenAI's Codex CLI to work with Looker over the Model Context Protocol (MCP), marking the third iteration of the same integration approach previously demonstrated with Gemini CLI, Antigravity CLI, and Claude Code. The setup leverages Google's MCP Toolbox and Google Skills repository to connect the business intelligence platform to Codex, with the Looker side of the stack remaining unchanged across all client variations. This article covers the MCP setup and configuration for using Looker with Codex to enhance and extend Looker operations over MCP. This paper is the third pass at the same idea. The original used Gemini CLI: MCP Configuration for Looker with Gemini CLI https://medium.com/google-cloud/mcp-configuration-for-looker-with-gemini-cli-55e5671197fb then Antigravity CLI: MCP Configuration for Looker with Antigravity CLI https://dev.to/gde/mcp-configuration-for-looker-with-antigravity-cli-504d then Claude Code: MCP Configuration for Looker with Claude Code https://dev.to/gde/mcp-configuration-for-looker-with-claude-code-21jh In this updated version, Codex is used to integrate Looker functionality. The Looker side of the stack does not change at all — that is the whole point of MCP. What changes is the client: how the server gets registered, how tool calls get approved, and where the agent reads its project instructions from. Looker is a cloud-based business intelligence BI and data analytics platform owned by Google Cloud that enables organizations to analyze, visualize, and share data in real-time. It uses a unique modeling language called LookML to define data relationships, offering a centralized “single source of truth” for metrics. Looker focuses on embedded analytics and live data exploration rather than storing data itself. More information is available here: Looker business intelligence platform embedded analytics https://cloud.google.com/looker Semantic layer is where all the cool kids hang out. Unless you have been living off grid without Internet- MCP is the new universal connector and next “Big Thing”. More information is here: What is Model Context Protocol MCP ? A guide https://cloud.google.com/discover/what-is-model-context-protocol Google has gone all-in for all the core Cloud services to provide connections over MCP. An overview is here: Google Cloud MCP servers overview | Google Cloud Documentation https://docs.cloud.google.com/mcp/overview MCP Toolbox is the “swiss army” knife that connects your data sources to MCP. Use Looker with MCP, Gemini CLI and other Agents | Google Cloud Documentation https://docs.cloud.google.com/looker/docs/connect-ide-to-looker-using-mcp-toolbox For a more detailed step by step setup instructions — there is a full codelab that goes through the setup: Connect Gemini CLI to Looker with MCP Toolbox | Google Codelabs https://codelabs.developers.google.com/codelabs/looker-mcp-toolbox 0 and a further deep dive is here: Use Looker with MCP, Gemini CLI and other Agents | Google Cloud Documentation https://docs.cloud.google.com/looker/docs/connect-ide-to-looker-using-mcp-toolbox Codex is OpenAI's terminal-driven, agent-assisted coding CLI — the same category of tool as Gemini CLI, Antigravity CLI and Claude Code, and like all of them it ships a full MCP client. Install it with npm: npm install -g @openai/codex or with Homebrew: brew install codex Then authenticate — Codex will open a browser to sign in with your ChatGPT account, or you can supply an API key: codex login Verify the install: codex --version Google Skills give your MCP client well known approaches to work with the core Google products including Big Query. The full details are here: Level Up Your Agents: Announcing Google's Official Skills Repository | Google Cloud Blog https://cloud.google.com/blog/topics/developers-practitioners/level-up-your-agents-announcing-googles-official-skills-repository To install the Skills: npx skills install github.com/google/skills This vendors the skills into .agents/skills/ and records them in skills-lock.json . They are client-neutral markdown, so the same checkout serves Codex, Claude Code and Gemini CLI. That was a lot of setup But wait- there is more So what is different about this lab compared to all the others out there? This demo is one of the first deep dives into configuring Looker for MCP with Codex. Codex provides a complete working environment with a full MCP client. Looker exposes the key features of the platform over the MCP layer. The interesting wrinkle in the Codex version is approvals . Roughly half of the ~50 Looker tools mutate your live instance — make look , make dashboard , add dashboard element , the project file family, the git and dev-mode tools. Codex has a first-class per-server approval mode, so this repo pins write tools behind a confirmation prompt while leaving discovery and querying to run freely. Read on. The strategy for configuring Looker with MCP is an incremental step by step approach. First, the Looker configuration settings are retrieved. Then, these settings are used to configure Codex. Finally- Codex is used as a MCP client to the Looker environment. Several samples are run using the Looker MCP Tools directly from Codex. For Looker Google Cloud core — Admins do not directly create keys for standard users; instead, they enable the permission for users to manage their own. Navigate to the Looker Admin Users page https://docs.cloud.google.com/looker/docs/admin-panel-users-users Admin Users . To connect to the Looker setup — you need to derive your Looker Base URL. Typically this will be the hostname in the Looker app domain. For the test instance- this is an example of what the URL looks like note the HTTPS prefix and no trailing slash : https://780eb09e-7dab-4076-9ec1-ecf9d8414630.looker.app First Login to your Looker User environment. Go to Profile- Account in upper right hand side and bring up the user settings: If the API Key box is unavailable- contact your Admin to enable the API setup on a per user basis. Once you have access to create API keys- the settings will look similar to this: Then click the “Manage” button to setup the API Keys: Click Create New API key to generate the API Key. Save the Client ID and Client Secret . At this point you should have a working Shell environment and a working Codex installation. All of the relevant code examples and documentation is available in GitHub. The next step is to clone the GitHub repository to your local environment: cd ~ git clone https://github.com/xbill9/looker-mcp-codex cd looker-mcp-codex Then run init.sh from the cloned directory. The script will attempt to determine your shell environment and set the correct variables: source init.sh This helper script will prompt for your Looker Instance details: bash xbill@penguin:~/looker-mcp-codex$ source set env.sh Looker Base URL e.g. https://your-company.looker.com : https://780eb09e-7dab-4076-9ec1-ecf9d8414630.looker.app Looker Client ID: Looker Client Secret: Downloading MCP Toolbox binary... Downloading from https://storage.googleapis.com/mcp-toolbox-for-databases/v1.6.0/linux/amd64/toolbox... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 292M 100 292M 0 0 71.8M 0 0:00:04 0:00:04 --:--:-- 71.8M Successfully installed MCP Toolbox binary v1.6.0 . Environment successfully set up. Current Environment .env — secret masked: GOOGLE GENAI USE VERTEXAI=True GOOGLE CLOUD PROJECT=comglitn GOOGLE CLOUD LOCATION=us-central1 LOOKER BASE URL=https://780eb09e-7dab-4076-9ec1-ecf9d8414630.looker.app LOOKER CLIENT ID= LOOKER CLIENT SECRET= LOOKER VERIFY SSL=true LOOKER TOOLBOX=/home/xbill/looker-mcp-codex/toolbox If your session times out or you need to re-authenticate- you can run the set env.sh script to reset your environment variables: source set env.sh One difference worth calling out versus the Claude Code write-up: with Codex you do not strictly need to source the script before every session. The launcher reads .env itself at process start. Sourcing is still the better habit, because it also puts LOOKER into your shell so you can drive toolbox or the Looker CLI by hand. Codex reads MCP servers from TOML. This repo ships a project-scoped .codex/config.toml : mcp servers."looker-toolbox" command = "bash" args = "./start-looker-mcp.sh" cwd = "." enabled = true startup timeout sec = 30 tool timeout sec = 120 default tools approval mode = "writes" Four of those lines are the whole story: command / args toolbox directly. That keeps the config file free of both secrets and shell quoting. startup timeout sec = 30 tool timeout sec = 120 run dashboard against a ten-tile dashboard is ten warehouse queries. Two minutes is a realistic ceiling. default tools approval mode = "writes" The launcher, start-looker-mcp.sh , is deliberately boring: bash /bin/bash set -eu PROJECT DIR="$ cd "$ dirname "${BASH SOURCE 0 }" " && pwd " if -f "$PROJECT DIR/.env" ; then set -a shellcheck disable=SC1091 source "$PROJECT DIR/.env" set +a fi LOOKER VERIFY SSL="${LOOKER VERIFY SSL:-true}" export LOOKER VERIFY SSL if -z "${LOOKER BASE URL:-}" || -z "${LOOKER CLIENT ID:-}" || -z "${LOOKER CLIENT SECRET:-}" ; then echo "looker-toolbox: Looker credentials are missing. Run: source set env.sh" &2 exit 1 fi exec "${LOOKER TOOLBOX:-$PROJECT DIR/toolbox}" --stdio --prebuilt looker,looker-dev Credential resolution order: .env in the project root LOOKER variables .env . source set env.sh , rather than dying with an opaque MCP connection error.That third case is worth the eight lines it costs. Every MCP client, Codex included, reports a server that exits during startup as a generic transport failure. Failing loudly with a sentence of English turns a twenty-minute debug into a five-second one. The repository also retains a Claude-compatible .mcp.json that launches the same binary through a bash -c wrapper. Both files contain only variable references, so both are safe to commit. Codex will not load a project-scoped config from a directory it does not trust. On first launch inside the repo it will ask; approve it once and the setting sticks: bash xbill@penguin:~/looker-mcp-codex$ codex You are running Codex in ~/looker-mcp-codex Since this folder is not version-control trusted, choose how to proceed: 1. Yes, allow Codex to work in this folder 2. No, exit If you would rather register the server globally instead of per-project, put the same mcp servers."looker-toolbox" block in ~/.codex/config.toml and use an absolute path for command / cwd . Project-scoped is the better default here — the launcher, the .env and the toolbox binary all live in the checkout, so the config travels with them. Start Codex from the project directory: bash xbill@penguin:~/looker-mcp-codex$ codex Then use /mcp to confirm the server came up: /mcp MCP Servers looker-toolbox ✔ connected 45 tools command bash ./start-looker-mcp.sh cwd /home/xbill/looker-mcp-codex approval writes You can also check without entering the TUI at all, which is handy in CI or when scripting a machine setup: bash xbill@penguin:~/looker-mcp-codex$ codex mcp list Name Command Args Env Cwd Status looker-toolbox bash ./start-looker-mcp.sh - . enabled and confirm Codex actually parsed every option — a typo'd key is silently ignored, so this is the fast way to prove the approval mode took effect: bash xbill@penguin:~/looker-mcp-codex$ codex mcp get looker-toolbox looker-toolbox enabled: true transport: stdio command: bash args: ./start-looker-mcp.sh cwd: . env: - startup timeout sec: 30 tool timeout sec: 120 default tools approval mode: writes remove: codex mcp remove looker-toolbox Now ask for the inventory: list the looker mcp tools Here are the Looker MCP tools available in this session, grouped by function: Metadata / Discovery - get models — list LookML models - get explores — list explores - get dimensions — list dimensions in an explore - get measures — list measures in an explore - get filters — list filters - get parameters — list parameters - get dashboards — list dashboards - get looks — list Looks - get projects — list LookML projects Querying / Running - query — run a Looker query - query sql — run raw SQL against a connection - query url — build a query URL - run look — run a saved Look - run dashboard — run a dashboard - run lookml tests / get lookml tests — LookML data tests Connections / Database Introspection - get connections - get connection databases - get connection schemas - get connection tables - get connection table columns Content Creation approval required - make look — create a Look - make dashboard — create a dashboard - add dashboard element — add a tile to a dashboard - add dashboard filter — add a filter to a dashboard - create view from table — generate a LookML view from a DB table - generate embed url — create an SSO embed URL LookML Project / File Management approval required - get project files / get project file / create project file / update project file / delete project file - get project directories / create project directory / delete project directory - validate project Git LookML version control approval required - list git branches / get git branch / create git branch / switch git branch / delete git branch - dev mode — toggle development mode Health / Diagnostics - health analyze - health pulse - health vacuum That's 51 tools total. The three groups marked approval required will prompt before running, per default tools approval mode = "writes" in .codex/config.toml. Want me to run one of them models, connections, or dashboards to verify connectivity? This is where the Codex configuration earns its keep. Codex separates two things that other clients tend to conflate: the sandbox what the agent may do to your filesystem and network and tool approval which MCP tools may fire without a human in the loop . default tools approval mode = "writes" means: run read-only tools freely, prompt before anything that changes state. A make dashboard call surfaces as: ⚠ looker-toolbox › make dashboard wants to run title VIP Customer Intelligence v2 description Real-time insights into top-performing revenue segments model advanced ecomm 1. Yes, run it 2. Yes, and don't ask again for make dashboard 3. No, and tell Codex what to do differently Option 2 is worth understanding before you reach for it. Approving make dashboard for the session is low-risk — it creates new content. Approving delete project file for the session is not. The Looker toolsets do not distinguish create from destroy in their naming, so read the tool name, not the category. The blunter instruments still exist if you want them — --ask-for-approval never for a fully unattended run, --sandbox read-only to clamp the agent's filesystem access. Neither is a substitute for the per-tool mode: sandbox settings govern the agent's own shell, not what an MCP server does to a remote SaaS instance over HTTPS. A read-only sandbox will happily let a tool call drop a LookML file on your Looker instance. The other half of the safety story is AGENTS.md , which Codex reads automatically from the project root. That is where this repo records the rules the config file cannot express — pass filter values bare, work LookML changes on a dev-mode branch, don't use mutating tools for routine verification, never print the client secret. Same role as CLAUDE.md for Claude Code and GEMINI.md for Gemini CLI; all three live side by side in the checkout. At this point- Codex is set up with the MCP Toolbox and has direct access to all the Looker MCP Tools. Any operations with the Tools come back directly into the Codex context. To get an overview of Dashboards: get dashboards • looker-toolbox › get dashboards Here are the dashboards in your Looker instance 16 total : ID Title Description ── ───────────────────────────────────────── ────────────────────────────────────── 1 2 Business Pulse - Intermediate — 2 1 Business Pulse - Basic — 3 3 Business Pulse - Advanced — 4 Agreement for Shared Use of this Instance — 5 test — 6 test — 7 Inventory — 8 TestJC — 9 Self-serve industry — 10 TestOrdersByCity — 11 My Dashboard — 12 test-orders — 13 E-commerce Overview Key e-commerce metrics 14 💎 VIP Customer Intelligence Advanced LTV and Ranking logic 15 ☁️ Cloud Optimization Hub AI-driven cost savings, Recommender API 16 Top Users & Countries Overview Top spenders and high-performing countries A few observations: - Several test/scratch dashboards 5, 6, 8, 10, 11, 12 look like leftovers — cleanup candidates. - The numbered "Business Pulse" set 1–3 are example/tutorial dashboards. - The substantive content is 13–16. Want me to run one of these run dashboard , or inspect the tiles on a specific one? You can also get models: get models • looker-toolbox › get models Here are the LookML models in your instance 11 total : Model Label Project Connection s ────────────────────── ─────────────────── ───────────────────────────────── ───────────────────────── basic ecomm Z Sample LookML sample thelook ecommerce default bigquery connection intermediate ecomm Z Sample LookML sample thelook ecommerce default bigquery connection advanced ecomm Z Sample LookML sample thelook ecommerce default bigquery connection extension-api-explorer Extension API Expl. marketplace extension api explorer default bigquery connection data block acs bigquery Census Data Block marketplace acs census-v2 american-community-survey gcp billing block Google Cloud Billing marketplace gcp-billing billing-export-sample chrome-ux-block Chrome UX Block marketplace chrome-ux-block chrome-ux london bicycles London Bicycles london bicycles london-bicycles gde rk Gde Rk gde rk 8 connections data-dictionary Data Dictionary marketplace extension data dict. default bigquery connection bq agent analytics Bq Agent Analytics agent events default bigquery connection Notable groupings: - theLook e-commerce samples basic/intermediate/advanced ecomm — Looker's standard demo dataset. - Marketplace blocks — Census/ACS, GCP Billing, Chrome UX, Data Dictionary, API Explorer. - Public datasets — london bicycles. - gde rk — a multi-connection catch-all model. Want me to pull the explores for one of these? advanced ecomm is the richest starting point. And drill into the details — the advanced example ecommerce explore is where the interesting LookML lives: get measures for advanced example ecommerce • looker-toolbox › get measures 20 measures, grouped by view: order items — core sales metrics order items.count of Order Items count order items.total sale price Sales sum order items.average sale price Average Price average order items.first order date First Order Date date order items.count for drill drill-support counts count users / products / inventory items users.count of Users count distinct products.count Count Distinct Products count distinct inventory items.total cost Total Cost sum inventory items.average cost Average Cost average User-summary measures filtered vs. lifetime symmetric-aggregate patterns user summary filtered.total sales for these users Sales Filtered Summary sum distinct user summary unfiltered.total sales for these users Sales Lifetime sum distinct user summary filtered.total items for these users Items Filtered Summary sum distinct user summary unfiltered.total items for these users Items Lifetime sum distinct Special measures — advanced ratio/comparison user summary and order items fields.percent of lifetime unfiltered sales user summary and order items fields.filtered average vs unfiltered average Notes: - The filtered vs. lifetime pairs showcase Looker's pattern for comparing a filtered subset against a user's full lifetime totals. - The count for drill measures exist to support drill-down on dashboard tiles. Let's see what VIP tiers look like: • looker-toolbox › query VIP Tiers — Lifetime Revenue Rank Group advanced example ecommerce Rank Group Users Total Sales Order Items Avg Sale Price ─────────── ────── ─────────── ─────────── ────────────── 1st 25% 15,569 $4,134,224 53,458 $77.34 2nd 25% 16,554 $1,931,678 36,005 $53.65 3rd 25% 16,557 $947,615 24,026 $39.44 Top 1000 ⭐ 1,000 $731,207 4,893 $149.44 Bottom 25% 16,560 $382,605 17,800 $21.49 What this shows - Steep revenue concentration. The top quartile drives $4.13M — about 55% of the ~$7.4M lifetime total — while the bottom 25% contributes only ~5%, despite having more users. - The "Top 1000" is a distinct elite segment, not a quartile — it overlaps with the 1st 25%. Just 1,000 users generate $731K, and their $149 average sale price is nearly 2× the top quartile's and 7× the bottom's. - Basket value declines cleanly down the tiers: $77 → $54 → $39 → $21. Rank correlates strongly with per-item spend, not just order count. Reading note: the quartile groups partition all purchasing users, while Top 1000 is a separate flag sitting inside the 1st quartile — its dollars are also counted in the 1st 25% row. Don't sum the column. Now build a Look — and this is where the writes approval mode fires for the first time: save that as a Look ⚠ looker-toolbox › make look wants to run model advanced ecomm explore advanced example ecommerce title VIP Tiers — Lifetime Revenue Rank Groups fields user summary unfiltered.user revenue rank group, users.count, order items.total sale price, order items.count, order items.average sale price sorts order items.total sale price desc vis looker bar 1. Yes, run it 2. Yes, and don't ask again for make look 3. No, and tell Codex what to do differently 1 • looker-toolbox › make look ✅ Look created — "VIP Tiers — Lifetime Revenue Rank Groups" - ID: 8 - URL: /looks/8 - Viz: horizontal bar chart, sorted by total sales, value labels on - Saved to: your personal folder Want me to add it to a dashboard, or create companion Looks Top 1000 by country/category ? The prompt shows the full argument payload before anything touches the instance. That is the part worth having — you can see explore , fields and folder and catch a wrong model before it creates content, rather than after. Once the Tools are exposed by MCP they have full access to Looker resources. Time to update a Dashboard — three mutations, batched into one approval round: add it to dashboard 14 and create the companion Looks I'll do all three — add the tile to dashboard 14, and create both companion Looks. ⚠ looker-toolbox › add dashboard element → dashboard id 14 1 approved ⚠ looker-toolbox › make look → "Top 1000 VIPs by Country" 1 approved ⚠ looker-toolbox › make look → "Top 1000 VIPs by Category" 1 approved • looker-toolbox › 3 calls All three succeeded. Pulling the underlying data so you can see what they contain. • looker-toolbox › 2 calls ✅ Dashboard tile added "VIP Tiers — Lifetime Revenue Rank Groups" is now a tile on 💎 VIP Customer Intelligence dashboard 14 . ✅ Look 9 — Top 1000 VIPs by Country /looks/9 Country VIP Users Total Sales Avg Price ────────────── ───────── ─────────── ───────── China 359 $259,129 $147.23 United States 224 $163,185 $147.41 Brasil 143 $106,613 $155.64 South Korea 53 $37,381 $129.34 France 52 $37,178 $149.31 Spain 47 $35,646 $163.51 Germany 43 $32,112 $158.19 United Kingdom 37 $28,494 $178.09 …6 more AU, BE, JP, PL ✅ Look 10 — Top 1000 VIPs by Product Category /looks/10 Category Total Sales Items Avg Price ─────────────────── ─────────── █████ ───────── Outerwear & Coats $245,412 664 $369.60 Suits & Sport Coats $70,838 278 $254.81 Jeans $58,421 423 $138.11 Active $48,295 220 $219.52 Sweaters $36,618 325 $112.67 Dresses $35,942 185 $194.28 …9 more Notable insights - Geography is concentrated: China + US + Brasil = ~726 of the 1,000 VIPs. The UK has the highest per-item spend $178 despite few users. - Outerwear dominates category spend — $245K, more than the next three categories combined, at a $369.60 average sale price. High-ticket outerwear is the signature purchase of your best customers. This will look similar to: And can also be accessed directly in Looker: Health checks and instance maintenance — and the first real one surfaced a finding, just not the expected kind: run a full health sweep Running usage analysis, six pulse checks, and cleanup candidates in parallel. • looker-toolbox › 10 calls Meanwhile — a metadata-based audit does work get dashboards / run dashboard don't touch System Activity, so here's a cleanup pass from what we already gathered: ID Title Flag ──── ──────────────────────────── ───────────────────────────────────── 5, 6 "test" ×2, duplicate name Scratch — almost certainly deletable 8 TestJC Scratch 10 TestOrdersByCity Scratch 11 My Dashboard Default/placeholder name 12 test-orders Scratch 14 💎 VIP Customer Intelligence Superseded by v2 17 — 7 broken tiles ~7 dashboards worth reviewing for deletion. Note what Codex did not do here: it identified six deletion candidates and stopped. Deleting dashboards is a mutation, and the approval mode plus the AGENTS.md rule "confirm before creating/altering/deleting Looker content" both point the same direction. The agent proposes; you dispose. The key value shows up when you push the combination of Codex, the model, and the Looker tools over MCP: "Are we at risk of losing our best customers?" I'll investigate using your Looker instance. Starting with what data is available, then digging into retention signals. • looker-toolbox › get models This is the thelook e-commerce dataset. Exploring the richest model. • looker-toolbox › 3 calls Rich model — there's a lifetime revenue-rank on each user, so I can define "best customers" precisely Top Revenue Group / Top 1000 and track activity over time. First, the data's date range, so I know what "recent" means. • looker-toolbox › query Data runs right up to today. Now the core analysis: the Top Revenue Group's monthly spend and active-customer count over the last ~2 years. • looker-toolbox › query The business is growing overall, so a raw trend hides churn. The real risk signal is recency — how many of our best customers have gone quiet. • looker-toolbox › 4 calls Here's what the data says. I defined "best customers" as your Top Revenue Group — the top 1,000 by lifetime valid revenue $731K lifetime, ~$731 each . Then I looked at whether they're still actually buying. Short answer: the cohort's revenue is healthy, but there's a large dormant tail. Aggregate spend from top customers is at record highs — valid revenue rose from ~$12–17K/month in late 2024 to $43K most recently, growing alongside the overall business. The franchise isn't collapsing. But recency tells a more worrying story. Of the 1,000 all-time best customers: Last purchased within still active Share → Gone silent ───────────────────── ────────────── ───── ─────────────────────────── 90 days 258 26% 74% 742 inactive 3+ months 180 days 419 42% 58% 581 inactive 6+ months 365 days 585 59% 42% 415 inactive 12+ months So ~415 of your top-1,000 42% haven't placed a valid order in over a year — effectively lapsed. At the cohort's average lifetime value ~$731 , that's on the order of ~$300K of historical revenue that has stopped repeating, plus another ~160 in the 6–12 month "cooling off" zone. How to read this - It's a tail problem, not a top-line collapse. A concentrated set of top customers is very active, while a long tail of former big spenders has quietly aged out. That's partly natural — "best customers" is a lifetime label. - The actionable risk is the 6–12 month cooling band ~160 customers — recently valuable, now slipping, still winnable. Suggested next steps I can do any of these — just say the word 1. Pull the actual at-risk list — name, email, lifetime spend, days-since-last-order. 2. Build a "Best Customer Retention" dashboard so this is monitored ongoing. 3. Add a churn-risk segment to the LookML model so "at-risk best customers" becomes a reusable, governed field. Note that 2 and 3 create or modify content in your live Looker instance — those will come through as approval prompts, and I'll confirm specifics before running them. Pull at-risk customers in real time, based on your actual data: Your best customers who've gone quiet The 5 highest-lifetime-value members of the Top-1,000 revenue group with no valid order in 90+ days, ranked by lifetime spend. "Cooling" = last bought 3–6 months ago most winnable ; "Dormant" = 6+ months silent. Customer Country Channel Lifetime $ Orders Status ─ ─────────────── ──────── ──────── ────────── ────── ────────── 1 Craig Dickerson France Email $1,849 8 🟡 Cooling 2 Mark Nolan USA Organic $1,826 7 🟡 Cooling 3 John Hill Brazil Search $1,554 4 🔴 Dormant 4 Glenn Foster USA Facebook $1,455 8 🟡 Cooling 5 Thomas Davis Australia Search $1,435 8 🔴 Dormant Notable: your single highest-lifetime-value customer overall Craig Dickerson, $1,849 is on this list — cooling, not yet lost. The full at-risk population all 1,000 top customers - 🟢 258 active bought in last 90 days — healthy - 🟡 161 cooling — last order 3–6 months ago ← highest-priority win-back - 🟠 166 slipping — last order 6–12 months ago - 🔴 415 lapsed — no order in 12+ months So 742 of your top 1,000 74% haven't purchased in 90+ days. Method note: ranked by lifetime valid spend; "at-risk" = no valid order in 90 days, cross-checked against the 90- and 180-day active sets. Status is bucketed by 90/180-day windows rather than exact per-customer last-order dates — the toolbox couldn't compute that inline. What-if scenarios: "What if we raised outerwear prices 10% — what happens to VIP revenue and would it dent volume?" A pricing what-if on the VIP segment. Grounding it in actual numbers first. • looker-toolbox › 2 calls Outerwear is the key finding: it's your VIPs' 1 category by a wide margin — $245K 34% of all VIP lifetime revenue , 664 items at $370/item. This decision hits VIPs where they're most concentrated. Pulling cost too, for profit impact. Baseline — VIP outerwear today Metric Value ──────────────── ─────────────────────── Revenue $245,412 Units sold 664 Avg price / unit $369.60 Cost / unit $163.48 Gross profit $136,859 55.8% margin Profit / unit $206.11 What a +10% price does New price = $406.56 +$36.96/unit; cost unchanged, so every extra dollar is margin . Volume response Units Δ Revenue vs today Gross profit vs today ────────────────── ────────── ──────── ──────── ──────────── ──────── No dip inelastic 664 0% $269,956 +$24,544 $161,405 +$24,546 −5% 631 −33 $256,458 +$11,046 $153,335 +$16,476 −10% 598 −66 $242,960 −$2,452 $145,266 +$8,407 −15% 564 −100 $229,462 −$15,950 $137,197 ~flat −20% 531 −133 $215,964 −$29,449 $129,127 −$7,732 The two numbers that matter - Revenue break-even: ~9% volume loss. You can lose up to ~60 of the 664 units before the hike stops adding revenue. - Profit break-even: ~15% volume loss. Because you keep the full $37 markup at zero added cost, profit holds even if revenue dips. Would it dent volume? Expect a modest dip. For your most loyal customers buying a premium considered-purchase category, elasticity is likely mild roughly −0.3 to −0.8 — the top two rows: revenue +$11–20K, profit +$16–22K, only ~20–50 fewer units. One strategic caveat Tying back to the last analysis: 74% of your VIPs are already cooling or lapsed, and outerwear is their anchor category. A blanket 10% hike risks nudging cooling VIPs out the door, and that churned lifetime value would swamp the ~$15–20K modeled gain. - Raise on healthy/active VIPs; protect the at-risk ones. - Apply to new-season inventory rather than a visible retroactive hike. - Run it as a holdout test on a VIP subset first to get real elasticity. Caveat on the model: elasticity is assumed, not measured — no price-experiment history exists in this data. Because looker-dev is loaded alongside looker , Codex can read the actual model source, not just the metadata — which is what makes "can I trust this measure?" an answerable question: "What does filtered average vs unfiltered average actually compute, and can I trust it?" Let me read the LookML that defines it. First, locating the project files. • looker-toolbox › 2 calls The measure lives in the user summary and order items fields view. Reading it plus the two views it depends on. • looker-toolbox › 3 calls I have the full definition and its dependencies. Verifying my reading against live data before giving a verdict — pulling the raw ingredients alongside the measure. • looker-toolbox › query The math reconciles exactly Outerwear: 145.37 / 88.47 − 1 = 0.643 ✓ . Full teardown: What it computes The percent difference between the average item price in the current query context and the same shoppers' average item price over their entire lifetime. Positive = they're buying pricier-than-usual items in this slice. The actual SQL measure: filtered average vs unfiltered average { label: "Avg Price vs These Users' Avg Price Lifetime " type: number sql: ${order items.average sale price} 1.0 / nullif ${user summary unfiltered.average sale price for these users}, 0 - 1 ;; value format name: percent 0 } Where each half comes from — the clever part Term Field Respects query filters? ─────────── ────────────────────────────────────── ───────────────────────── Numerator order items.average sale price Yes — rows in scope Denominator user summary unfiltered.average sale No — lifetime avg for price for these users those same users The denominator's "lifetime" behavior comes from one line: derived table: { explore source: advanced example ecommerce { ... bind all filters: no } } That derived table is one row per user, joined back to order items by user id. Because it's a 1-user-row joined to many order-item rows, Looker applies symmetric aggregates so summing lifetime sales/items counts each user exactly once no fan-out . Its twin, user summary filtered, is identical but bind all filters: yes. Empirically verified: Category Filtered avg Lifetime avg Measure Check ───────────────── ──────────── ──────────── ─────── ────────────────────── Outerwear & Coats $145.37 $88.47 +64% 145.37/88.47−1 = 0.643 ✓ Suits $118.39 $77.38 +53% ✓ Blazers & Jackets $92.51 $67.84 +36% ✓ Can you trust it? ✅ Yes — with three rules Correctly built: proper symmetric-aggregate handling, nullif ...,0 guards against divide-by-zero, both sides on the same "Valid Orders only" basis. No bug here. But it's a ratio-of-averages, so respect its nature: 1. Don't sum, average, or trust a Totals row for it. Ratio measures don't roll up. 2. The baseline is dynamic, not a global constant. Change a filter that changes which users appear and the baseline moves. This is the 1 way people misread it. 3. It's about per-item price mix, not spend or loyalty. Bottom line: trustworthy for exactly one question — "in this slice, are these shoppers trading up or down on per-item price versus their own norm?" Note that this whole exchange used only read tools — get project files , get project file , query — so it ran without a single approval prompt. The mode is calibrated so that understanding your instance is frictionless and changing it is not. The dashboard existed already dashboard 14, built earlier from advanced ecomm . To make it a proper briefing I added an executive layer on top of the existing charts: a 4-KPI summary strip, and a "bottom line" callout. The briefing in 30 seconds Metric Value Meaning ───────────────────── ────── ───────────────────────────────────── Lifetime revenue $7.40M All purchasing users Top-1000 VIP revenue $731K $149 avg basket — ~7× the bottom tier Revenue concentration 56% From the 1st customer quartile VIP geography 72% Of VIP spend from China, US, Brasil Bottom line for the exec team: revenue is highly concentrated — a 1,000-customer VIP core spends ~7× the average shopper, is geographically narrow three countries , and is premium-led Outerwear & Coats alone: $245K at a $370 avg item . The strategic lever is retaining and expanding the VIP core, not broad acquisition. One note on reading the charts: the Top 1000 tier is an elite flag inside the 1st quartile — its dollars are already counted there, so don't sum the tier bars. These are only high level examples of what can be done with the tech stack The MCP path is not the only way in. The repo also ships a Makefile target that installs the Looker CLI https://github.com/looker-open-source/looker-cli into the project root, checksum-verified: make cli latest release make cli LOOKER CLI VERSION=v0.4.8 pinned make clean remove downloaded binaries, keep credentials It reads the same LOOKER variables, so source set env.sh covers both. Useful for the deterministic, scriptable half of the work — CI checks, bulk operations — while MCP covers the exploratory half. A short list of the things that actually go wrong: | Symptom | Cause | Fix | |---|---|---| /mcp shows no servers | Project not trusted, so .codex/config.toml never loaded | Restart codex in the repo root and approve the trust prompt | | Server fails immediately | No .env and no exported LOOKER | source set env.sh — the launcher prints exactly this | | Server times out on startup | 300 MB binary + Looker handshake on a cold/slow start | Raise startup timeout sec | run dashboard times out | Ten tiles = ten warehouse queries | Raise tool timeout sec , or run tiles individually | All health return Access Denied | API3 role lacks see system activity | Admin → Roles, add the permission | | Filter returns nothing | Value was quoted | Pass values bare — first touch , not "first touch" | | Tools run without asking | Approval mode not applied | codex mcp get looker-toolbox — if the key isn't echoed back it was misspelled and silently dropped. Also check you didn't pick "don't ask again" earlier in the session | Codex was configured as a Looker MCP client using the MCP Toolbox. The .codex/config.toml registration points at a secret-free launcher script that resolves credentials from .env at runtime, and pins write-capable tools behind default tools approval mode = "writes" so discovery and analysis run unattended while anything that mutates the live instance stops and asks. The MCP connection was then used to explore the instance, read and verify LookML, build Looks and dashboards, and run open-ended business analysis against the governed semantic model. The stack underneath is unchanged from the Gemini CLI, Antigravity CLI and Claude Code versions of this paper — same toolbox binary, same looker,looker-dev toolsets, same ~50 tools. That is the actual result worth noting: the same repository, with three client config files sitting side by side, serves all of them.