-
Notifications
You must be signed in to change notification settings - Fork 122
Expand file tree
/
Copy pathdefinitions.py
More file actions
100 lines (85 loc) · 3.07 KB
/
definitions.py
File metadata and controls
100 lines (85 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from collections.abc import Callable
from dataclasses import dataclass
from enum import Enum
from functools import partial
from typing import Any
from mcp.server.fastmcp.tools.base import Tool
from mcp.types import ToolAnnotations
from dbt_mcp.tools.injection import adapt_with_mapper
from dbt_mcp.tools.tool_names import ToolName
@dataclass
class GenericToolDefinition[NameEnum: Enum]:
fn: Callable[..., Any]
description: str
name_enum: type[NameEnum]
name: str | None = None
title: str | None = None
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
meta: dict[str, Any] | None = None
def get_name(self) -> NameEnum:
return self.name_enum((self.name or self.fn.__name__).lower())
def to_fastmcp_internal_tool(self) -> Tool:
return Tool.from_function(
fn=self.fn,
name=self.name,
title=self.title,
description=self.description,
annotations=self.annotations,
structured_output=self.structured_output,
meta=self.meta,
)
def adapt_context(
self, context_mapper: Callable[..., Any]
) -> "GenericToolDefinition[NameEnum]":
"""
Adapt the tool definition to accept a different context object.
"""
return type(self)(
fn=adapt_with_mapper(self.fn, context_mapper),
description=self.description,
name_enum=self.name_enum,
name=self.name,
title=self.title,
annotations=self.annotations,
structured_output=self.structured_output,
meta=self.meta,
)
@dataclass
class ToolDefinition(GenericToolDefinition[ToolName]):
name_enum: type[ToolName] = ToolName
def generic_dbt_mcp_tool[NameEnum: Enum](
description: 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,
meta: dict[str, Any] | None = None,
) -> Callable[[Callable], GenericToolDefinition[NameEnum]]:
"""Decorator to define a tool definition for dbt MCP"""
def decorator(fn: Callable) -> GenericToolDefinition[NameEnum]:
return GenericToolDefinition(
fn=fn,
description=description,
name_enum=name_enum,
name=name,
title=title,
annotations=ToolAnnotations(
title=title,
readOnlyHint=read_only_hint,
destructiveHint=destructive_hint,
idempotentHint=idempotent_hint,
openWorldHint=open_world_hint,
),
structured_output=structured_output,
meta=meta,
)
return decorator
# Wrapper with ToolName pre-supplied for the common case
dbt_mcp_tool = partial(generic_dbt_mcp_tool, name_enum=ToolName)