npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luutuankiet/looker-mcp-shim

v0.5.0

Published

MCP server for AI-powered Looker development — tile inspection, compiled SQL, dev/prod mode, code execution escape hatch

Downloads

2,730

Readme

@luutuankiet/looker-mcp-shim

One MCP server. Full Looker developer autonomy for AI agents.

Inspect dashboards tile-by-tile. Create, modify, and delete tiles and filters. Run queries with compiled SQL. Edit LookML, push, validate. Execute any of Looker's 469 API endpoints via SDK method discovery. All through a single stdio server — no human-in-the-loop for mechanical steps.

npx -y @luutuankiet/looker-mcp-shim

Install skill docs for Claude Code agents (workflow guides, API patterns, recipes):

npx -y @luutuankiet/looker-mcp-shim install-skill          # current project
npx -y @luutuankiet/looker-mcp-shim install-skill --global  # all projects

What This Does

An AI agent using this server can do everything a Looker developer does — including LookML dashboard lifecycle (import, iterate, export):

graph LR
    A[Inspect<br/>dashboards + tiles] --> B[Query<br/>data + compiled SQL]
    B --> C[Mutate<br/>create/update/delete<br/>tiles + filters]
    C --> D[Edit LookML<br/>push + validate]
    D --> E[Verify<br/>re-inspect + re-query]
    E --> A
    F[LookML Dashboard<br/>import → iterate → export] --> C
    A --> F

    style F fill:#9C27B0,color:#fff

    style A fill:#4285F4,color:#fff
    style B fill:#34A853,color:#fff
    style C fill:#FBBC04,color:#000
    style D fill:#EA4335,color:#fff
    style E fill:#4285F4,color:#fff

57 tools from one server: 17 custom shim tools + 41 dynamically bridged from Google's upstream Looker MCP.


Architecture

graph TD
    subgraph "AI Agent"
        A["Claude Code / Cursor / etc"]
    end

    subgraph "looker-mcp-shim — single stdio server"
        direction TB
        D["core.ts<br/>Session + Safety Layer"]
        
        subgraph "Read Tools"
            E["inspect"]
            F["run_tile / run_query"]
        end
        
        subgraph "Mutation Tools"
            G["create_tile / update_tile / delete_tile"]
            H["create_filter / update_filter / delete_filter"]
        end
        
        subgraph "Dev Tools"
            I["switch_mode / reset_to_remote / validate"]
        end
        
        subgraph "Escape Hatch"
            J["retrieve_sdk_methods"]
            K["describe_sdk_method"]
            L["execute_sdk_code"]
        end
        
        U["upstream.ts<br/>MCP Client Bridge"]
    end

    subgraph "Google Looker MCP"
        V["@toolbox-sdk/server<br/>41 tools"]
    end

    subgraph "Looker"
        W["REST API 4.0"]
        X["swagger.json<br/>469 methods"]
    end

    A -->|stdio| D
    D --> E & F & G & H & I & J & K & L
    D --> U
    U -->|stdio| V
    V --> W
    D --> W
    J & K -.->|loads at startup| X

    style D fill:#4285F4,color:#fff
    style U fill:#34A853,color:#fff
    style V fill:#EA4335,color:#fff

Quickstart

1. Configure

# .env (or pass as env vars in MCP config)
LOOKER_BASE_URL=https://your-instance.cloud.looker.com
LOOKER_CLIENT_ID=your_client_id
LOOKER_CLIENT_SECRET=your_client_secret
LOOKER_PROJECT_ID=your-lookml-project
# Branch auto-detected from Looker. Optional overrides:
# LOOKER_ALLOWED_BRANCHES=*                              # default: any branch
# LOOKER_RESET_BRANCHES=feat/my-branch,tmp/sandbox       # default: none

2. Register

Claude Code / Cursor — add to .mcp.json:

{
  "mcpServers": {
    "looker": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@luutuankiet/looker-mcp-shim"],
      "env": {
        "LOOKER_BASE_URL": "https://your-instance.cloud.looker.com",
        "LOOKER_CLIENT_ID": "...",
        "LOOKER_CLIENT_SECRET": "...",
        "LOOKER_PROJECT_ID": "your-project",
        "LOOKER_RESET_BRANCHES": "feat/your-branch"
      }
    }
  }
}

3. Test without registration

npx @luutuankiet/mcp-proxy-shim passthru -- npx @luutuankiet/looker-mcp-shim

# From another terminal:
curl http://localhost:3456/tools              # list all 56 tools
curl -X POST http://localhost:3456/call/inspect -d '{"args":{"target":"151"}}'

Disable upstream bridge: SKIP_UPSTREAM=1 npx @luutuankiet/looker-mcp-shim

4. Install Skill Docs (recommended)

npx -y @luutuankiet/looker-mcp-shim install-skill

Installs workflow guides to .claude/skills/looker-mcp-shim/:

| File | What It Teaches | |------|----------------| | SKILL.md | Entry point + tool index + decision tree | | rules/workflow.md | The complete dev loop | | rules/inspect.md | Dashboard/tile inspection | | rules/query.md | Running queries with filter auto-wiring | | rules/mutate.md | Tile + filter CRUD, filter wiring via SDK | | rules/git-ops.md | Dev mode, git sync, LookML validation | | rules/sdk-escape.md | SDK method discovery + code execution | | rules/patterns.md | Migration QA, dashboard cloning, bulk ops |

Only touches looker-mcp-shim/ namespace. No interference with other skills.


Branch Safety Model

Looker dev mode operates on git branches. The shim separates switching (safe) from resetting (destructive):

graph TD
    A[Agent wants to work<br/>on a branch] --> B{switch_mode}
    B -->|LOOKER_ALLOWED_BRANCHES=*| C[Switch to ANY branch]
    B -->|explicit list| D[Only listed branches]
    
    C --> E{Agent calls<br/>reset_to_remote?}
    D --> E
    
    E -->|Branch in<br/>LOOKER_RESET_BRANCHES| F[Reset allowed<br/>Wipes uncommitted changes]
    E -->|Branch NOT in<br/>LOOKER_RESET_BRANCHES| G[BLOCKED<br/>Other people's work protected]
    
    style F fill:#34A853,color:#fff
    style G fill:#EA4335,color:#fff

Setup

# .env — branch is auto-detected from Looker, no config needed
LOOKER_ALLOWED_BRANCHES=*                            # switch to any branch (default)
LOOKER_RESET_BRANCHES=feat/dev_tools,tmp/sandbox     # ONLY these can be reset

How It Works

| Action | Gate | Example | |--------|------|---------| | switch_mode({mode: "dev", branch: "feat/alice"}) | ALLOWED_BRANCHES | ✅ With *, any branch works | | switch_mode({mode: "dev", branch: "main"}) | ALLOWED_BRANCHES | ✅ Safe — read-only inspection per session | | reset_to_remote({}) on feat/dev_tools | RESET_BRANCHES | ✅ In the list — reset allowed | | reset_to_remote({}) on feat/alice | RESET_BRANCHES | ❌ BLOCKED — not in list | | reset_to_remote({}) on main | RESET_BRANCHES | ❌ BLOCKED — not in list |

Typical Branch Workflow

sequenceDiagram
    participant Agent
    participant Shim
    participant Looker

    Note over Agent: Start on default dev branch
    Agent->>Shim: switch_mode({mode: "dev",<br/>branch: "feat/dev_tools"})
    Shim-->>Agent: {mode: "dev", branch: "feat/dev_tools"}

    Note over Agent: Inspect another team member's branch
    Agent->>Shim: switch_mode({mode: "dev",<br/>branch: "feat/alice-dashboard"})
    Shim-->>Agent: {mode: "dev", branch: "feat/alice-dashboard"}
    Agent->>Shim: inspect({target: "152"})
    Shim-->>Agent: Dashboard state on Alice's branch

    Note over Agent: Try to reset — BLOCKED
    Agent->>Shim: reset_to_remote({})
    Shim-->>Agent: ERROR: Branch "feat/alice-dashboard"<br/>not in LOOKER_RESET_BRANCHES

    Note over Agent: Switch to safe branch, edit, reset
    Agent->>Shim: switch_mode({mode: "dev",<br/>branch: "feat/dev_tools"})
    Note over Agent: Edit LookML, git push
    Agent->>Shim: reset_to_remote({})
    Shim-->>Agent: {success: true}
    Agent->>Shim: validate({})
    Shim-->>Agent: {status: "ok"}

Why this matters: reset_to_remote wipes all uncommitted changes on the current branch for the API user. Without the safety gate, an agent switching to a colleague's branch and resetting could destroy work-in-progress.


Agent Workflows

1. Dashboard Inspection

The agent explores a dashboard in two levels — overview first, then drill into specific tiles.

sequenceDiagram
    participant Agent
    participant Shim
    participant Looker

    Agent->>Shim: inspect({target: "152"})
    Shim->>Looker: GET /dashboard_elements + /dashboard_filters
    Shim-->>Agent: 12 tiles, 14 filters<br/>(~50 tokens/tile)

    Note over Agent: Agent picks tile to investigate

    Agent->>Shim: inspect({target: "tile:1486"})
    Shim->>Looker: GET /dashboard_elements/1486
    Shim-->>Agent: fields, filters, sorts, vis_config,<br/>filter wiring, query_id (~200 tokens)

    Agent->>Shim: run_tile({element_id: "1486", format: "sql"})
    Shim->>Looker: GET /queries/{id}/run/sql
    Shim-->>Agent: Compiled BigQuery SQL (33K chars)

    Agent->>Shim: run_tile({element_id: "1486", format: "json", limit: 5})
    Shim->>Looker: GET /queries/{id}/run/json
    Shim-->>Agent: 5 data rows

URL-smart input — all of these work:

| Input | Parses To | |-------|----------| | "152" | Dashboard 152 | | "tile:1486" | Tile detail | | "https://host/dashboards/152" | Dashboard 152 | | "https://host/explore/common/transactions?fields=..." | Explore |


2. Dashboard Mutation — Build & Modify Tiles

The agent creates tiles, modifies them, and verifies — full CRUD without touching the Looker UI.

sequenceDiagram
    participant Agent
    participant Shim
    participant Looker

    Note over Agent: Create a revenue tile
    Agent->>Shim: create_tile({dashboard_id: "152",<br/>title: "Revenue by Region",<br/>query: {model: "common",<br/>view: "transactions",<br/>fields: ["transactions.region",<br/>"transactions.total_revenue"],<br/>vis_config: {type: "looker_bar"}}})
    Note over Shim: Two-step: create_query() -> query_id<br/>then create_dashboard_element()
    Shim->>Looker: POST /queries + POST /dashboard_elements
    Shim-->>Agent: {element_id: "1503"}

    Note over Agent: Change chart type to pie
    Agent->>Shim: update_tile({element_id: "1503",<br/>query: {vis_config: {type: "looker_pie"}}})
    Note over Shim: Reads existing query, merges changes,<br/>creates new query, updates element
    Shim->>Looker: GET element -> POST /queries -> PATCH element
    Shim-->>Agent: {fields preserved, vis updated}

    Note over Agent: Add a filter
    Agent->>Shim: create_filter({dashboard_id: "152",<br/>name: "region_filter",<br/>title: "Region",<br/>type: "field_filter",<br/>dimension: "transactions.region",<br/>model: "common",<br/>explore: "transactions"})
    Shim->>Looker: POST /dashboard_filters
    Shim-->>Agent: {filter_id: "1141"}

    Note over Agent: Verify everything
    Agent->>Shim: inspect({target: "152"})
    Shim-->>Agent: Tile 1503 + Filter 1141 confirmed

Key insight: Looker's API rejects inline query objects on element create/update. The shim handles the two-step dance automatically — create_query() first, then reference via query_id. Agents don't need to know this.

Partial updates: When updating a tile's vis_config, the shim reads the existing query, merges your changes, and preserves everything else (fields, filters, sorts). You only send what changed.


3. LookML Edit → Validate → Verify Loop

The complete developer loop: edit LookML, sync Looker, validate, check results.

sequenceDiagram
    participant Agent
    participant Git as Local Git
    participant Shim
    participant Looker
    participant BQ as BigQuery

    Note over Agent: Agent edits LookML locally
    Agent->>Git: Edit .lkml files
    Agent->>Git: git push origin feat/branch

    Note over Agent: Sync Looker to latest code
    Agent->>Shim: reset_to_remote({})
    Shim->>Looker: POST /projects/{id}/reset_to_remote
    Shim-->>Agent: {success: true}

    Note over Agent: Validate LookML syntax
    Agent->>Shim: validate({})
    Shim->>Looker: POST /projects/{id}/lookml_validation
    Shim-->>Agent: {status: "ok", errors: []}

    Note over Agent: Verify data still correct
    Agent->>Shim: run_tile({element_id: "1486",<br/>format: "json", limit: 5})
    Shim->>Looker: GET /queries/{id}/run/json
    Looker->>BQ: Execute compiled SQL
    BQ-->>Looker: Result rows
    Shim-->>Agent: [{region: "SG", revenue: 45000}, ...]

    Note over Agent: Compare with expected values
    Agent->>Shim: run_tile({element_id: "1486",<br/>format: "json", limit: 5,<br/>force_production: true})
    Shim-->>Agent: Production data for parity check

force_production — Run a query against production LookML from dev mode. Perfect for comparing dev changes against prod baseline without switching modes.

Long-running queries — Complex explores (e.g., BigQuery with 33K char compiled SQL) get 120s timeout by default. If that expires, the shim automatically falls back to Looker's async query task mechanism (same as the Looker UI), polls for completion, and returns results.


4. SDK Method Discovery — The Escape Hatch

For anything not covered by the 15 dedicated tools, the agent discovers and executes any of Looker's 469 API methods.

sequenceDiagram
    participant Agent
    participant Shim
    participant Swagger as swagger.json

    Note over Agent: "I need to find scheduled plans"<br/>Step 1: Search
    Agent->>Shim: retrieve_sdk_methods({query: "schedule plan"})
    Shim->>Shim: Search catalog (loaded from swagger.json)
    Shim-->>Agent: 15 matches:<br/>scheduled_plans_for_dashboard,<br/>create_scheduled_plan, ...

    Note over Agent: Step 2: Get details
    Agent->>Shim: describe_sdk_method({<br/>method: "scheduled_plans_for_dashboard"})
    Shim-->>Agent: Parameters: dashboard_id (required),<br/>user_id, all_users, fields<br/>Code example: sdk.ok(sdk.scheduled_plans_for_dashboard({<br/>  dashboard_id: "152" }))

    Note over Agent: Step 3: Execute
    Agent->>Shim: execute_sdk_code({code: "<br/>const plans = await sdk.ok(<br/>  sdk.scheduled_plans_for_dashboard({<br/>    dashboard_id: '152', all_users: true<br/>  })<br/>)<br/>return plans.map(p => ({<br/>  name: p.name, cron: p.crontab<br/>}))"})
    Shim-->>Agent: [{name: "Weekly Revenue",<br/>cron: "0 9 * * 1"}, ...]

The catalog is loaded from the Looker instance's own swagger.json at startup — always accurate for your specific Looker version.


5. Migration QA — Tableau to Looker

The use case that drove this tool: an agent receives a Tableau screenshot and verifies data parity in Looker, tile by tile.

sequenceDiagram
    participant Human
    participant Agent
    participant Shim
    participant Looker

    Human->>Agent: "Verify dashboard 152 matches<br/>this Tableau screenshot"

    Agent->>Shim: switch_mode({mode: "dev",<br/>branch: "feat/migration"})
    Shim-->>Agent: {mode: "dev", branch: "feat/migration"}

    Agent->>Shim: inspect({target: "152"})
    Shim-->>Agent: 12 tiles, 14 filters

    loop For each tile
        Agent->>Shim: inspect({target: "tile:{id}"})
        Shim-->>Agent: fields, model, explore, filters

        Agent->>Shim: run_tile({element_id: "{id}",<br/>format: "json", limit: 20})
        Shim-->>Agent: Data rows

        Note over Agent: Compare data vs Tableau screenshot

        alt Data mismatch found
            Agent->>Shim: run_tile({element_id: "{id}",<br/>format: "sql"})
            Shim-->>Agent: Compiled SQL
            Note over Agent: Agent identifies join/filter issue,<br/>edits LookML, pushes to git
            Agent->>Shim: reset_to_remote({})
            Agent->>Shim: validate({})
            Agent->>Shim: run_tile({element_id: "{id}",<br/>format: "json"})
            Note over Agent: Data matches now
        end
    end

    Agent->>Human: "All 12 tiles verified.<br/>3 had issues, fixed in LookML."

6. LookML Dashboard Lifecycle — Import, Iterate, Export

LookML dashboards are code-defined — tiles cannot be mutated via API. The shim provides a fast iteration path: import as UDD, iterate with mutation tools (no git commits), then export back to LookML.

sequenceDiagram
    participant Agent
    participant Shim
    participant Looker
    participant Git

    Note over Agent: Inspect the LookML dashboard
    Agent->>Shim: inspect({target: "model::dashboard_name"})
    Shim->>Looker: GET /dashboards/model::dashboard_name
    Shim-->>Agent: 4 tiles, 14 filters, type: lookml_dashboard<br/>hint: use import_lookml_dashboard

    Note over Agent: Import as editable UDD
    Agent->>Shim: import_lookml_dashboard({<br/>lookml_dashboard_id: "model::dashboard_name",<br/>folder_id: "85"})
    Shim->>Looker: validate_project + dashboard() + import_lookml_dashboard()
    Shim-->>Agent: {id: "173", verification: {tiles_match: true}}

    Note over Agent: Fast iteration loop (no git!)
    loop Iterate on UDD
        Agent->>Shim: update_tile / create_tile / update_filter
        Agent->>Shim: run_tile({dashboard_id: "173", tile: "#1"})
        Agent->>Shim: inspect({target: "173"})
    end

    Note over Agent: Export final state as LookML
    Agent->>Shim: export_dashboard_lookml({dashboard_id: "173"})
    Shim->>Looker: GET /dashboards/173/lookml
    Shim-->>Agent: {lookml: "---\n- dashboard: ..."}

    Note over Agent: Commit to code
    Agent->>Git: Write .dashboard.lookml + git push
    Agent->>Shim: reset_to_remote({})
    Agent->>Shim: validate({})
    Agent->>Shim: inspect({target: "model::dashboard_name"})
    Note over Agent: Compiled result matches intent ✔

Two loops, one bridge:

  • Fast loop (UDD): mutation tools, instant, no git
  • Slow loop (LookML): git push + reset + validate
  • import enters the fast loop, export exits it

Tool Reference

Inspection

| Tool | What It Does | Key Args | |------|-------------|----------| | inspect | Dashboard overview or tile detail | target: URL, ID, or tile:NNN |

LookML Dashboard Lifecycle

| Tool | What It Does | Key Args | |------|-------------|----------| | inspect | Inspect LookML dashboard (tiles, filters) | target: "model::dashboard_name" | | import_lookml_dashboard | Clone LookML dashboard as editable UDD | lookml_dashboard_id, folder_id | | export_dashboard_lookml | Export any dashboard as LookML YAML | dashboard_id |

Query Execution

| Tool | What It Does | Key Args | |------|-------------|----------| | run_tile | Execute a tile's query | element_id, format (json/sql/csv), limit, force_production, timeout | | run_query | Ad-hoc explore query | model, explore, fields, filters, sorts, limit, force_production, timeout |

Both tools handle long-running BigQuery queries automatically — 120s timeout with async query task fallback.

Dashboard Mutation

| Tool | What It Does | Key Args | |------|-------------|----------| | create_tile | Add tile to dashboard | dashboard_id, title, query (inline) or query_id | | update_tile | Modify tile (partial) | element_id, title, query (partial merge) | | delete_tile | Remove tile | element_id | | create_filter | Add dashboard filter | dashboard_id, name, title, type, dimension, model, explore | | update_filter | Modify filter | filter_id, title, default_value, ... | | delete_filter | Remove filter | filter_id |

Partial query updates: update_tile merges your changes with the existing query. Send only what changed — fields, vis_config, sorts, and filters are preserved.

{"element_id": "1486", "query": {"vis_config": {"type": "looker_pie"}}}

The shim reads the current query, merges your vis_config change, creates a new query, and updates the element. Fields, filters, sorts — all preserved.

Dev Operations

| Tool | What It Does | |------|-------------| | switch_mode | Toggle dev/prod mode with branch selection | | reset_to_remote | Sync Looker project to git HEAD | | validate | LookML syntax validation with file:line errors |

SDK Escape Hatch

| Tool | What It Does | |------|-------------| | retrieve_sdk_methods | Search 469 SDK methods by keyword/tag | | describe_sdk_method | Get full params + code example for a method | | execute_sdk_code | Run arbitrary SDK code with pre-authenticated session |

Workflow: Search -> Describe -> Execute. Never guess method signatures.

retrieve_sdk_methods({query: "render png"})        # find the method
describe_sdk_method({method: "create_dashboard_element_render_task"})  # get params
execute_sdk_code({code: "..."})                     # run it

Upstream Looker MCP (41 tools, auto-bridged)

All tools from @toolbox-sdk/server --prebuilt=looker,looker-dev are automatically available:

get_project_files, update_project_file, create_project_file, delete_project_file, get_explores, get_dimensions, get_measures, get_filters, get_models, get_connections, run_dashboard, run_look, query_sql, query, make_dashboard, make_look, dev_mode, validate_project, get_dashboards, get_looks, and more.

These are prefixed with [upstream] in descriptions. Our shim tools take priority on name collisions.


Safety Layer

Blocked SDK Methods (hardcoded, non-configurable)

| Category | Methods | |----------|--------| | Production deployment | deploy_ref_to_production, deploy_to_production | | User impersonation | login_user | | Destructive admin | delete_group, create_group, update_group, delete_user_attribute, delete_role, delete_folder, delete_dashboard, delete_look, update_user | | Schedule manipulation | delete_scheduled_plan, update_scheduled_plan, create_scheduled_plan |

Configurable Guardrails

| Setting | Purpose | |---------|--------| | LOOKER_ALLOWED_BRANCHES | Branch allowlist for switch_mode. Set * for any branch | | LOOKER_RESET_BRANCHES | Branches where reset_to_remote is allowed (defaults to none) | | LOOKER_SANDBOX_FOLDER_ID | Restrict dashboard saves to folder |


Configuration

| Variable | Required | Default | Description | |----------|----------|---------|------------| | LOOKER_BASE_URL | Yes | — | Looker instance URL | | LOOKER_CLIENT_ID | Yes | — | API client ID | | LOOKER_CLIENT_SECRET | Yes | — | API client secret | | LOOKER_PROJECT_ID | No | '' | LookML project ID | | LOOKER_ALLOWED_BRANCHES | No | * | Branch allowlist for switch_mode. * = any branch | | LOOKER_RESET_BRANCHES | No | '' (none) | Branches where reset_to_remote is allowed. Must be explicit | | LOOKER_SANDBOX_FOLDER_ID | No | — | Default folder for import_lookml_dashboard | | SKIP_UPSTREAM | No | — | Set to 1 to disable upstream bridge |


How It Compares

| Capability | Google Looker MCP | This Shim | |-----------|------------------|----------| | LookML file CRUD | \u2705 | \u2705 (via upstream bridge) | | Run dashboard (full) | \u2705 | \u2705 (via upstream bridge) | | Per-tile inspection | \u274c | \u2705 fields, filters, vis_config, filter wiring | | Per-tile compiled SQL | \u274c | \u2705 run_tile format=sql | | Create/update/delete tiles | \u274c | \u2705 with partial merge | | Create/update/delete filters | \u274c | \u2705 | | Reset to remote | \u274c | \u2705 | | Dev/prod mode + branch | \u274c atomic | \u2705 atomic switch | | SDK method discovery | \u274c | \u2705 retrieve + describe from swagger | | Arbitrary SDK execution | \u274c | \u2705 with safety proxy | | Long query handling | \u274c | \u2705 120s timeout + async fallback | | Total tools | 41 | 57 (17 shim + 41 bridged, 1 shared name) |

You only register one server. It bridges the upstream automatically.


Tech Stack

| Component | Package | Purpose | |-----------|---------|--------| | Runtime | Node.js >=20 (ESM) | Modern JavaScript | | Language | TypeScript ^5.7 | Type safety | | Looker SDK | @looker/sdk-node | Auth, session, API | | MCP Server | @modelcontextprotocol/sdk | Server + Client (for bridge) | | Upstream | @toolbox-sdk/server | Google's Looker MCP (bridged) | | Testing | @luutuankiet/mcp-proxy-shim | Passthru REST testing |

License

MIT