cwtwb
cwtwb is a Python-based MCP server for programmatically building, editing, validating, and migrating Tableau workbooks (.twb/.twbx) from code or agent tool calls (e.g., Claude, Cursor, VSCode).
Workbook Management
Create workbooks from templates or scratch, open existing ones, save as
.twbor.twbx, and validate against the official Tableau XSD schema.
Worksheet Operations
List, add, clone, hide/unhide, caption, and refactor worksheets; list available datasource fields.
Chart Building
Configure bar, line, pie, map, KPI, text, and dual-axis charts with full control over rows, columns, marks, colors, labels, filters, tooltips, sorting, and axes. Apply styles and use preset chart recipes.
Data Connections
Set up Excel, Hyper, MySQL, or Tableau Server datasource connections.
Calculated Fields & Parameters
Add/remove calculated fields with custom formulas and add parameters with ranges and allowed values.
Dashboard Authoring
Combine worksheets into dashboards with layout control, add filter/highlight/URL actions, and generate layout JSON with ASCII preview.
Guided Authoring (Agentic Workflow)
Multi-stage pipeline: datasource intake → schema inspection → analysis brief → authoring contract → wireframes → execution plan → workbook generation, with human-in-the-loop confirmation at each stage.
Migration Tools
Profile a TWB, inspect a target schema, propose field mappings, preview and apply migration, or run a guided migration with blocker/warning detection.
Analysis & Capability Inspection
Analyze TWB files against cwtwb's capability registry, diff template gaps, and list/describe server capabilities.
Allows inspecting .hyper file schemas, resolving physical table names, and using Hyper as a datasource for guided workbook authoring.
The cwtwb package is distributed via PyPI for installation with pip.
The toolkit is a Python library and MCP server that allows programmatic generation of Tableau workbooks using Python code.
Provides XML engine (lxml) for patching, validating, and saving Tableau workbook XML files.
cwtwb
Tableau workbook engineering for reproducible
.twb/.twbxgeneration, validation, and migration.
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>
Star History
Try the example workflow · Read the guide
Related MCP server: Tableau MCP Server
Quick Start
Install
pip install cwtwbIf you want the bundled Hyper-backed example too:
pip install "cwtwb[examples]"If you want cloud validation (upload to Tableau Cloud/Server):
pip install "cwtwb[validate]"Run As An MCP Server
uvx cwtwbThe short form above remains the simplest option and is the default config shown in this repository. cwtwb is a smart entrypoint: with no arguments in an interactive terminal it prints CLI help; when launched by an MCP client over stdio it starts the server.
Add the server to your MCP client with the same command. For example:
{
"mcpServers": {
"cwtwb": {
"command": "uvx",
"args": ["cwtwb"]
}
}
}For Claude Code:
claude mcp add cwtwb -- uvx cwtwbFor VSCode, add cwtwb to your workspace or user mcp.json and use uvx cwtwb as the command.
If you prefer an explicit script name, these equivalent launch styles also work:
uvx cwtwb mcp
uvx --from cwtwb cwtwb-mcp
python -m cwtwb.mcp_serverUse As A CLI
The same package also exposes first-class command-line workflows for humans, scripts, CI, and agents that need direct file operations instead of MCP tool calls.
cwtwb --help
cwtwb doctor
cwtwb status --json
cwtwb inspect workbook.twb --json
cwtwb validate workbook.twb
cwtwb analyze workbook.twb --json
cwtwb run examples/specs/basic_cli.yamlCommon write commands require an explicit output path by default:
cwtwb create --out output/base.twb
cwtwb chart add output/base.twb --worksheet "Sales by Category" --mark Bar --rows Category --columns "SUM(Sales)" --out output/chart.twb
cwtwb dashboard add output/chart.twb --name Overview --worksheets "Sales by Category" --out output/dashboard.twbUse --in-place only when you intentionally want to overwrite the input workbook, and --force only when replacing an existing output file.
MCP Client Stability
When cwtwb is connected as an MCP server, agents should call the exposed MCP tools directly through their client. They should not run shell commands such as mcp call cwtwb ..., mcp list-tools cwtwb, or gh api .../mcp/...; those commands are not part of cwtwb and are usually unavailable in normal Claude, Codex, Cursor, or VSCode environments.
If an agent cannot see tools such as create_workbook, add_worksheet, or save_workbook, restart or reconnect the MCP client and verify the server config. Clearing the uv cache only refreshes installed packages; it does not fix a stale client tool surface.
When using an existing .twb as a visual reference, agents must not copy Tableau XML column-instance tokens into chart inputs. Values such as [sum:Sales:qk], [none:Category:nk], [mn:Order Date:ok], or [federated.xxx].[sum:Profit:qk] are generated internals. Pass user-facing expressions such as Sales, SUM(Sales), Category, or MONTH(Order Date) instead.
Useful resources for agents:
cwtwb://tool-surface
cwtwb://skills/index
cwtwb://skills/dashboard_designer
file://docs/tableau_all_functions.jsonCompatibility aliases are also available for common guessed URIs such as cwtwb://docs/manual-editing, but new prompts should prefer cwtwb://tool-surface and cwtwb://skills/index.
For client-specific details and the full reference, see https://github.com/aidatacooper/cwtwb/blob/main/docs/guide.md.
Dashboard Layout Files
Custom dashboard layouts can now be authored as either JSON or YAML using the same declarative DSL. For agent workflows, generate a layout file first, then pass that file path into add_dashboard(layout=...).
generate_layout_json("output/layout.json", layout_tree, ascii_preview)
generate_layout_yaml("output/layout.yaml", layout_tree, ascii_preview)Both formats support the same wrapper structure:
layout_schema: canonical dashboard layout tree_ascii_layout_preview: optional human/agent review aid
Highlights
Area | What you get |
Workbook authoring | Generate |
Chart building | Build bar, line, pie, map, KPI, and dual-axis workbooks |
Safety | Validate structure, Tableau XSD (2026.1/2026.2), and REST API semantic validation before publishing |
Cloud validation | REST API syntactic/semantic validation + upload to Tableau Cloud/Server with optional screenshot |
Migration | Repoint existing workbooks to new data sources with explicit steps |
MCP support | Drive 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.
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 --> CLOUDThe 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 evidencePrompts 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:
Level | Meaning |
Core | Stable primitives for normal SDK docs, examples, and MCP workflows |
Advanced | Supported compositions and interaction patterns with more moving parts |
Recipe | Showcase patterns exposed through |
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, andupload_workbookhave 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:
Level | Description | Requires |
1. Local XSD | Validate against the official Tableau TWB XSD schema (version-aware: 2026.1 or 2026.2) | None (built-in) |
2. REST API Syntactic | Validate XML syntax via Tableau Cloud REST API | Tableau credentials + Tableau Cloud 2026.2+ |
3. REST API Semantic | Full semantic validation without publishing — default cloud check for | Tableau credentials + Tableau Cloud 2026.2+ |
4. Upload + Screenshot | Publish to Tableau Cloud/Server and capture a view image | Tableau credentials + |
# 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") # Default cloud semantic validation, no publish
validate_workbook_api(twb_path="output.twb", env_path="project/.env") # Runtime credentials
upload_workbook(twb_path="output.twb") # Publish/openability evidence or TWBX validation
screenshot_workbook(workbook_id="...", view_name="Sheet 1") # Visual check after upload_workbookFAQ
What is the difference between .twb and .twbx?
.twb is the workbook XML. .twbx is the packaged version that bundles the workbook together with extracts and images.
Does validate_workbook save files?
No. validate_workbook() performs local XSD validation on the active in-memory workbook or an existing .twb / .twbx file. It does not write output. save_workbook() is the tool that writes files.
What validation does save() perform?
save() runs local XSD validation automatically before replacing the final output file. For .twb output, REST API semantic validation also runs when Tableau credentials are configured and the server supports it. Use validate_workbook_api(..., validation_level="semantic") when you want to request the Tableau Cloud/Server validation step directly.
What is upload_workbook for?
upload_workbook publishes a .twb or .twbx to Tableau Cloud/Server. Use it when you explicitly need publish/openability evidence, a workbook ID for screenshots, or .twbx package validation. For the default .twb cloud semantic check, prefer validate_workbook_api because it does not publish or store the workbook. Requires pip install "cwtwb[validate]" and Tableau credentials from environment variables, an explicit env_path, TABLEAU_ENV_FILE, or a .env file next to the workbook.
How do I set up Tableau Cloud/Server validation?
Install:
pip install "cwtwb[validate]"Copy
.env.exampleto.envFill in your Tableau Cloud/Server PAT credentials
Call
save_workbookto write the.twbor.twbxCall
validate_workbook_apifor the default REST API semantic validation, orupload_workbookonly when you also want publish/openability evidence, screenshots, or.twbxvalidation
Credential lookup order is explicit env_path first, then environment variables, TABLEAU_ENV_FILE, the workbook sibling .env, the current working directory .env, the cwtwb project .env, and finally the user's home .env. Prefer env_path for one-off MCP calls instead of editing MCP server configuration and restarting the server.
If validation reports that tableauserverclient is missing, call get_mcp_status first. It reports the MCP process's Python executable, cwtwb version, and whether the Tableau client is importable without exposing credentials. An env_path change is runtime-scoped and does not require an MCP restart; installing dependencies into a different Python environment does not fix the running server, so install the validation extra into the interpreter reported by get_mcp_status and reconnect only when the runtime or tool schema changes.
When should I use uvx cwtwb versus python -m cwtwb.mcp_server?
Use uvx cwtwb for the normal MCP workflow. Use python -m cwtwb.mcp_server for local testing without uvx.
For backward compatibility, uvx --from cwtwb cwtwb-mcp, python -m cwtwb.server, and python -m cwtwb.mcp continue to work.
Where is the full guide?
See the online guide.
Documentation
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aidatacooper/cwtwb'
If you have feedback or need assistance with the MCP directory API, please join our Discord server