Add ToolMetadata to OSS toolkits (#776)
Resolves TOO-388 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Primarily metadata/dependency additions with no changes to core tool execution paths; risk is limited to potential packaging/import issues from the new `arcade-mcp-server` dependency. > > **Overview** > Adds `ToolMetadata` to tool decorators across the Bright Data, ClickHouse, MongoDB, Postgres, LinkedIn, Zendesk, and Math toolkits, specifying *behavior* (read-only/idempotency/destructive/open-world) and, where applicable, *service domain* classification. > > Updates each toolkit package to depend on `arcade-mcp-server` (plus local `uv` source wiring) and bumps toolkit versions accordingly; minor `__all__` ordering tweaks in Math/Zendesk are included. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3bde3a061194e1d1b6a4e8a2ebd608b17984db4f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This commit is contained in:
parent
fe8ddfd500
commit
5228c75dc9
26 changed files with 625 additions and 67 deletions
|
|
@ -5,6 +5,13 @@ from typing import Annotated, Any, cast
|
|||
|
||||
import requests
|
||||
from arcade_core.errors import RetryableToolError
|
||||
from arcade_mcp_server.metadata import (
|
||||
Behavior,
|
||||
Classification,
|
||||
Operation,
|
||||
ServiceDomain,
|
||||
ToolMetadata,
|
||||
)
|
||||
from arcade_tdk import ToolContext, tool
|
||||
|
||||
from arcade_brightdata.bright_data_client import BrightDataClient
|
||||
|
|
@ -51,7 +58,21 @@ class SourceType(str, Enum):
|
|||
YOUTUBE_VIDEOS = "youtube_videos"
|
||||
|
||||
|
||||
@tool(requires_secrets=["BRIGHTDATA_API_KEY", "BRIGHTDATA_ZONE"])
|
||||
@tool(
|
||||
requires_secrets=["BRIGHTDATA_API_KEY", "BRIGHTDATA_ZONE"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.WEB_SCRAPING],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
def scrape_as_markdown(
|
||||
context: ToolContext,
|
||||
url: Annotated[str, "URL to scrape"],
|
||||
|
|
@ -71,7 +92,21 @@ def scrape_as_markdown(
|
|||
return client.make_request(payload)
|
||||
|
||||
|
||||
@tool(requires_secrets=["BRIGHTDATA_API_KEY", "BRIGHTDATA_ZONE"])
|
||||
@tool(
|
||||
requires_secrets=["BRIGHTDATA_API_KEY", "BRIGHTDATA_ZONE"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.WEB_SCRAPING],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
def search_engine( # noqa: C901
|
||||
context: ToolContext,
|
||||
query: Annotated[str, "Search query"],
|
||||
|
|
@ -167,7 +202,21 @@ def search_engine( # noqa: C901
|
|||
return client.make_request(payload)
|
||||
|
||||
|
||||
@tool(requires_secrets=["BRIGHTDATA_API_KEY"])
|
||||
@tool(
|
||||
requires_secrets=["BRIGHTDATA_API_KEY"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.WEB_SCRAPING],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
def web_data_feed(
|
||||
context: ToolContext,
|
||||
source_type: Annotated[SourceType, "Type of data source"],
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_brightdata"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
description = "Search, Crawl and Scrape any site, at scale, without getting blocked"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"requests>=2.32.5",
|
||||
]
|
||||
[[project.authors]]
|
||||
|
|
@ -49,6 +50,7 @@ ignore_missing_imports = "True"
|
|||
arcade-mcp = { path = "../../", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = [ "tests",]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,24 @@
|
|||
from typing import Annotated, Any
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, Operation, ToolMetadata
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.errors import RetryableToolError
|
||||
|
||||
from ..database_engine import MAX_ROWS_RETURNED, DatabaseEngine
|
||||
|
||||
|
||||
@tool(requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_schemas(
|
||||
context: ToolContext,
|
||||
) -> list[str]:
|
||||
|
|
@ -18,7 +30,18 @@ async def discover_schemas(
|
|||
return ["default"]
|
||||
|
||||
|
||||
@tool(requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_databases(
|
||||
context: ToolContext,
|
||||
) -> list[str]:
|
||||
|
|
@ -30,7 +53,18 @@ async def discover_databases(
|
|||
return databases
|
||||
|
||||
|
||||
@tool(requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_tables(
|
||||
context: ToolContext,
|
||||
) -> list[str]:
|
||||
|
|
@ -45,7 +79,18 @@ async def discover_tables(
|
|||
return tables
|
||||
|
||||
|
||||
@tool(requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def get_table_schema(
|
||||
context: ToolContext,
|
||||
schema_name: Annotated[str, "The schema to get the table schema of"],
|
||||
|
|
@ -62,7 +107,18 @@ async def get_table_schema(
|
|||
return await _get_table_schema(client, "default", table_name)
|
||||
|
||||
|
||||
@tool(requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["CLICKHOUSE_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def execute_select_query(
|
||||
context: ToolContext,
|
||||
select_clause: Annotated[
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_clickhouse"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
description = "Tools to query and explore a ClickHouse database"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"clickhouse-connect>=0.7.0",
|
||||
"pydantic>=2.11.7",
|
||||
"sqlalchemy>=2.0.41",
|
||||
|
|
@ -41,6 +42,7 @@ dev = [
|
|||
arcade-mcp = { path = "../../", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import (
|
||||
Behavior,
|
||||
Classification,
|
||||
Operation,
|
||||
ServiceDomain,
|
||||
ToolMetadata,
|
||||
)
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.auth import LinkedIn
|
||||
from arcade_tdk.errors import ToolExecutionError
|
||||
|
|
@ -10,7 +17,19 @@ from arcade_linkedin.tools.utils import _handle_linkedin_api_error, _send_linked
|
|||
@tool(
|
||||
requires_auth=LinkedIn(
|
||||
scopes=["w_member_social"],
|
||||
)
|
||||
),
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.SOCIAL_MEDIA],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.CREATE],
|
||||
read_only=False,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def create_text_post(
|
||||
context: ToolContext,
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_linkedin"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
description = "Arcade.dev LLM tools for LinkedIn"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"httpx>=0.27.2,<1.0.0",
|
||||
]
|
||||
[[project.authors]]
|
||||
|
|
@ -34,6 +35,7 @@ dev = [
|
|||
arcade-mcp = {path = "../../", editable = true}
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
[tool.mypy]
|
||||
files = [ "arcade_linkedin/**/*.py",]
|
||||
|
|
|
|||
|
|
@ -39,27 +39,27 @@ from arcade_math.tools.trigonometry import (
|
|||
)
|
||||
|
||||
__all__ = [
|
||||
"add",
|
||||
"subtract",
|
||||
"multiply",
|
||||
"divide",
|
||||
"sum_list",
|
||||
"sum_range",
|
||||
"mod",
|
||||
"log",
|
||||
"power",
|
||||
"abs_val",
|
||||
"add",
|
||||
"avg",
|
||||
"ceil",
|
||||
"deg_to_rad",
|
||||
"divide",
|
||||
"factorial",
|
||||
"sqrt",
|
||||
"floor",
|
||||
"gcd",
|
||||
"generate_random_float",
|
||||
"generate_random_int",
|
||||
"gcd",
|
||||
"lcm",
|
||||
"ceil",
|
||||
"floor",
|
||||
"round_num",
|
||||
"avg",
|
||||
"log",
|
||||
"median",
|
||||
"deg_to_rad",
|
||||
"mod",
|
||||
"multiply",
|
||||
"power",
|
||||
"rad_to_deg",
|
||||
"round_num",
|
||||
"sqrt",
|
||||
"subtract",
|
||||
"sum_list",
|
||||
"sum_range",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,12 +2,22 @@ import decimal
|
|||
from decimal import Decimal
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def add(
|
||||
a: Annotated[str, "The first number as a string"],
|
||||
b: Annotated[str, "The second number as a string"],
|
||||
|
|
@ -21,7 +31,16 @@ def add(
|
|||
return str(a_decimal + b_decimal)
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def subtract(
|
||||
a: Annotated[str, "The first number as a string"],
|
||||
b: Annotated[str, "The second number as a string"],
|
||||
|
|
@ -35,7 +54,16 @@ def subtract(
|
|||
return str(a_decimal - b_decimal)
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def multiply(
|
||||
a: Annotated[str, "The first number as a string"],
|
||||
b: Annotated[str, "The second number as a string"],
|
||||
|
|
@ -49,7 +77,16 @@ def multiply(
|
|||
return str(a_decimal * b_decimal)
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def divide(
|
||||
a: Annotated[str, "The first number as a string"],
|
||||
b: Annotated[str, "The second number as a string"],
|
||||
|
|
@ -63,7 +100,16 @@ def divide(
|
|||
return str(a_decimal / b_decimal)
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def sum_list(
|
||||
numbers: Annotated[list[str], "The list of numbers as strings"],
|
||||
) -> Annotated[str, "The sum of the numbers in the list as a string"]:
|
||||
|
|
@ -74,7 +120,16 @@ def sum_list(
|
|||
return str(sum([Decimal(n) for n in numbers]))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def sum_range(
|
||||
start: Annotated[str, "The start of the range to sum as a string"],
|
||||
end: Annotated[str, "The end of the range to sum as a string"],
|
||||
|
|
@ -85,7 +140,16 @@ def sum_range(
|
|||
return str(sum(list(range(int(start), int(end) + 1))))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def mod(
|
||||
a: Annotated[str, "The dividend as a string"],
|
||||
b: Annotated[str, "The divisor as a string"],
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@ import math
|
|||
from decimal import Decimal
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def log(
|
||||
a: Annotated[str, "The number to take the logarithm of as a string"],
|
||||
base: Annotated[str, "The logarithmic base as a string"],
|
||||
|
|
@ -20,7 +30,16 @@ def log(
|
|||
return str(math.log(Decimal(a), Decimal(base)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def power(
|
||||
a: Annotated[str, "The base number as a string"],
|
||||
b: Annotated[str, "The exponent as a string"],
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@ import math
|
|||
from decimal import Decimal
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def abs_val(
|
||||
a: Annotated[str, "The number as a string"],
|
||||
) -> Annotated[str, "The absolute value of the number as a string"]:
|
||||
|
|
@ -19,7 +29,16 @@ def abs_val(
|
|||
return str(abs(Decimal(a)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def factorial(
|
||||
a: Annotated[str, "The non-negative integer to compute the factorial for as a string"],
|
||||
) -> Annotated[str, "The factorial of the number as a string"]:
|
||||
|
|
@ -30,7 +49,16 @@ def factorial(
|
|||
return str(math.factorial(int(a)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def sqrt(
|
||||
a: Annotated[str, "The number to square root as a string"],
|
||||
) -> Annotated[str, "The square root of the number as a string"]:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
import random
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def generate_random_int(
|
||||
min_value: Annotated[str, "The minimum value of the random integer as a string"],
|
||||
max_value: Annotated[str, "The maximum value of the random integer as a string"],
|
||||
|
|
@ -21,7 +31,16 @@ def generate_random_int(
|
|||
return str(random.randint(int(min_value), int(max_value))) # noqa: S311
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def generate_random_float(
|
||||
min_value: Annotated[str, "The minimum value of the random float as a string"],
|
||||
max_value: Annotated[str, "The maximum value of the random float as a string"],
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
import math
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def gcd(
|
||||
a: Annotated[str, "First integer as a string"],
|
||||
b: Annotated[str, "Second integer as a string"],
|
||||
|
|
@ -15,7 +25,16 @@ def gcd(
|
|||
return str(math.gcd(int(a), int(b)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def lcm(
|
||||
a: Annotated[str, "First integer as a string"],
|
||||
b: Annotated[str, "Second integer as a string"],
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@ import math
|
|||
from decimal import Decimal
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def ceil(
|
||||
a: Annotated[str, "The number to round up as a string"],
|
||||
) -> Annotated[str, "The smallest integer greater than or equal to the number as a string"]:
|
||||
|
|
@ -19,7 +29,16 @@ def ceil(
|
|||
return str(math.ceil(Decimal(a)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def floor(
|
||||
a: Annotated[str, "The number to round down as a string"],
|
||||
) -> Annotated[str, "The largest integer less than or equal to the number as a string"]:
|
||||
|
|
@ -30,7 +49,16 @@ def floor(
|
|||
return str(math.floor(Decimal(a)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def round_num(
|
||||
value: Annotated[str, "The number to round as a string"],
|
||||
ndigits: Annotated[str, "The number of digits after the decimal point as a string"],
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@ from decimal import Decimal
|
|||
from statistics import median as stats_median
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def avg(
|
||||
numbers: Annotated[list[str], "The list of numbers as strings"],
|
||||
) -> Annotated[str, "The average (mean) of the numbers in the list as a string"]:
|
||||
|
|
@ -21,7 +31,16 @@ def avg(
|
|||
return str(sum(d_numbers) / len(d_numbers)) if d_numbers else "0.0"
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def median(
|
||||
numbers: Annotated[list[str], "A list of numbers as strings"],
|
||||
) -> Annotated[str, "The median value of the numbers in the list as a string"]:
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@ import math
|
|||
from decimal import Decimal
|
||||
from typing import Annotated
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, ToolMetadata
|
||||
from arcade_tdk import tool
|
||||
|
||||
decimal.getcontext().prec = 100
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def deg_to_rad(
|
||||
degrees: Annotated[str, "Angle in degrees as a string"],
|
||||
) -> Annotated[str, "Angle in radians as a string"]:
|
||||
|
|
@ -19,7 +29,16 @@ def deg_to_rad(
|
|||
return str(math.radians(Decimal(degrees)))
|
||||
|
||||
|
||||
@tool
|
||||
@tool(
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=False,
|
||||
),
|
||||
),
|
||||
)
|
||||
def rad_to_deg(
|
||||
radians: Annotated[str, "Angle in radians as a string"],
|
||||
) -> Annotated[str, "Angle in degrees as a string"]:
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_math"
|
||||
version = "1.0.5"
|
||||
version = "1.1.0"
|
||||
description = "Arcade.dev LLM tools for doing math"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
]
|
||||
[[project.authors]]
|
||||
name = "Arcade"
|
||||
|
|
@ -33,6 +34,7 @@ dev = [
|
|||
arcade-mcp = {path = "../../", editable = true}
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
[tool.mypy]
|
||||
files = [ "arcade_math/**/*.py",]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
from typing import Annotated, Any
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, Operation, ToolMetadata
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.errors import RetryableToolError
|
||||
|
||||
|
|
@ -20,7 +21,18 @@ from .utils import (
|
|||
# BANNED = "banned"
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_databases(
|
||||
context: ToolContext,
|
||||
) -> list[str]:
|
||||
|
|
@ -32,7 +44,18 @@ async def discover_databases(
|
|||
return databases
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_collections(
|
||||
context: ToolContext,
|
||||
database_name: Annotated[str, "The database name to discover collections in"],
|
||||
|
|
@ -48,7 +71,18 @@ async def discover_collections(
|
|||
return list(collections)
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def get_collection_schema(
|
||||
context: ToolContext,
|
||||
database_name: Annotated[str, "The database name to get the collection schema of"],
|
||||
|
|
@ -90,7 +124,18 @@ async def get_collection_schema(
|
|||
}
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def find_documents(
|
||||
context: ToolContext,
|
||||
database_name: Annotated[str, "The database name to query"],
|
||||
|
|
@ -193,7 +238,18 @@ async def find_documents(
|
|||
) from e
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def count_documents(
|
||||
context: ToolContext,
|
||||
database_name: Annotated[str, "The database name to query"],
|
||||
|
|
@ -230,7 +286,18 @@ async def count_documents(
|
|||
) from e
|
||||
|
||||
|
||||
@tool(requires_secrets=["MONGODB_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["MONGODB_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def aggregate_documents(
|
||||
context: ToolContext,
|
||||
database_name: Annotated[str, "The database name to query"],
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_mongodb"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
description = "Tools to query and explore a MongoDB database"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"pymongo>=4.10.1",
|
||||
"pydantic>=2.11.7",
|
||||
"motor>=3.6.0",
|
||||
|
|
@ -37,6 +38,7 @@ dev = [
|
|||
arcade-mcp = { path = "../../", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from typing import Annotated, Any
|
||||
|
||||
from arcade_mcp_server.metadata import Behavior, Operation, ToolMetadata
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.errors import RetryableToolError
|
||||
from sqlalchemy import inspect, text
|
||||
|
|
@ -8,7 +9,18 @@ from sqlalchemy.ext.asyncio import AsyncEngine
|
|||
from ..database_engine import MAX_ROWS_RETURNED, DatabaseEngine
|
||||
|
||||
|
||||
@tool(requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_schemas(
|
||||
context: ToolContext,
|
||||
) -> list[str]:
|
||||
|
|
@ -20,7 +32,18 @@ async def discover_schemas(
|
|||
return schemas
|
||||
|
||||
|
||||
@tool(requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def discover_tables(
|
||||
context: ToolContext,
|
||||
schema_name: Annotated[
|
||||
|
|
@ -38,7 +61,18 @@ async def discover_tables(
|
|||
return tables
|
||||
|
||||
|
||||
@tool(requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def get_table_schema(
|
||||
context: ToolContext,
|
||||
schema_name: Annotated[str, "The database schema to get the table schema of"],
|
||||
|
|
@ -55,7 +89,18 @@ async def get_table_schema(
|
|||
return await _get_table_schema(engine, schema_name, table_name)
|
||||
|
||||
|
||||
@tool(requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"])
|
||||
@tool(
|
||||
requires_secrets=["POSTGRES_DATABASE_CONNECTION_STRING"],
|
||||
metadata=ToolMetadata(
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def execute_select_query(
|
||||
context: ToolContext,
|
||||
select_clause: Annotated[
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_postgres"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
description = "Tools to query and explore a postgres database"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"psycopg2-binary>=2.9.10",
|
||||
"pydantic>=2.11.7",
|
||||
"sqlalchemy>=2.0.41",
|
||||
|
|
@ -40,6 +41,7 @@ dev = [
|
|||
arcade-mcp = { path = "../../", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ from arcade_zendesk.tools import (
|
|||
)
|
||||
|
||||
__all__ = [
|
||||
"list_tickets",
|
||||
"add_ticket_comment",
|
||||
"get_ticket_comments",
|
||||
"list_tickets",
|
||||
"mark_ticket_solved",
|
||||
"search_articles",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ from arcade_zendesk.tools.tickets import (
|
|||
)
|
||||
|
||||
__all__ = [
|
||||
"list_tickets",
|
||||
"add_ticket_comment",
|
||||
"get_ticket_comments",
|
||||
"list_tickets",
|
||||
"mark_ticket_solved",
|
||||
"search_articles",
|
||||
"who_am_i",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@ import logging
|
|||
from typing import Annotated, Any
|
||||
|
||||
import httpx
|
||||
from arcade_mcp_server.metadata import (
|
||||
Behavior,
|
||||
Classification,
|
||||
Operation,
|
||||
ServiceDomain,
|
||||
ToolMetadata,
|
||||
)
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.auth import OAuth2
|
||||
from arcade_tdk.errors import RetryableToolError
|
||||
|
|
@ -20,6 +27,18 @@ logger = logging.getLogger(__name__)
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["read"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def search_articles(
|
||||
context: ToolContext,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
from typing import Annotated, Any
|
||||
|
||||
from arcade_mcp_server.metadata import (
|
||||
Behavior,
|
||||
Classification,
|
||||
Operation,
|
||||
ServiceDomain,
|
||||
ToolMetadata,
|
||||
)
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.auth import OAuth2
|
||||
|
||||
|
|
@ -9,6 +16,18 @@ from arcade_zendesk.who_am_i_util import build_who_am_i_response
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["read"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def who_am_i(
|
||||
context: ToolContext,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
from typing import Annotated, Any
|
||||
|
||||
import httpx
|
||||
from arcade_mcp_server.metadata import (
|
||||
Behavior,
|
||||
Classification,
|
||||
Operation,
|
||||
ServiceDomain,
|
||||
ToolMetadata,
|
||||
)
|
||||
from arcade_tdk import ToolContext, tool
|
||||
from arcade_tdk.auth import OAuth2
|
||||
from arcade_tdk.errors import RetryableToolError
|
||||
|
|
@ -23,6 +30,18 @@ def _handle_ticket_not_found(response: httpx.Response, ticket_id: int) -> None:
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["read"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def list_tickets(
|
||||
context: ToolContext,
|
||||
|
|
@ -133,6 +152,18 @@ async def list_tickets(
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["read"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.READ],
|
||||
read_only=True,
|
||||
destructive=False,
|
||||
idempotent=True,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def get_ticket_comments(
|
||||
context: ToolContext,
|
||||
|
|
@ -184,6 +215,18 @@ async def get_ticket_comments(
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["tickets:write"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.CREATE],
|
||||
read_only=False,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def add_ticket_comment(
|
||||
context: ToolContext,
|
||||
|
|
@ -243,6 +286,18 @@ async def add_ticket_comment(
|
|||
@tool(
|
||||
requires_auth=OAuth2(id="zendesk", scopes=["tickets:write"]),
|
||||
requires_secrets=["ZENDESK_SUBDOMAIN"],
|
||||
metadata=ToolMetadata(
|
||||
classification=Classification(
|
||||
service_domains=[ServiceDomain.CUSTOMER_SUPPORT],
|
||||
),
|
||||
behavior=Behavior(
|
||||
operations=[Operation.UPDATE, Operation.CREATE],
|
||||
read_only=False,
|
||||
destructive=False,
|
||||
idempotent=False,
|
||||
open_world=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
async def mark_ticket_solved(
|
||||
context: ToolContext,
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_zendesk"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"arcade-tdk>=3.0.0,<4.0.0",
|
||||
"arcade-mcp-server>=1.17.0,<2.0.0",
|
||||
"httpx>=0.25.0,<1.0.0",
|
||||
"beautifulsoup4>=4.0.0,<5"
|
||||
]
|
||||
|
|
@ -32,6 +33,7 @@ dev = [
|
|||
arcade-mcp = { path = "../../", editable = true }
|
||||
arcade-serve = { path = "../../libs/arcade-serve/", editable = true }
|
||||
arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true }
|
||||
arcade-mcp-server = { path = "../../libs/arcade-mcp-server/", editable = true }
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
|||
Loading…
Reference in a new issue