diff --git a/.changes/unreleased/Under the Hood-20260513-085632.yaml b/.changes/unreleased/Under the Hood-20260513-085632.yaml new file mode 100644 index 00000000..332e8d37 --- /dev/null +++ b/.changes/unreleased/Under the Hood-20260513-085632.yaml @@ -0,0 +1,3 @@ +kind: Under the Hood +body: Make ToolDefinition.structured_output default to True and require title in generic_dbt_mcp_tool. Decorator now keyword-only. +time: 2026-05-13T08:56:32.224755-05:00 diff --git a/src/dbt_mcp/dbt_cli/tools.py b/src/dbt_mcp/dbt_cli/tools.py index 59527071..70cf6a71 100644 --- a/src/dbt_mcp/dbt_cli/tools.py +++ b/src/dbt_mcp/dbt_cli/tools.py @@ -429,6 +429,7 @@ def get_node_details_dev( return [ ToolDefinition( fn=build, + title="dbt build", description=get_prompt("dbt_cli/build"), annotations=create_tool_annotations( title="dbt build", @@ -439,6 +440,7 @@ def get_node_details_dev( ), ToolDefinition( fn=compile, + title="dbt compile", description=get_prompt("dbt_cli/compile"), annotations=create_tool_annotations( title="dbt compile", @@ -449,6 +451,7 @@ def get_node_details_dev( ), ToolDefinition( fn=docs, + title="dbt docs", description=get_prompt("dbt_cli/docs"), annotations=create_tool_annotations( title="dbt docs", @@ -460,6 +463,7 @@ def get_node_details_dev( ToolDefinition( name="list", fn=ls, + title="dbt list", description=get_prompt("dbt_cli/list"), annotations=create_tool_annotations( title="dbt list", @@ -470,6 +474,7 @@ def get_node_details_dev( ), ToolDefinition( fn=parse, + title="dbt parse", description=get_prompt("dbt_cli/parse"), annotations=create_tool_annotations( title="dbt parse", @@ -480,6 +485,7 @@ def get_node_details_dev( ), ToolDefinition( fn=run, + title="dbt run", description=get_prompt("dbt_cli/run"), annotations=create_tool_annotations( title="dbt run", @@ -490,6 +496,7 @@ def get_node_details_dev( ), ToolDefinition( fn=test, + title="dbt test", description=get_prompt("dbt_cli/test"), annotations=create_tool_annotations( title="dbt test", @@ -500,6 +507,7 @@ def get_node_details_dev( ), ToolDefinition( fn=show, + title="dbt show", description=get_prompt("dbt_cli/show"), annotations=create_tool_annotations( title="dbt show", @@ -510,6 +518,7 @@ def get_node_details_dev( ), ToolDefinition( fn=clone, + title="dbt clone", description=get_prompt("dbt_cli/clone"), annotations=create_tool_annotations( title="dbt clone", @@ -521,6 +530,7 @@ def get_node_details_dev( ToolDefinition( name="get_lineage_dev", fn=get_lineage_dev, + title="Get Model Lineage (Dev)", description=get_prompt("dbt_cli/get_lineage_dev"), annotations=create_tool_annotations( title="Get Model Lineage (Dev)", @@ -532,6 +542,7 @@ def get_node_details_dev( ToolDefinition( name="get_node_details_dev", fn=get_node_details_dev, + title="Get Node Details (Dev)", description=get_prompt("dbt_cli/get_node_details_dev"), annotations=create_tool_annotations( title="Get Node Details (Dev)", diff --git a/src/dbt_mcp/dbt_codegen/tools.py b/src/dbt_mcp/dbt_codegen/tools.py index 08685d73..3ea74cc4 100644 --- a/src/dbt_mcp/dbt_codegen/tools.py +++ b/src/dbt_mcp/dbt_codegen/tools.py @@ -163,9 +163,9 @@ def generate_staging_model( return [ ToolDefinition( fn=generate_source, + title="Generate Source", description=get_prompt("dbt_codegen/generate_source"), annotations=create_tool_annotations( - title="dbt-codegen generate_source", read_only_hint=True, destructive_hint=False, idempotent_hint=True, @@ -173,9 +173,9 @@ def generate_staging_model( ), ToolDefinition( fn=generate_model_yaml, + title="Generate Model YAML", description=get_prompt("dbt_codegen/generate_model_yaml"), annotations=create_tool_annotations( - title="dbt-codegen generate_model_yaml", read_only_hint=True, destructive_hint=False, idempotent_hint=True, @@ -183,9 +183,9 @@ def generate_staging_model( ), ToolDefinition( fn=generate_staging_model, + title="Generate Staging Model", description=get_prompt("dbt_codegen/generate_staging_model"), annotations=create_tool_annotations( - title="dbt-codegen generate_staging_model", read_only_hint=True, destructive_hint=False, idempotent_hint=True, diff --git a/src/dbt_mcp/lsp/tools.py b/src/dbt_mcp/lsp/tools.py index d88faa77..d841d187 100644 --- a/src/dbt_mcp/lsp/tools.py +++ b/src/dbt_mcp/lsp/tools.py @@ -70,9 +70,9 @@ async def wrapper(*args, **kwargs) -> Any: return [ ToolDefinition( fn=call_with_lsp_client(get_column_lineage), + title="Get Column Lineage", description=get_prompt("lsp/get_column_lineage"), annotations=create_tool_annotations( - title="get_column_lineage", read_only_hint=False, destructive_hint=False, idempotent_hint=True, diff --git a/src/dbt_mcp/tools/definitions.py b/src/dbt_mcp/tools/definitions.py index 4dd9392d..c5fca039 100644 --- a/src/dbt_mcp/tools/definitions.py +++ b/src/dbt_mcp/tools/definitions.py @@ -14,14 +14,12 @@ @dataclass class GenericToolDefinition[NameEnum: Enum]: fn: Callable[..., Any] + title: str # Human-friendly title for the tool description: str name_enum: type[NameEnum] - name: str | None = None - title: str | None = None + name: str | None = None # Machine-friendly name for the tool annotations: ToolAnnotations | None = None - # We haven't strictly defined our tool contracts yet. - # So we're setting this to False by default for now. - structured_output: bool | None = False + structured_output: bool = True meta: dict[str, Any] | None = None def get_name(self) -> NameEnum: @@ -62,15 +60,16 @@ class ToolDefinition(GenericToolDefinition[ToolName]): def generic_dbt_mcp_tool[NameEnum: Enum]( + *, description: str, + title: str, name_enum: type[NameEnum], name: str | None = None, - title: str | None = None, read_only_hint: bool = False, destructive_hint: bool = True, idempotent_hint: bool = False, open_world_hint: bool = True, - structured_output: bool | None = False, + structured_output: bool = True, meta: dict[str, Any] | None = None, ) -> Callable[[Callable], GenericToolDefinition[NameEnum]]: """Decorator to define a tool definition for dbt MCP"""