You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
### Step 2b: Create dynamic tools with `@fenic_tool`
142
142
143
-
Dynamic tools let you expose arbitrary Python logic as an MCP tool. They are defined with the `@fenic_tool` decorator and must return a Fenic `DataFrame`. Annotate parameters with `typing_extensions.Annotated` to provide per-argument descriptions in the tool schema. The server automatically adds `limit` and `table_format` keyword-only parameters for limiting the size of result sets and output formatting.
143
+
Dynamic tools let you expose arbitrary Python logic as an MCP tool. They are defined with the `@fenic_tool` decorator and must return a Fenic `DataFrame`. Annotate parameters with `typing_extensions.Annotated` to provide per-argument descriptions in the tool schema. The server automatically adds `limit` and `table_format` keyword-only parameters for limiting the size of result sets and output formatting -- if the tool handles its own limiting, set `client_limit_parameter` to `False` to disable this behavior. The wrapped function can be async (recommended) or synchronous.
"""Decorator to bind a DataFrame to a user-authored tool function.
111
126
127
+
Can be added to a synchronous or asynchronous (recommended) tool function.
128
+
Function based tools (dynamic tools) cannot be persisted to the catalog.
129
+
See the (Fenic MCP documentation)[https://fenic.ai/docs/topics/fenic-mcp] for more details.
130
+
112
131
Args:
113
132
tool_name: The name of the tool.
114
133
tool_description: The description of the tool.
115
-
max_result_limit: The maximum number of results to return.
134
+
max_result_limit: The maximum number of results to return. If omitted, no limit will be enforced.
135
+
client_limit_parameter: Whether to add a client-side limit parameter to the tool.
116
136
default_table_format: The default table format to return.
117
137
read_only: A hint to provide to the model that the tool does not modify its environment.
118
138
idempotent: A hint to provide to the model that calling the tool multiple times with the same input will always return the same result (redundant if read_only is True).
@@ -136,10 +156,10 @@ def find_rust(
136
156
137
157
Example: Creating an open-world tool that reaches out to an external API. The open_world flag indicates to the model that the tool may interact with an "open world" of external entities
query: Annotated[str, "Knowledge base search query"],
141
161
) -> DataFrame:
142
-
results = requests.get(...)
162
+
results = await requests.get(...)
143
163
return fc.create_dataframe(results)
144
164
145
165
Notes:
@@ -149,20 +169,26 @@ def search_knowledge_base(
149
169
- The returned object is a DynamicTool ready for registration.
150
170
- A `limit` parameter is automatically added to the function signature, which can be used to limit the number of rows returned up to the tool's `max_result_limit`.
151
171
- A `table_format` parameter is automatically added to the function signature, which can be used to specify the format of the returned data (markdown, structured)
172
+
- The `add_limit_parameter` flag can be used to control whether the client is allowed to specify a limit parameter.
"- For text search, prefer regular expressions using REGEXP_MATCHES().\n",
465
491
"- Paging: use ORDER BY to define row order, then LIMIT and OFFSET for pages.\n",
466
492
f"- Results are limited to {result_limit} rows, use LIMIT/OFFSET to paginate when receiving a result set of {result_limit} or more rows.\n",
467
-
"Examples:\n", # nosec B608 - example text only
468
-
f"- SELECT * FROM {{{example_name}}} WHERE REGEXP_MATCHES(message, '(?i)error|fail') LIMIT {result_limit}",
469
-
# nosec B608 - example text only
470
-
f"- SELECT dept, COUNT(*) AS n FROM {{{example_name}}} WHERE status = 'active' GROUP BY dept HAVING n > 10 ORDER BY n DESC LIMIT {result_limit}",
471
-
# nosec B608 - example text only
472
-
f"- Paging: page 2 of size {result_limit}\n SELECT * FROM {{{example_name}}} ORDER BY created_at DESC LIMIT {result_limit} OFFSET {result_limit}",
473
-
# nosec B608 - example text only
493
+
"Examples:\n",
494
+
f"- SELECT * FROM {{{example_name}}} WHERE REGEXP_MATCHES(message, '(?i)error|fail') LIMIT {result_limit}", # nosec B608 - example text only
495
+
f"- SELECT dept, COUNT(*) AS n FROM {{{example_name}}} WHERE status = 'active' GROUP BY dept HAVING n > 10 ORDER BY n DESC LIMIT {result_limit}", # nosec B608 - example text only
496
+
f"- Paging: page 2 of size {result_limit}\n SELECT * FROM {{{example_name}}} ORDER BY created_at DESC LIMIT {result_limit} OFFSET {result_limit}", # nosec B608 - example text only
0 commit comments