Python SDK for Tableau Hosted MCP
Project description
tableau-hosted-mcp
Python SDK for Tableau Hosted MCP. Handles OAuth 2.1
PKCE via a CIMD-registered public client, persists tokens locally, and exposes
both an async and sync API plus a tableau-mcp CLI. Ready to drop into an LLM
agent — the MCP tool schemas map 1:1 to Anthropic and OpenAI tool-use formats.
Install
pip install tableau-hosted-mcp
Requires Python 3.11+.
First run
The first call opens a browser tab to sso.online.tableau.com. Sign in once —
tokens are persisted to the platform's user-config directory (resolved via
platformdirs) and reused on
subsequent runs.
| Platform | Default cache directory |
|---|---|
| macOS | ~/Library/Application Support/tableau-hosted-mcp/ |
| Linux | ~/.config/tableau-hosted-mcp/ (respects $XDG_CONFIG_HOME) |
| Windows | %LOCALAPPDATA%\tableau-hosted-mcp\tableau-hosted-mcp\ |
Override with the TABLEAU_MCP_CONFIG_DIR env var if you want tokens on an
encrypted volume, a shared drive, or an ephemeral location. Storage is a
SQLite-backed key-value store (via diskcache under py-key-value-aio); no
native binaries, works identically on all three platforms.
The easiest way to warm up the token cache is:
tableau-mcp login
Library usage (async)
import asyncio
from tableau_hosted_mcp import TableauHostedClient
async def main():
async with TableauHostedClient() as client:
tools = await client.list_tools()
print(f"{len(tools)} tools available")
result = await client.call_tool("list-projects", {})
# result is fastmcp.client.client.CallToolResult:
# .is_error: bool
# .content: list[mcp.types.ContentBlock] (text/image/resource)
# .structured_content: dict | None
# .data: Any
print(result.content[0].text)
asyncio.run(main())
Also available: list_resources(), list_prompts(), and .fastmcp for direct
access to the underlying fastmcp.Client if you need something the wrapper
doesn't expose.
Library usage (sync)
For scripts, notebooks, Django management commands, or anything without an event loop:
from tableau_hosted_mcp import TableauHostedClientSync
with TableauHostedClientSync() as client:
tools = client.list_tools()
result = client.call_tool("list-projects", {})
The sync facade runs a dedicated background thread with its own asyncio loop. The connection persists across method calls — you pay OAuth cost once, not per call. Do not share a single instance across threads.
CLI
tableau-mcp login # run the OAuth flow, persist tokens
tableau-mcp logout # clear stored tokens (recovery for stale-cache errors)
tableau-mcp doctor # diagnose config + connectivity (CIMD reachable, MCP
# reachable, live list_tools round-trip)
tableau-mcp list-tools # list available MCP tools
tableau-mcp call-tool NAME [--arg key=value ...] [--json '{"k": "v"}']
# invoke a tool, print JSON result
tableau-mcp playground # open the Streamlit UI playground (requires [playground] extra)
tableau-mcp --version
tableau-mcp --log-level DEBUG # verbose httpx + MCP protocol logs
Every subcommand honours the same env-var-driven config as the library API (see below).
Configuration
Settings reads from four sources, highest precedence first:
- Constructor kwargs —
Settings(server_url=..., verify_ssl=False) - Environment variables (prefix
TABLEAU_MCP_):TABLEAU_MCP_SERVER_URL(defaulthttps://mcp.tableau.com)TABLEAU_MCP_CIMD_URL(default your CIMDclient.jsonURL)TABLEAU_MCP_CONFIG_DIRTABLEAU_MCP_LOG_LEVELTABLEAU_MCP_VERIFY_SSLTABLEAU_MCP_TIMEOUT
.envfile in the current working directory- Built-in defaults
Settings.from_file(path, **overrides) also loads a JSON config file.
Exceptions
from tableau_hosted_mcp import (
TableauHostedMCPError, # base — catch this to handle any SDK failure
ConfigurationError, # invalid settings
AuthenticationError, # OAuth failed even after auto-retry with cleared tokens
ConnectionError, # transport failure reaching the MCP server (httpx-level)
)
connect() automatically retries once on the stale-cache OAuth 500 pattern
by clearing the token store and re-authenticating. If that retry also fails,
you get an AuthenticationError. That means the manual logout && login
recovery step is normally invisible to callers.
Using it inside an LLM agent
The MCP tool schemas exposed by client.list_tools() are plain JSON Schema
objects (mcp.types.Tool.inputSchema). They map 1:1 to the tool-use formats
used by:
- Anthropic API —
input_schemafield on tool specs - OpenAI API —
parametersfield on function specs - Any framework built on those primitives (LangChain, LlamaIndex, etc.)
The pattern for a manual agent loop is:
tools = await client.list_tools()— the 24 Tableau MCP tools- Convert each
Toolto your LLM's tool spec (change the wrapper keys) - Pass the user's question + the tool specs to the LLM
- LLM responds with tool_use blocks
- For each tool_use,
await client.call_tool(name, arguments) - Feed the tool results back as the next user message
- Loop until the LLM returns a final text answer
See examples/04_claude_agent.py for a complete working implementation.
Examples
The examples/ directory contains runnable scripts:
| File | What it shows |
|---|---|
01_quickstart_async.py |
Connect, list tools, call list-projects. |
02_quickstart_sync.py |
Same flow with the sync facade — no asyncio in your code. |
03_data_pipeline.py |
Chain search-content → get-workbook → list-views → get-view-data. Pure-SDK, no LLM. |
04_claude_agent.py |
Wire the MCP tools into an Anthropic Claude agent loop. |
05_openai_compat_agent.py |
Same loop against any OpenAI-compatible endpoint (OpenAI, Groq, Together, Ollama, LM Studio, …). |
Run any of them from the repo root:
python examples/01_quickstart_async.py
The Claude example needs pip install anthropic and
export ANTHROPIC_API_KEY=sk-ant-....
The OpenAI-compat example needs pip install openai and OPENAI_API_KEY.
Point at a non-OpenAI endpoint via OPENAI_BASE_URL, e.g.
export OPENAI_BASE_URL=http://localhost:11434/v1 # Ollama
export OPENAI_MODEL=qwen2.5-coder:14b
export OPENAI_API_KEY=ollama # placeholder, endpoint ignores it
python examples/05_openai_compat_agent.py
Playground
A Streamlit UI for exploring the SDK interactively — pick tools from a dropdown, run them with an auto-generated form, chat with an LLM that has the tools wired up, and inspect diagnostics + settings.
Install and launch:
pip install "tableau-hosted-mcp[playground]"
tableau-mcp playground
Four tabs:
- Tool Explorer — every MCP tool's JSON schema becomes a form; run it and see JSON / images / structured content rendered in place.
- Agent Chat — switch between Anthropic (Claude) and OpenAI-compatible endpoints, watch each tool call unfold in a collapsible expander.
- Diagnostics — live version of
tableau-mcp doctorplus token cache contents. - Settings — resolved effective values, which env vars are present, and
the
.envfile's contents.
Set ANTHROPIC_API_KEY and/or OPENAI_API_KEY (and OPENAI_BASE_URL for
non-OpenAI endpoints) before launching if you want the chat tab.
Troubleshooting
OAuth 500 from sso.online.tableau.com — the SDK auto-retries after
clearing the token cache; you should rarely see this bubble up. If it persists,
run tableau-mcp logout and try again, or open your CIMD document
(TABLEAU_MCP_CIMD_URL) in a browser to confirm it's serving valid JSON.
"Client failed to connect" with a stack trace — run tableau-mcp doctor.
It probes CIMD reachability, MCP endpoint reachability, and full auth
round-trip, and points at whichever step failed.
Tokens on the wrong tenant — tableau-mcp logout clears the stored token
for the current TABLEAU_MCP_SERVER_URL value; run it before switching
tenants.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tableau_hosted_mcp-0.1.0a1.tar.gz.
File metadata
- Download URL: tableau_hosted_mcp-0.1.0a1.tar.gz
- Upload date:
- Size: 24.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc90d5bd2dd2e2f0f3aaa33cf493bcb25e22a76ff5270a82c6423cc3728073ae
|
|
| MD5 |
2035a17af0b343189c1ac3dc2cecb54c
|
|
| BLAKE2b-256 |
de04bc6e719d59aab806822dac3c74e5e813711f5b6ec2f3020653730ac53b25
|
Provenance
The following attestation bundles were made for tableau_hosted_mcp-0.1.0a1.tar.gz:
Publisher:
publish.yml on mok3bat/tableau-hosted-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tableau_hosted_mcp-0.1.0a1.tar.gz -
Subject digest:
cc90d5bd2dd2e2f0f3aaa33cf493bcb25e22a76ff5270a82c6423cc3728073ae - Sigstore transparency entry: 2072325737
- Sigstore integration time:
-
Permalink:
mok3bat/tableau-hosted-mcp@0c2598bc59367b6f58ae9693cb153228bd907fbc -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/mok3bat
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c2598bc59367b6f58ae9693cb153228bd907fbc -
Trigger Event:
push
-
Statement type:
File details
Details for the file tableau_hosted_mcp-0.1.0a1-py3-none-any.whl.
File metadata
- Download URL: tableau_hosted_mcp-0.1.0a1-py3-none-any.whl
- Upload date:
- Size: 24.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2810295e552f126d61b9888902c524a15e92e4b9a71d64971b2a9634676cac1e
|
|
| MD5 |
b5b33ab6e26e4f401130baa710071564
|
|
| BLAKE2b-256 |
1d6ea98721e7e1dd343acdacfa8f69c99c5aeea917db22f532a0098efe1f5cd4
|
Provenance
The following attestation bundles were made for tableau_hosted_mcp-0.1.0a1-py3-none-any.whl:
Publisher:
publish.yml on mok3bat/tableau-hosted-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tableau_hosted_mcp-0.1.0a1-py3-none-any.whl -
Subject digest:
2810295e552f126d61b9888902c524a15e92e4b9a71d64971b2a9634676cac1e - Sigstore transparency entry: 2072325805
- Sigstore integration time:
-
Permalink:
mok3bat/tableau-hosted-mcp@0c2598bc59367b6f58ae9693cb153228bd907fbc -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/mok3bat
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c2598bc59367b6f58ae9693cb153228bd907fbc -
Trigger Event:
push
-
Statement type: