tableau-audit-mcp
Tableau Workbook Audit MCP Server
An MCP server that audits local Tableau workbooks (.twb / .twbx) for:
Unused assets — worksheets never embedded on a dashboard, calculated fields nothing depends on (directly or transitively), parameters never referenced, and groups/sets never used.
Duplicate worksheets — near-identical sheets flagged via a weighted similarity score (shared fields, mark type, filter overlap), so you know what to consolidate.
Dashboard weight — a load-time risk score per dashboard (worksheet count, filter/action/web-object counts, embedded extract size) with concrete recommendations.
No Tableau Server/Cloud connection required — it works entirely from the workbook file on disk.
Install
git clone https://github.com/Sujan2396/tableau-audit-mcp.git
cd tableau-audit-mcp
pip install -e .Or, once published, directly from PyPI:
pip install tableau-audit-mcpRun standalone (for testing)
python3 -c "
from tableau_audit import load_workbook, WorkbookGraph, find_unused_assets, analyze_dashboards, find_duplicate_worksheets, render_markdown_report
loaded = load_workbook('/path/to/your/workbook.twbx')
graph = WorkbookGraph(loaded.root)
unused = find_unused_assets(graph)
dups = find_duplicate_worksheets(graph)
dws = analyze_dashboards(graph)
print(render_markdown_report('your_workbook.twbx', unused, dups, dws, loaded.total_extract_bytes / (1024*1024)))
"Run as an MCP server
python3 server.py
# or, after `pip install -e .` / `pip install tableau-audit-mcp`:
tableau-audit-mcpRegister with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"tableau-audit": {
"command": "python3",
"args": ["/absolute/path/to/tableau-audit-mcp/server.py"]
}
}
}Tools exposed
Tool | Purpose |
| Parse + cache a workbook, return a summary |
| Unused worksheets/calcs/parameters/groups+sets |
| Near-duplicate worksheet pairs |
| Per-dashboard weight/risk score + recommendations |
| Compact scorecard: counts + structural-complexity % + load-time risk rating |
| Full combined Markdown report (recommended default) |
How the analysis works
Field usage: each
<worksheet>in the.twbXML lists exactly which columns it uses via<datasource-dependencies>. A field/calc/group/set with zero worksheet references (and, for calcs, no other used calc depending on it) is flagged unused.Parameters: unlike other fields, parameters aren't referenced via dependencies — they're used by name inside formulas, filters, actions, and titles. We scan those specifically for the parameter's name (and exclude the parameter's own definition, to avoid a trivial self-match).
Groups vs. Sets: both are stored in Tableau's XML as a
<column>with a<groupfilter>child, so we track them together asgroup_or_set. Reliably telling groups apart from sets from the XML alone is a known limitation (see below).Duplicate sheets: `0.7 × Jaccard(field usage) + 0.15 × (mark type match)
0.15 × Jaccard(filters)`. Tune the threshold per tool call — lower it to catch looser near-duplicates.
Dashboard weight: a heuristic score from worksheet count, filter/action/ web-object counts on the dashboard, plus overall embedded extract size (for
.twbxfiles). Thresholds are tunable intableau_audit/analysis.py.
Known limitations / next steps
Tableau version drift: the
.twbschema has shifted across Desktop versions (2018.x vs. 2023.x vs. Cloud). The XPath heuristics here cover the common structure; workbooks with heavy custom XML (Tableau Prep flows, very old Desktop versions) may need small adjustments ingraph.py.Group vs. Set disambiguation is currently a placeholder — both show up as
group_or_set. Both static groups/sets (a<column>with a<groupfilter>child) and dynamic sets like "Top N by..." (a separate top-level<group>element with a different attribute shape — validated against a real workbook) are parsed and tracked for usage, including parameters referenced viacount/size-parameterattributes rather than formula text. They just aren't labeled apart from each other. If you need Groups split from Sets specifically, the most reliable path is cross-referencing against the Tableau Metadata API rather than the raw XML.Dashboard action counts are currently workbook-level (Tableau doesn't always scope
<action>elements per-dashboard in older schema versions) — treat this figure as "actions in the workbook that could fire from this dashboard" rather than a strict per-dashboard count.Extract size is only available for
.twbx(packaged) workbooks, since.twbfiles reference external.hyper/.tdefiles rather than embedding them.The automated suite in
tests/test_audit.pycovers the synthetic sample workbook plus regression cases found while validating against real Tableau Public workbooks. It's not exhaustive — if you hit a workbook shape that breaks parsing, please open an issue (see CONTRIBUTING.md) with a minimal reproducing snippet.The two "Workbook Health" headline numbers are intentionally scoped honestly: structural complexity reduction % is a heuristic (documented in
compute_health_summary's docstring) based on unused-asset ratios, not a calibrated file-size prediction. Dashboard load-time risk is a qualitative Low/Medium/High rating rather than a percentage, because Tableau publishes no formula for converting static asset counts into a load-time number — for a measured value, use Tableau's own Performance Recorder.
Contributing
Contributions are welcome — see CONTRIBUTING.md for setup instructions, what kinds of contributions are most valuable, and development guidelines.
License
MIT — free to use, modify, and redistribute.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/Sujan2396/tableau_aduit_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server