Labsco
imgwho logo

cwtwb

β˜… 35

from imgwho

ai generate tableau file

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup

cwtwb

Datacooper logo

Tableau workbook engineering for reproducible .twb / .twbx generation, validation, and migration.

cwtwb hero image

cwtwb is a Python toolkit and Model Context Protocol (MCP) server for building Tableau Desktop workbooks from code or agent tool calls.

It is meant to be a workbook engineering layer, not a conversational analytics agent. The focus is reproducibility, inspectability, and safe automation in local workflows, scripts, and CI.

The cw in cwtwb comes from Cooper Wenhua.

Author: Cooper Wenhua <imgwho@gmail.com>

Website Β· Source Β· Changelog

PyPI Downloads

Star History Chart

Try the example workflow Β· Read the guide

Highlights

AreaWhat you get
Workbook authoringGenerate .twb / .twbx files from templates or from scratch
Chart buildingBuild bar, line, pie, map, KPI, and dual-axis workbooks
SafetyValidate structure, Tableau XSD (2026.1/2026.2), and REST API semantic validation before publishing
Cloud validationREST API syntactic/semantic validation + upload to Tableau Cloud/Server with optional screenshot
MigrationRepoint existing workbooks to new data sources with explicit steps
MCP supportDrive workbook workflows from Claude, Cursor, VSCode, or other MCP clients

See It In Action

This GIF shows the MCP tool flow that builds a dashboard step by step.

cwtwb demo GIF

Architecture

                            Interfaces
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
  β”‚  β”‚        MCP Server        β”‚  β”‚      Python Library       β”‚  β”‚
  β”‚  β”‚  tools_workbook          β”‚  β”‚  from cwtwb.twb_editor    β”‚  β”‚
  β”‚  β”‚  tools_validate          β”‚  β”‚  import TWBEditor         β”‚  β”‚
  β”‚  β”‚                          β”‚  β”‚                           β”‚  β”‚
  β”‚  β”‚                          β”‚  β”‚  editor.add_...()         β”‚  β”‚
  β”‚  β”‚                          β”‚  β”‚  editor.configure_...()   β”‚  β”‚
  β”‚  β”‚                          β”‚  β”‚  editor.validate_schema() β”‚  β”‚
  β”‚  β”‚  (Claude / Cursor /      β”‚  β”‚  editor.save(...)         β”‚  β”‚
  β”‚  β”‚   VSCode / Claude Code)  β”‚  β”‚                           β”‚  β”‚
  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
  β”‚                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
  └─────────────────────────────  β”Ό  β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                          TWBEditor                            β”‚
  β”‚       ParametersMixin  Β·  ConnectionsMixin                    β”‚
  β”‚       ChartsMixin      Β·  DashboardsMixin                     β”‚
  β”‚       validate_schema()  Β·  save()                            β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
             β–Ό                  β–Ό                  β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Chart Builders  β”‚  β”‚  Dashboard   β”‚  β”‚  Analysis &          β”‚
  β”‚                  β”‚  β”‚  System      β”‚  β”‚  Migration           β”‚
  β”‚  Basic  DualAxis β”‚  β”‚              β”‚  β”‚                      β”‚
  β”‚  Pie    Text     β”‚  β”‚  layouts     β”‚  β”‚  migration.py        β”‚
  β”‚  Map    Recipes  β”‚  β”‚  actions     β”‚  β”‚  twb_analyzer.py     β”‚
  β”‚                  β”‚  β”‚  dependenciesβ”‚  β”‚  capability_registry β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                    Packaged References                        β”‚
  β”‚    empty_template.twb  Β·  Superstore XLS/Hyper                β”‚
  β”‚    tableau_all_functions.json  Β·  dataset profiles            β”‚
  β”‚    vendored Tableau TWB XSD schemas (2026.1 / 2026.2)         β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                     XML Engine  (lxml)                        β”‚
  β”‚    template.twb/.twbx  β†’  patch  β†’  validate  β†’  save        β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β–Ό
                      output.twb  /  output.twbx
                                  β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚               Cloud Validation (optional)                    β”‚
  β”‚    validate_workbook_api β†’ REST API semantic validation      β”‚
  β”‚    upload_workbook       β†’ Tableau Cloud/Server publish      β”‚
  β”‚    screenshot_workbook   β†’ capture view for visual check     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Mermaid view:

flowchart TD
    subgraph Interfaces
        MCP["MCP Server<br/>tools_workbook<br/>tools_validate"]
        PY["Python Library<br/>TWBEditor API"]
    end

    subgraph Editor["Core Editor"]
        TWB["TWBEditor<br/>parameters Β· connections<br/>charts Β· dashboards<br/>validate_schema Β· save"]
    end

    subgraph Builders["Workbook Systems"]
        CHARTS["Chart Builders<br/>basic Β· dual-axis<br/>pie Β· text Β· map Β· recipes"]
        DASH["Dashboard System<br/>layouts Β· actions<br/>dependencies"]
        ANALYSIS["Analysis & Migration<br/>migration.py<br/>twb_analyzer.py<br/>capability_registry"]
    end

    subgraph References["Packaged References"]
        REFS["empty_template.twb<br/>Superstore XLS/Hyper<br/>Tableau functions<br/>TWB XSD schemas"]
    end

    subgraph Engine["XML Engine"]
        XML["lxml patch pipeline<br/>template.twb/.twbx β†’ patch β†’ validate β†’ save"]
    end

    subgraph Outputs
        OUT["output.twb / output.twbx"]
        CLOUD["Cloud Validation<br/>REST semantic validation<br/>upload Β· screenshot"]
    end

    MCP --> TWB
    PY --> TWB
    TWB --> CHARTS
    TWB --> DASH
    TWB --> ANALYSIS
    CHARTS --> XML
    DASH --> XML
    ANALYSIS --> XML
    REFS --> TWB
    REFS --> XML
    XML --> OUT
    OUT --> CLOUD

The reference layer is packaged with the library so agents and scripts can start from known-good workbook assets, resolve Tableau calculation syntax, run Hyper-backed examples, and validate against local XSD schemas without relying on a checked-out repository.

Agent Architecture

cwtwb is designed for tool-using agents, not just direct Python calls. The MCP server gives agents a small, stateful workbook editing surface; skill resources give phase-specific Tableau guidance before each set of tool calls.

Human or agent prompt
        |
        v
MCP server instructions
        |
        v
Skill resources
calculation_builder -> chart_builder -> dashboard_designer -> formatting -> validation
        |
        v
Workbook tools
create/open -> list_fields -> add/configure -> layout -> save -> validate/upload
        |
        v
TWB/TWBX artifact + validation evidence

Prompts explain what to build. Skills explain how to build it well. Tools make the workbook changes inspectable and repeatable.

Capability Boundary

cwtwb keeps its public surface intentionally small:

LevelMeaning
CoreStable primitives for normal SDK docs, examples, and MCP workflows
AdvancedSupported compositions and interaction patterns with more moving parts
RecipeShowcase patterns exposed through configure_chart_recipe, not one tool per chart

Use list_capabilities or describe_capability when an agent needs to check whether a requested chart or workbook feature belongs in the stable surface.

Design Decisions

  • The MCP server uses a stateful session model: open or create a workbook, mutate it through explicit tools, then call save_workbook.
  • Skills are phase-specific operating guides, not generic prompt stuffing.
  • save_workbook, validate_workbook, validate_workbook_api, and upload_workbook have separate responsibilities so agents do not confuse writing, local checks, semantic validation, and publishing.
  • The capability registry keeps the product boundary explicit instead of letting showcase examples become accidental API promises.

Validation

cwtwb provides four levels of workbook validation:

LevelDescriptionRequires
1. Local XSDValidate against the official Tableau TWB XSD schema (version-aware: 2026.1 or 2026.2)None (built-in)
2. REST API SyntacticValidate XML syntax via Tableau Cloud REST APITableau credentials + Tableau Cloud 2026.2+
3. REST API SemanticFull semantic validation β€” guarantees the workbook opens in TableauTableau credentials + Tableau Cloud 2026.2+
4. Upload + ScreenshotPublish to Tableau Cloud/Server and capture a view imageTableau credentials + pip install "cwtwb[validate]"
# Level 1 β€” Local XSD (in-memory, no save required)
result = editor.validate_schema()
print(result.to_text())

# Level 3 β€” REST API semantic validation
from cwtwb.validate.uploader import TableauUploader
uploader = TableauUploader(env_path="project/.env")
result = uploader.validate("output.twb", validation_level="semantic")

# Save with local XSD validation; REST API semantic validation also runs when .env is configured
editor.save("output.twb")
# MCP tools
validate_workbook(file_path="output.twb")                                       # Local XSD validation
validate_workbook_api(twb_path="output.twb", validation_level="semantic")        # REST API validation
validate_workbook_api(twb_path="output.twb", env_path="project/.env")            # Runtime credentials
upload_workbook(twb_path="output.twb")                                          # Cloud upload
screenshot_workbook(workbook_id="...", view_name="Sheet 1")                     # Visual check

Documentation