dbt-mcp is an MCP (Model Context Protocol) server that exposes dbt functionality as tools to AI assistants. Built on FastMCP from the mcp SDK.
- Entry point:
src/dbt_mcp/main.py - Server:
src/dbt_mcp/mcp/server.py(DbtMCPclass,create_dbt_mcp()) - Tool infra:
src/dbt_mcp/tools/(definitions, registration, injection, toolsets, tool_names) - Tool categories:
discovery/,semantic_layer/,dbt_cli/,dbt_codegen/,dbt_admin/,lsp/,mcp_server_metadata/ - Prompts (tool descriptions):
src/dbt_mcp/prompts/ - Config:
src/dbt_mcp/config/ - Tests:
tests/unit/,tests/integration/
Tools follow a consistent pattern:
@dbt_mcp_tooldecorator defines the tool with metadataToolNameenum intools/tool_names.py— every tool needs an entry- Toolset mapping in
tools/toolsets.py— maps tools to categories - Context injection via
adapt_context()— tools receive typed context objects, but MCP only sees user-facing params register_tools()intools/register.py— precedence-based enablement (individual > toolset > default)
Tools can have associated UIs via the meta field:
meta={"ui": {"resourceUri": "ui://dbt-mcp/app-name"}}on@dbt_mcp_toolstructured_output=Truerequired so the host can pass structured JSON to the UI- Return type should be a Pydantic model
- Register matching resource with
@dbt_mcp.resource(uri=..., mime_type="text/html;profile=mcp-app") - Frontend uses
@modelcontextprotocol/ext-appsSDK
task test:unit— run unit teststask test:integration— run integration tests (requires dbt Platform credentials)task install— install dependenciestask check— run linting and type checking. Run before every PR push.task fmt— format codetask docs:generate— regenerate README tool list and d2 diagram from tool definitions (run after adding/removing tools)task dev— run server with streamable-http transporttask inspector— run with MCP Inspectoruv run pytest tests/ --ignore=tests/integration -x -q— quick unit test run
- This is an open-source repo. Do not include internal links (Notion, Slack, Jira) or internal details in PR descriptions, commit messages, or code comments. Keep PR descriptions focused on the public-facing what and why.
- Run
task checkbefore every PR push - Run
task test:unitbefore every commit to catch failures early
- See
.cursor/rules/python.mdcfor Python conventions - Import at top of file, type annotations on all functions
- Prefer Pydantic models or dataclasses over dicts
- Use
*in param lists when adjacent params share a type - Avoid code in
__init__.py
Every PR requires a changelog entry. Run changie new --kind "<kind>" --body "<description>" to create one.
Valid kinds: Breaking Change (major), Enhancement or New Feature (minor), Under the Hood (patch), Bug Fix (patch), Security (patch). See CONTRIBUTING.md for full contributing guidelines.
MockFastMCPintests/conftest.pycaptures registered tools and their kwargs (includingmeta)- Tool definition tests:
tests/unit/tools/test_definitions.py - Precedence logic tests:
tests/unit/tools/test_precedence.py