Skip to main content
Glama
secoda-analysis-mcp

secoda-analysis-mcp

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

ai_chat

Ask Secoda AI a natural language question (supports multi-turn conversations)

search_data_assets

Find tables, columns, charts, and dashboards by keyword

search_documentation

Find docs, glossary terms, and Q&A by keyword

retrieve_entity

Get full details of any entity by its Secoda ID

get_resource

Get full details of a catalog resource (table, column, view) by ID

list_resources

Browse and filter resources using structured criteria

entity_lineage

Trace upstream/downstream data flow for any entity

glossary

Browse all business term definitions in the workspace

list_collections

Browse organised groups of resources

get_collection

Get details of a specific collection

list_questions

Browse previously asked and answered Q&A threads

get_question

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.

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-mcp

Then 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

manifest.template.json

Generic — prompts the user for credentials at install time via Claude's UI

Committed

manifest.json

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.json

Edit 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.json and dist/ are both gitignored. Only the credential-free template is committed. Never add credentials to any file tracked by git.

Configuration

Variable

Description

Default

API_TOKEN

Your Secoda API token (required)

—

API_URL

Secoda API base URL

https://app.secoda.co/api/v1/

AI_PERSONA_ID

Secoda AI persona ID — pins a specific persona for all ai_chat calls. Find it in Secoda → Settings → AI → Personas.

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 dev

Copy .env.example to .env and fill in your credentials:

cp .env.example .env

Project 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-version

Architecture

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/ -v

Integration tests (requires a valid API_TOKEN in your .env):

uv run pytest tests/integration/ -v

Integration tests hit the live Secoda API. The ai_chat tests are slow (30–120s each) as they wait for the AI to respond.

All tests:

uv run pytest -v

Integration 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 tools
ai_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 expected

Inputs: 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 length

Inputs: 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 answers

Inputs: 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 length

Inputs: 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 length

Inputs: 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 length

Inputs: 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 length

Inputs: 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 length

Inputs: 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 length

Inputs: 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

    A3.8/5.0

    Scored across 12 tools

    Disambiguation3/5

    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.

    Naming Consistency3/5

    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.

    Tool Count5/5

    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.

    Completeness4/5

    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

    Related MCP Servers

    • A
      license
      C
      quality
      D
      maintenance
      A 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.
      25
      4
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      A 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.
      4
      1
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Read-only MCP server for Microsoft SQL Server that retrieves connection details from AWS Secrets Manager, enabling database exploration and querying via natural language.
      12
      9 npm
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      A read-only MCP server that provides AI coding tools with database schema structure (tables, columns, keys, relationships) without exposing row data.
      3
      Apache 2.0