secoda-analysis-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@secoda-analysis-mcp How is Gross Margin calculated?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Secoda Analysis MCP Server
A read-only Model Context Protocol (MCP) server for exploring and analysing your Secoda data catalog. Designed for business users who need to discover data, look up metric definitions, and understand data lineage — without any risk of modifying the catalog.
Features
Zero write access — completely safe to use; nothing in Secoda can be changed
AI chat — ask Secoda's AI natural language questions about your data
Semantic search — find tables, columns, dashboards, and documentation by keyword
Glossary & definitions — browse business term definitions
Data lineage — trace where data comes from and where it flows downstream
Browse collections & Q&A — explore organised resource groups and previously answered questions
Related MCP server: starrocks-mcp
Tools
Tool | Purpose |
| Ask Secoda AI a natural language question (supports multi-turn conversations) |
| Find tables, columns, charts, and dashboards by keyword |
| Find docs, glossary terms, and Q&A by keyword |
| Get full details of any entity by its Secoda ID |
| Get full details of a catalog resource (table, column, view) by ID |
| Browse and filter resources using structured criteria |
| Trace upstream/downstream data flow for any entity |
| Browse all business term definitions in the workspace |
| Browse organised groups of resources |
| Get details of a specific collection |
| Browse previously asked and answered Q&A threads |
| Read a specific question and its answer |
Requirements
Python 3.10+
A Secoda account with API access
A Secoda API token (read permissions are sufficient)
Setup
1. Get your Secoda API token
Generate a token at Secoda → Settings → API. Read permissions are sufficient.
2. Install with uvx (recommended)
No manual install needed — your MCP client runs the server automatically via uvx.
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"secoda-analysis": {
"command": "uvx",
"args": ["secoda-analysis-mcp"],
"env": {
"API_TOKEN": "your-secoda-api-token"
}
}
}
}Cursor — add to .cursor/mcp.json:
{
"mcpServers": {
"secoda-analysis": {
"command": "uvx",
"args": ["secoda-analysis-mcp"],
"env": {
"API_TOKEN": "your-secoda-api-token"
}
}
}
}3. Alternative: pip install
pip install secoda-analysis-mcpThen replace the uvx block above with "command": "secoda-analysis-mcp" and "args": [].
4. Claude Desktop bundle (.mcpb) — for organisation-wide distribution
A .mcpb (MCP Bundle) is a ZIP archive that Claude Desktop installs via drag-and-drop — no manual config editing required. The bundle auto-installs all Python dependencies on first run; the only prerequisite is Python 3.9+.
Two manifests live in bundle/:
File | Purpose | Git |
| Generic — prompts the user for credentials at install time via Claude's UI | Committed |
| Org-specific — credentials hardcoded for silent deployment | Gitignored — never commit |
Building an org bundle:
# 1. Create your org manifest (one-time setup)
cp bundle/manifest.template.json bundle/manifest.jsonEdit bundle/manifest.json and set your values in mcp_config.env:
"env": {
"API_TOKEN": "your-secoda-api-token",
"API_URL": "https://your-org.secoda.co/api/v1/",
"AI_PERSONA_ID": "your-persona-uuid"
}AI_PERSONA_ID is optional — omit it to use the workspace default persona.
# 2. Build the bundle
chmod +x bundle/build.sh
./bundle/build.sh
# → dist/miinto-secoda-analyst.mcpb (gitignored)Distributing: Share dist/*.mcpb with colleagues. They drag-and-drop it onto Claude Desktop → Settings → Developer. Works on macOS and Windows.
Security:
bundle/manifest.jsonanddist/are both gitignored. Only the credential-free template is committed. Never add credentials to any file tracked by git.
Configuration
Variable | Description | Default |
| Your Secoda API token (required) | — |
| Secoda API base URL |
|
| Secoda AI persona ID — pins a specific persona for all | workspace default |
Example workflows
Ask a business question
ai_chat(prompt="How is Gross Margin calculated and what tables does it use?")Find a table and explore its schema
# 1. Find the table
search_data_assets(query="order lines")
# 2. Get full details (columns, description, tags)
get_resource(resource_id="<id-from-search>", truncate_length=None)Understand data lineage
# Find the entity first
search_data_assets(query="my_important_table")
# Then trace its lineage
entity_lineage(entity_id="<id-from-search>")License
Apache License 2.0 — see LICENSE for details.
Development
Setup
Clone the repo and install all dependencies (including dev tools) with uv:
git clone https://github.com/mbrummerstedt/secoda-analysis-mcp.git
cd secoda-analysis-mcp
uv sync --extra devCopy .env.example to .env and fill in your credentials:
cp .env.example .envProject structure
secoda-analysis-mcp/
├── src/
│ └── secoda_analysis/ # Main package
│ ├── __init__.py
│ ├── __main__.py # python -m secoda_analysis entrypoint
│ ├── server.py # FastMCP server setup and tool registration
│ ├── prompt.py # MCP system prompt (tool guidance for the LLM)
│ ├── core/
│ │ ├── client.py # HTTP client with retry logic
│ │ ├── config.py # Environment variable configuration
│ │ └── models.py # Pydantic models (filter/sort validation)
│ └── tools/
│ ├── ai_chat.py # AI chat tool (submit + poll)
│ ├── collections.py # list_collections, get_collection
│ ├── entity.py # retrieve_entity, entity_lineage, glossary
│ ├── questions.py # list_questions, get_question
│ ├── resources.py # list_resources, get_resource
│ └── search.py # search_data_assets, search_documentation
├── tests/
│ ├── conftest.py # Root fixtures (env var defaults)
│ ├── mock/ # Unit tests — all HTTP calls mocked
│ │ ├── conftest.py # Shared mock fixtures and response payloads
│ │ ├── test_client.py
│ │ ├── test_models.py
│ │ ├── test_prompt.py
│ │ ├── test_tools_ai_chat.py
│ │ ├── test_tools_collections.py
│ │ ├── test_tools_entity.py
│ │ ├── test_tools_questions.py
│ │ ├── test_tools_resources.py
│ │ └── test_tools_search.py
│ └── integration/ # Integration tests — hit the real Secoda API
│ ├── conftest.py # Auto-skip when API_TOKEN is not set
│ ├── test_ai_chat.py
│ ├── test_collections.py
│ ├── test_entity.py
│ ├── test_questions.py
│ ├── test_resources.py
│ └── test_search.py
├── pyproject.toml
├── .env.example
└── .python-versionArchitecture
LLM / MCP client
│ MCP protocol (stdio)
▼
server.py ──── registers tools from tools/*.py
│
├── tools calling Secoda AI MCP endpoint
│ tools/search.py, entity.py
│ │
│ └── core/client.py call_tool()
│ │
│ └── POST {API_URL}/ai/mcp/tools/call/
│
├── tools making direct REST calls
│ tools/resources.py, collections.py, questions.py
│ │
│ └── core/client.py _make_request_with_retry()
│ │
│ └── GET {API_URL}/resource/... etc.
│
└── ai_chat tool (submit + poll)
tools/ai_chat.py
│
└── POST/GET {base_url}/ai/embedded_prompt/All tools are read-only — there are no write, update, or delete operations.
Running tests
Mock tests (no credentials required, fast):
uv run pytest tests/mock/ -vIntegration tests (requires a valid API_TOKEN in your .env):
uv run pytest tests/integration/ -vIntegration tests hit the live Secoda API. The
ai_chattests are slow (30–120s each) as they wait for the AI to respond.
All tests:
uv run pytest -vIntegration tests are automatically skipped when API_TOKEN is not set.
Code style
This project uses Ruff for linting and formatting, and mypy for type checking.
# Lint
uv run ruff check src/ tests/
# Format
uv run ruff format src/ tests/
# Type check
uv run mypy src/Available Tools
12 toolsai_chatA
Start an AI chat session in Secoda and wait for the response.
Submits a prompt to the Secoda embedded AI endpoint and polls until the
response is complete. Sends MCP progress notifications at each poll interval
so clients can show elapsed time. Returns the AI's response text along with
the chat ID, which can be passed as `parent` in a follow-up call to continue
the conversation.
Args:
prompt: The message or question to send to the Secoda AI.
ctx: MCP context (injected by FastMCP; not part of the tool schema).
parent: Chat ID of a previous conversation to continue (optional).
Pass the chat_id from a previous ai_chat response to maintain context.
persona_id: Persona ID to use for the AI chat (optional).
Defaults to AI_PERSONA_ID env var if set, otherwise the workspace default persona.
poll_interval_seconds: Seconds between polling attempts (default: 10).
timeout_seconds: Maximum seconds to wait for completion (default: 360).
Returns:
JSON with keys:
- success: true
- chat_id: The ID of this chat (use as `parent` in follow-up calls)
- status: "completed"
- response_content: The AI's response text
Example:
# Start a new conversation
ai_chat(prompt="How do we handle price reductions in GMV calculations?")
# Continue a previous conversation
ai_chat(
prompt="Can you elaborate on the discount logic?",
parent="0d53d57b-d1ef-4fc2-bc50-fd3fba2fea93"
)
Error handling:
- 403: Permission denied - check API token has AI chat permissions
- 429: Rate limit exceeded - tool retries automatically
- Timeout: Increase timeout_seconds if the AI takes longer than expectedInputs: prompt (required), parent, persona_id, poll_interval_seconds, +1 more. Returns: result
entity_lineageA
Retrieve the upstream and downstream lineage of an entity.
Args:
entity_id: The ID of the entity to get lineage for
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
Entity lineage with text fields truncated to specified lengthInputs: entity_id (required), truncate_length. Returns: result
get_collectionA
Retrieve a specific collection by its ID.
Use this to get full details about a collection after finding it via list_collections.
Args:
collection_id: The unique identifier of the collection
truncate_length: Maximum characters for text fields in results (default: 150).
Set to None for full descriptions.
Returns:
Collection details with text fields truncated to specified length
Example:
get_collection(collection_id="collection-123")Inputs: collection_id (required), truncate_length. Returns: result
get_questionA
Retrieve a specific question and its answer by ID.
Use this to read the full content of a question and any accepted answers after
finding it via list_questions or search_documentation.
Args:
question_id: The unique identifier of the question
truncate_length: Maximum characters for text fields in results (default: 150).
Set to None to read the full question and answer text.
Returns:
Question details including title, description, and answersInputs: question_id (required), truncate_length. Returns: result
get_resourceA
Retrieve a specific resource by its ID.
Use this to get full details of a catalog resource (table, column, view, etc.)
after finding it through list_resources or search_data_assets.
Args:
resource_id: The unique identifier of the resource to retrieve
truncate_length: Maximum characters for text fields in results (default: 150).
Set to None when you need full descriptions/definitions.
Returns:
Resource details with text fields truncated to specified lengthInputs: resource_id (required), truncate_length. Returns: result
glossaryA
Retrieve all business term definitions from the workspace glossary.
Args:
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
Glossary with text fields truncated to specified lengthInputs: truncate_length. Returns: result
list_collectionsA
List all collections in the workspace.
Collections are organized groups of related resources (tables, dashboards, documents).
Use this to browse what topic areas and resource groups exist.
Args:
title: Filter collections by title (optional)
page: Page number for pagination (default: 1)
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
List of collections with text fields truncated to specified length
Example:
list_collections(title="Customer")
list_collections(page=2)Inputs: title, page, truncate_length. Returns: result
list_questionsA
List all questions in the workspace.
Questions in Secoda represent data consumer inquiries that have been asked and
answered by the data team. Use this to find existing answers before asking
a new question.
Args:
page: Page number for pagination (default: 1)
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
List of questions with text fields truncated to specified lengthInputs: page, truncate_length. Returns: result
list_resourcesA
List catalog resources with advanced filtering capabilities.
This endpoint provides precise control over resource queries using structured filters.
Use this when you need exact matching, specific field filtering, or complex queries.
Args:
filter: FilterOperand (field or logical) for filtering resources
sort: SortConfig for ordering results
page: Page number for pagination (default: 1)
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
Paginated list of resources matching the filter criteria
Filter Examples:
# Single condition - title contains
filter = {"operator": "contains", "field": "title", "value": "order_lines"}
# Single condition - entity type
filter = {"operator": "exact", "field": "native_type", "value": "table"}
# Find all columns of a specific table
filter = {"operator": "exact", "field": "parent_id", "value": "table-id-123"}
# Multiple conditions with AND
filter = {
"operator": "and",
"operands": [
{"operator": "exact", "field": "native_type", "value": "table"},
{"operator": "contains", "field": "title", "value": "customer"}
]
}
Sort Examples:
# Sort by title ascending
sort = {"field": "title", "order": "asc"}
# Sort by external_usage descending (most popular first)
sort = {"field": "external_usage", "order": "desc"}Inputs: filter, sort, page, truncate_length. Returns: result
retrieve_entityB
Retrieve an entity from the catalog by ID.
Args:
entity_id: The ID of the entity to retrieve
truncate_length: Maximum characters for text fields in results (default: 150).
Often useful to set to None when you need full descriptions/definitions.
Returns:
Entity details with text fields truncated to specified lengthInputs: entity_id (required), truncate_length. Returns: result
search_data_assetsA
Search for data assets in the catalog.
Args:
query: Search query for finding tables, columns, charts, dashboards
page: Page number for pagination (default: 1)
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
Search results with text fields truncated to specified lengthInputs: query (required), page, truncate_length. Returns: result
search_documentationA
Search for documentation in the catalog.
Args:
query: Search query for finding documents, questions, glossary terms
page: Page number for pagination (default: 1)
truncate_length: Maximum characters for text fields in results (default: 150)
Returns:
Search results with text fields truncated to specified lengthInputs: query (required), page, truncate_length. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Most tools have distinct purposes, but 'get_resource' and 'retrieve_entity' overlap significantly, both retrieving a catalog item by ID. This creates ambiguity for an agent about which to use.
Most tools follow a verb_noun pattern (e.g., get_collection, list_resources), but 'entity_lineage' and 'glossary' are noun-only names, breaking consistency. The pattern is mostly readable but not uniform.
With 12 tools, the set is well-scoped for a data catalog analysis server. It covers listing, retrieval, search, and AI chat without being bloated.
The tools cover core read operations (list, get, search) and AI chat, but miss a dedicated tool to retrieve a single glossary term by ID. For an analysis server, this is a minor gap.
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
One governed MCP endpoint for 40+ business systems. Read-only, source-cited answers.
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Related MCP Servers
- AlicenseCqualityDmaintenanceA read-only MCP server that enables users to query Databricks SQL, browse metadata, and monitor Delta Lake tables. It also supports tracking Databricks Jobs, DLT Pipelines, and cluster metrics through natural language interfaces.254MIT
- AlicenseAqualityDmaintenanceA read-only MCP server that enables users to query and explore StarRocks databases through AI assistants like Claude. It supports SQL execution, schema discovery, and secure LDAP authentication for data analysis and metadata exploration.41MIT
- AlicenseAqualityDmaintenanceRead-only MCP server for Microsoft SQL Server that retrieves connection details from AWS Secrets Manager, enabling database exploration and querying via natural language.129 npmMIT
- AlicenseAqualityDmaintenanceA read-only MCP server that provides AI coding tools with database schema structure (tables, columns, keys, relationships) without exposing row data.3Apache 2.0