Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this would be considered a breaking change? One of the examples actually (if you Ctrl + F for the deleted tools), actually refers to both get_model_parents and get_model_children in examples/ag2_agent/main_multiagent.py which is a solid case of potentially existing references to these tools that would break

cc @b-per thoughts here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Same as the other PR. This should be a breaking change. We need an approach to

  • potentially move dbt-mcp to 2.x
  • plan the steps required to keep the openai and anthropic apps working

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Enhancement or New Feature
body: Remove get_model_parents and get_model_children tools; get_lineage(depth=1) provides the same information and now also returns a description field per node
time: 2026-06-22T10:30:11.723713-07:00
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,11 @@ To learn more about the dbt Discovery API, click [here](https://docs.getdbt.com/
- `get_all_sources`: Gets all sources with freshness status; option to filter by source name.
- `get_exposure_details`: Gets exposure details including owner, parents, and freshness status.
- `get_exposures`: Gets all exposures (downstream dashboards, apps, or analyses).
- `get_lineage`: Gets full lineage graph (ancestors and descendants) with type and depth filtering.
- `get_lineage`: Gets full lineage graph (ancestors and descendants) with type and depth filtering; use depth=1 to get immediate parents or children.
- `get_macro_details`: Gets details for a specific macro.
- `get_mart_models`: Retrieves all mart models.
- `get_model_children`: Gets downstream dependents of a model.
- `get_model_details`: Gets model details including compiled SQL, columns, and schema.
- `get_model_health`: Gets health signals: run status, test results, and upstream source freshness.
- `get_model_parents`: Gets upstream dependencies of a model.
- `get_model_performance`: Gets execution history for a model; option to include test results.
- `get_related_models`: Finds similar models using semantic search.
- `get_seed_details`: Gets details for a specific seed.
Expand Down
165 changes: 0 additions & 165 deletions src/dbt_mcp/discovery/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,125 +140,6 @@ class GraphQLQueries:
}
""")

COMMON_FIELDS_PARENTS_CHILDREN = textwrap.dedent("""
{
... on ExposureAppliedStateNestedNode {
resourceType
name
description
}
... on ExternalModelNode {
resourceType
description
name
}
... on MacroDefinitionNestedNode {
resourceType
name
description
}
... on MetricDefinitionNestedNode {
resourceType
name
description
}
... on ModelAppliedStateNestedNode {
resourceType
name
description
}
... on SavedQueryDefinitionNestedNode {
resourceType
name
description
}
... on SeedAppliedStateNestedNode {
resourceType
name
description
}
... on SemanticModelDefinitionNestedNode {
resourceType
name
description
}
... on SnapshotAppliedStateNestedNode {
resourceType
name
description
}
... on SourceAppliedStateNestedNode {
resourceType
sourceName
uniqueId
name
description
}
... on TestAppliedStateNestedNode {
resourceType
name
description
}
""")

GET_MODEL_PARENTS = (
textwrap.dedent("""
query GetModelParents(
$environmentId: BigInt!,
$modelsFilter: ModelAppliedFilter
$first: Int,
) {
environment(id: $environmentId) {
applied {
models(filter: $modelsFilter, first: $first) {
pageInfo {
endCursor
}
edges {
node {
parents
""")
+ COMMON_FIELDS_PARENTS_CHILDREN
+ textwrap.dedent("""
}
}
}
}
}
}
}
""")
)

GET_MODEL_CHILDREN = (
textwrap.dedent("""
query GetModelChildren(
$environmentId: BigInt!,
$modelsFilter: ModelAppliedFilter
$first: Int,
) {
environment(id: $environmentId) {
applied {
models(filter: $modelsFilter, first: $first) {
pageInfo {
endCursor
}
edges {
node {
children
""")
+ COMMON_FIELDS_PARENTS_CHILDREN
+ textwrap.dedent("""
}
}
}
}
}
}
}
""")
)

GET_SOURCES = textwrap.dedent("""
query GetSources(
$environmentId: BigInt!,
Expand Down Expand Up @@ -511,52 +392,6 @@ async def fetch_models(
config=config,
)

async def fetch_model_parents(
self,
model_name: str | None = None,
unique_id: str | None = None,
*,
config: DiscoveryConfig,
) -> list[dict]:
model_filters = self._get_model_filters(model_name, unique_id)
variables = {
"environmentId": config.environment_id,
"modelsFilter": model_filters,
"first": 1,
}
result = await execute_query(
GraphQLQueries.GET_MODEL_PARENTS, variables, config=config
)
raise_gql_error(result)
edges = result["data"]["environment"]["applied"]["models"]["edges"]
if not edges:
return []
return edges[0]["node"]["parents"]

async def fetch_model_children(
self,
model_name: str | None = None,
unique_id: str | None = None,
*,
config: DiscoveryConfig,
) -> list[dict]:
model_filters = self._get_model_filters(model_name, unique_id)
variables = {
"environmentId": config.environment_id,
"modelsFilter": model_filters,
"first": 1,
}
result = await execute_query(
GraphQLQueries.GET_MODEL_CHILDREN,
variables,
config=config,
)
raise_gql_error(result)
edges = result["data"]["environment"]["applied"]["models"]["edges"]
if not edges:
return []
return edges[0]["node"]["children"]

async def fetch_model_health(
self,
model_name: str | None = None,
Expand Down
1 change: 1 addition & 0 deletions src/dbt_mcp/discovery/graphql/get_full_lineage.gql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ query GetFullLineage($environmentId: BigInt!, $types: [ResourceNodeType!]!) {
name
uniqueId
resourceType
description
... on LineageNodeWithParents {
parentIds
}
Expand Down
38 changes: 0 additions & 38 deletions src/dbt_mcp/discovery/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,42 +159,6 @@ async def get_model_details(
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_parents"),
title="Get Model Parents",
read_only_hint=True,
destructive_hint=False,
idempotent_hint=True,
)
async def get_model_parents(
context: DiscoveryToolContext,
name: str | None = NAME_FIELD,
unique_id: str | None = UNIQUE_ID_FIELD,
) -> list[dict]:
config = await context.config_provider.get_config()
return await context.models_fetcher.fetch_model_parents(
model_name=name, unique_id=unique_id, config=config
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_children"),
title="Get Model Children",
read_only_hint=True,
destructive_hint=False,
idempotent_hint=True,
)
async def get_model_children(
context: DiscoveryToolContext,
name: str | None = NAME_FIELD,
unique_id: str | None = UNIQUE_ID_FIELD,
) -> list[dict]:
config = await context.config_provider.get_config()
return await context.models_fetcher.fetch_model_children(
name, unique_id, config=config
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_health"),
title="Get Model Health",
Expand Down Expand Up @@ -480,8 +444,6 @@ async def get_test_details(
get_mart_models,
get_all_models,
get_model_details,
get_model_parents,
get_model_children,
get_model_health,
get_model_performance,
get_lineage,
Expand Down
40 changes: 0 additions & 40 deletions src/dbt_mcp/discovery/tools_multiproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,44 +171,6 @@ async def get_model_details(
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_parents"),
title="Get Model Parents",
read_only_hint=True,
destructive_hint=False,
idempotent_hint=True,
)
async def get_model_parents(
context: MultiProjectDiscoveryToolContext,
project_id: Annotated[int, Field(description=DISCOVERY_PROJECT_ID_DESCRIPTION)],
name: str | None = NAME_FIELD,
unique_id: str | None = UNIQUE_ID_FIELD,
) -> list[dict]:
config = await context.config_provider.get_config(project_id=project_id)
return await context.models_fetcher.fetch_model_parents(
name, unique_id, config=config
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_children"),
title="Get Model Children",
read_only_hint=True,
destructive_hint=False,
idempotent_hint=True,
)
async def get_model_children(
context: MultiProjectDiscoveryToolContext,
project_id: Annotated[int, Field(description=DISCOVERY_PROJECT_ID_DESCRIPTION)],
name: str | None = NAME_FIELD,
unique_id: str | None = UNIQUE_ID_FIELD,
) -> list[dict]:
config = await context.config_provider.get_config(project_id=project_id)
return await context.models_fetcher.fetch_model_children(
model_name=name, unique_id=unique_id, config=config
)


@dbt_mcp_tool(
description=get_prompt("discovery/get_model_health"),
title="Get Model Health",
Expand Down Expand Up @@ -508,8 +470,6 @@ async def get_test_details(
get_mart_models,
get_all_models,
get_model_details,
get_model_parents,
get_model_children,
get_model_health,
get_model_performance,
get_lineage,
Expand Down
12 changes: 9 additions & 3 deletions src/dbt_mcp/prompts/discovery/get_lineage.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,33 @@ A list of all nodes in the connected subgraph, where each node contains:
- `uniqueId`: The resource's unique identifier
- `name`: The resource name
- `resourceType`: The type of resource (Model, Source, etc.)
- `description`: A description of the resource
- `parentIds`: List of unique IDs that this resource directly depends on

**Getting immediate parents or children:** use `depth=1`. This returns the target node plus its direct upstream dependencies and direct downstream dependents.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with the above! get_lineage does not return parent or child but does both . Many references may need to be updated to make "or" --> "and". Or maybe we can update get_lineage to return either parents or children to maintain the "or".


**Example Response:**
```json
[
{
"uniqueId": "source.raw.users",
"name": "users",
"resourceType": "Source",
"description": "Raw user events from the application",
"parentIds": []
},
{
"uniqueId": "model.stg_customers",
"name": "stg_customers",
"resourceType": "Model",
"description": "Staged customer records",
"parentIds": ["source.raw.users"]
},
{
"uniqueId": "model.customers",
"name": "customers",
"resourceType": "Model",
"description": "Customer dimension model",
"parentIds": ["model.stg_customers"]
}
]
Expand All @@ -38,12 +44,12 @@ A list of all nodes in the connected subgraph, where each node contains:
# Get complete lineage (all connected nodes, all types, default depth of 5)
get_lineage(unique_id="model.analytics.customers")

# Get only immediate parents and children (replaces get_model_parents / get_model_children)
get_lineage(unique_id="model.analytics.customers", depth=1)
Comment on lines +47 to +48

# Get lineage filtered to only models and sources
get_lineage(unique_id="model.analytics.customers", types=["Model", "Source"])

# Get only immediate neighbors (depth=1)
get_lineage(unique_id="model.analytics.customers", depth=1)

# Get deeper lineage for comprehensive analysis
get_lineage(unique_id="model.analytics.customers", depth=10)
```
Expand Down
18 changes: 0 additions & 18 deletions src/dbt_mcp/prompts/discovery/get_model_children.md

This file was deleted.

Loading
Loading