chore: lint issues

This commit is contained in:
Timothy
2026-03-03 20:38:30 -08:00
parent e421bcc326
commit b4cf10214b
98 changed files with 2001 additions and 1129 deletions
+8 -2
View File
@@ -79,7 +79,9 @@ def main():
cursor.execute(payroll_query)
print(f"\n{'Department':<25} {'Employees':<12} {'Total Salary Cost':<20} {'Avg Salary':<15}")
print(
f"\n{'Department':<25} {'Employees':<12} {'Total Salary Cost':<20} {'Avg Salary':<15}"
)
print("-" * 80)
total_company_payroll = 0
@@ -176,7 +178,11 @@ def main():
print("=" * 80)
print(f"✓ Total Employees: {total_employees}")
print(f"✓ Total Company Payroll: ${total_company_payroll:,.2f}")
print(f"✓ Average Employee Salary: ${total_company_payroll / total_employees:,.2f}" if total_employees > 0 else "N/A")
print(
f"✓ Average Employee Salary: ${total_company_payroll / total_employees:,.2f}"
if total_employees > 0
else "N/A"
)
print("=" * 80)
print("\nPayroll analysis completed successfully!")
+3 -1
View File
@@ -89,7 +89,9 @@ def main():
# Highlight the department with the highest average
if avg_salary == highest_avg:
# Use special formatting for the highest
print(f"{'>>> ' + str(idx):<6} {department:<25} {avg_salary_str:<20} {emp_count:<12} ⭐ HIGHEST")
print(
f"{'>>> ' + str(idx):<6} {department:<25} {avg_salary_str:<20} {emp_count:<12} ⭐ HIGHEST"
)
else:
print(f"{idx:<6} {department:<25} {avg_salary_str:<20} {emp_count:<12}")
@@ -2,6 +2,7 @@
Brevo tool credentials.
Contains credentials for Brevo email and SMS integration.
"""
from .base import CredentialSpec
BREVO_CREDENTIALS = {
@@ -76,7 +76,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
if not base_id or not table_name:
return {"error": "base_id and table_name are required"}
@@ -127,7 +130,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
if not base_id or not table_name or not record_id:
return {"error": "base_id, table_name, and record_id are required"}
@@ -158,7 +164,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
if not base_id or not table_name or not records:
return {"error": "base_id, table_name, and records are required"}
@@ -186,10 +195,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
return {
"result": "created",
"count": len(created),
"records": [
{"id": r["id"], "fields": r.get("fields", {})}
for r in created
],
"records": [{"id": r["id"], "fields": r.get("fields", {})} for r in created],
}
@mcp.tool()
@@ -211,7 +217,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
if not base_id or not table_name or not records:
return {"error": "base_id, table_name, and records are required"}
@@ -239,10 +248,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
return {
"result": "updated",
"count": len(updated),
"records": [
{"id": r["id"], "fields": r.get("fields", {})}
for r in updated
],
"records": [{"id": r["id"], "fields": r.get("fields", {})} for r in updated],
}
@mcp.tool()
@@ -250,7 +256,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""List all Airtable bases accessible with the current token."""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
url = f"{BASE_URL}/meta/bases"
data = _get(url, hdrs)
@@ -281,7 +290,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
hdrs = _get_headers()
if hdrs is None:
return {"error": "AIRTABLE_PAT is required", "help": "Set AIRTABLE_PAT env var with your Airtable personal access token"}
return {
"error": "AIRTABLE_PAT is required",
"help": "Set AIRTABLE_PAT env var with your Airtable personal access token",
}
if not base_id:
return {"error": "base_id is required"}
@@ -35,7 +35,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{APIFY_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{APIFY_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your APIFY_API_TOKEN."}
if resp.status_code == 404:
@@ -51,7 +53,9 @@ def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any
def _post(endpoint: str, token: str, body: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.post(f"{APIFY_API}/{endpoint}", headers=_headers(token), json=body or {}, timeout=60.0)
resp = httpx.post(
f"{APIFY_API}/{endpoint}", headers=_headers(token), json=body or {}, timeout=60.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your APIFY_API_TOKEN."}
if resp.status_code not in (200, 201):
@@ -252,13 +256,15 @@ def register_tools(
actors = []
for a in data.get("data", {}).get("items", []):
stats = a.get("stats", {})
actors.append({
"id": a.get("id", ""),
"name": a.get("name", ""),
"title": a.get("title", ""),
"description": (a.get("description", "") or "")[:200],
"total_runs": stats.get("totalRuns", 0),
})
actors.append(
{
"id": a.get("id", ""),
"name": a.get("name", ""),
"title": a.get("title", ""),
"description": (a.get("description", "") or "")[:200],
"total_runs": stats.get("totalRuns", 0),
}
)
return {"actors": actors, "count": len(actors)}
@mcp.tool()
@@ -290,14 +296,16 @@ def register_tools(
runs = []
for r in data.get("data", {}).get("items", []):
runs.append({
"run_id": r.get("id", ""),
"actor_id": r.get("actId", ""),
"status": r.get("status", ""),
"started_at": r.get("startedAt", ""),
"finished_at": r.get("finishedAt", ""),
"dataset_id": r.get("defaultDatasetId", ""),
})
runs.append(
{
"run_id": r.get("id", ""),
"actor_id": r.get("actId", ""),
"status": r.get("status", ""),
"started_at": r.get("startedAt", ""),
"finished_at": r.get("finishedAt", ""),
"dataset_id": r.get("defaultDatasetId", ""),
}
)
return {"runs": runs, "count": len(runs)}
@mcp.tool()
@@ -34,7 +34,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{ASANA_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{ASANA_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your ASANA_ACCESS_TOKEN."}
if resp.status_code == 403:
@@ -52,7 +54,12 @@ def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any
def _post(endpoint: str, token: str, body: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.post(f"{ASANA_API}/{endpoint}", headers=_headers(token), json={"data": body or {}}, timeout=30.0)
resp = httpx.post(
f"{ASANA_API}/{endpoint}",
headers=_headers(token),
json={"data": body or {}},
timeout=30.0,
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your ASANA_ACCESS_TOKEN."}
if resp.status_code not in (200, 201):
@@ -130,12 +137,14 @@ def register_tools(
projects = []
for p in data.get("data", []):
projects.append({
"gid": p.get("gid", ""),
"name": p.get("name", ""),
"color": p.get("color", ""),
"archived": p.get("archived", False),
})
projects.append(
{
"gid": p.get("gid", ""),
"name": p.get("name", ""),
"color": p.get("color", ""),
"archived": p.get("archived", False),
}
)
return {"projects": projects}
@mcp.tool()
@@ -180,13 +189,15 @@ def register_tools(
tasks = []
for t in data.get("data", []):
assignee_obj = t.get("assignee") or {}
tasks.append({
"gid": t.get("gid", ""),
"name": t.get("name", ""),
"completed": t.get("completed", False),
"due_on": t.get("due_on", ""),
"assignee_name": assignee_obj.get("name", ""),
})
tasks.append(
{
"gid": t.get("gid", ""),
"name": t.get("name", ""),
"completed": t.get("completed", False),
"due_on": t.get("due_on", ""),
"assignee_name": assignee_obj.get("name", ""),
}
)
return {"tasks": tasks, "count": len(tasks)}
@mcp.tool()
@@ -206,7 +217,9 @@ def register_tools(
if not task_gid:
return {"error": "task_gid is required"}
params = {"opt_fields": "name,notes,completed,due_on,assignee.name,projects.name,tags.name,created_at,modified_at"}
params = {
"opt_fields": "name,notes,completed,due_on,assignee.name,projects.name,tags.name,created_at,modified_at"
}
data = _get(f"tasks/{task_gid}", token, params)
if "error" in data:
return data
@@ -306,10 +319,12 @@ def register_tools(
tasks = []
for t in data.get("data", []):
tasks.append({
"gid": t.get("gid", ""),
"name": t.get("name", ""),
"completed": t.get("completed", False),
"due_on": t.get("due_on", ""),
})
tasks.append(
{
"gid": t.get("gid", ""),
"name": t.get("name", ""),
"completed": t.get("completed", False),
"due_on": t.get("due_on", ""),
}
)
return {"query": query, "tasks": tasks}
@@ -121,9 +121,7 @@ class TestAttioClient:
mock_request.return_value = mock_response
params = {"matching_attribute": "email_addresses"}
result = self.client._request(
"PUT", "/objects/people/records", json_body={}, params=params
)
result = self.client._request("PUT", "/objects/people/records", json_body={}, params=params)
call_kwargs = mock_request.call_args.kwargs
assert call_kwargs["params"] == params
@@ -210,7 +208,10 @@ class TestAttioClient:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": {"record_id": "rec-123"}, "values": {"name": [{"first_name": "Updated"}]}}
"data": {
"id": {"record_id": "rec-123"},
"values": {"name": [{"first_name": "Updated"}]},
}
}
mock_request.return_value = mock_response
@@ -223,9 +224,7 @@ class TestAttioClient:
def test_assert_record(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": {"record_id": "rec-upserted"}}
}
mock_response.json.return_value = {"data": {"id": {"record_id": "rec-upserted"}}}
mock_request.return_value = mock_response
values = {"email_addresses": [{"email_address": "test@example.com"}]}
@@ -241,9 +240,7 @@ class TestAttioClient:
def test_list_lists(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "list-1", "name": "Sales Pipeline"}]
}
mock_response.json.return_value = {"data": [{"id": "list-1", "name": "Sales Pipeline"}]}
mock_request.return_value = mock_response
result = self.client.list_lists()
@@ -255,9 +252,7 @@ class TestAttioClient:
def test_get_entries(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "entry-1"}, {"id": "entry-2"}]
}
mock_response.json.return_value = {"data": [{"id": "entry-1"}, {"id": "entry-2"}]}
mock_request.return_value = mock_response
result = self.client.get_entries("list-1")
@@ -332,9 +327,7 @@ class TestAttioClient:
def test_list_tasks(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "task-1"}, {"id": "task-2"}]
}
mock_response.json.return_value = {"data": [{"id": "task-1"}, {"id": "task-2"}]}
mock_request.return_value = mock_response
result = self.client.list_tasks()
@@ -346,9 +339,7 @@ class TestAttioClient:
def test_get_task(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": "task-1", "content": "Call back"}
}
mock_response.json.return_value = {"data": {"id": "task-1", "content": "Call back"}}
mock_request.return_value = mock_response
result = self.client.get_task("task-1")
@@ -26,7 +26,10 @@ def _get_config() -> tuple[str, str, str] | dict:
secret_key = os.getenv("AWS_SECRET_ACCESS_KEY", "")
region = os.getenv("AWS_REGION", "us-east-1")
if not access_key or not secret_key:
return {"error": "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required", "help": "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables"}
return {
"error": "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required",
"help": "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables",
}
return access_key, secret_key, region
@@ -72,9 +75,7 @@ def _sign_request(
# Canonical headers
signed_header_names = sorted(headers.keys())
canonical_headers = "".join(
f"{k}:{headers[k].strip()}\n" for k in signed_header_names
)
canonical_headers = "".join(f"{k}:{headers[k].strip()}\n" for k in signed_header_names)
signed_headers = ";".join(signed_header_names)
canonical_request = (
@@ -131,7 +132,7 @@ def _parse_xml(text: str, ns: str = "") -> ET.Element:
if ns:
for elem in root.iter():
if elem.tag.startswith(f"{{{ns}}}"):
elem.tag = elem.tag[len(f"{{{ns}}}"):]
elem.tag = elem.tag[len(f"{{{ns}}}") :]
return root
@@ -158,10 +159,12 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
for b in root.findall(".//Bucket"):
name_el = b.find("Name")
date_el = b.find("CreationDate")
buckets.append({
"name": name_el.text if name_el is not None else None,
"creation_date": date_el.text if date_el is not None else None,
})
buckets.append(
{
"name": name_el.text if name_el is not None else None,
"creation_date": date_el.text if date_el is not None else None,
}
)
return {"count": len(buckets), "buckets": buckets}
@mcp.tool()
@@ -202,11 +205,13 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
key_el = c.find("Key")
size_el = c.find("Size")
modified_el = c.find("LastModified")
objects.append({
"key": key_el.text if key_el is not None else None,
"size": int(size_el.text) if size_el is not None else 0,
"last_modified": modified_el.text if modified_el is not None else None,
})
objects.append(
{
"key": key_el.text if key_el is not None else None,
"size": int(size_el.text) if size_el is not None else 0,
"last_modified": modified_el.text if modified_el is not None else None,
}
)
prefixes = []
for cp in root.findall("CommonPrefixes"):
p_el = cp.find("Prefix")
@@ -297,7 +302,9 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
body = content.encode("utf-8")
extra = {"content-type": content_type}
resp = _s3_request("PUT", bucket, key, access_key, secret_key, region, body=body, extra_headers=extra)
resp = _s3_request(
"PUT", bucket, key, access_key, secret_key, region, body=body, extra_headers=extra
)
if resp.status_code >= 400:
return {"error": f"HTTP {resp.status_code}: {resp.text[:500]}"}
@@ -21,7 +21,10 @@ def _get_config() -> tuple[dict, str] | dict:
token = os.getenv("AZURE_SQL_ACCESS_TOKEN", "")
sub_id = os.getenv("AZURE_SUBSCRIPTION_ID", "")
if not token or not sub_id:
return {"error": "AZURE_SQL_ACCESS_TOKEN and AZURE_SUBSCRIPTION_ID are required", "help": "Set AZURE_SQL_ACCESS_TOKEN and AZURE_SUBSCRIPTION_ID environment variables"}
return {
"error": "AZURE_SQL_ACCESS_TOKEN and AZURE_SUBSCRIPTION_ID are required",
"help": "Set AZURE_SQL_ACCESS_TOKEN and AZURE_SUBSCRIPTION_ID environment variables",
}
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
return headers, sub_id
@@ -149,9 +152,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
}
@mcp.tool()
def azure_sql_get_database(
resource_group: str, server_name: str, database_name: str
) -> dict:
def azure_sql_get_database(resource_group: str, server_name: str, database_name: str) -> dict:
"""Get details of a specific Azure SQL database.
Args:
@@ -174,9 +175,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
return _extract_database(data)
@mcp.tool()
def azure_sql_list_firewall_rules(
resource_group: str, server_name: str
) -> dict:
def azure_sql_list_firewall_rules(resource_group: str, server_name: str) -> dict:
"""List firewall rules for an Azure SQL server.
Args:
@@ -189,9 +189,7 @@ def register_tools(
if credentials is not None:
key = credentials.get("brevo")
if key is not None and not isinstance(key, str):
raise TypeError(
f"Expected string from credentials, got {type(key).__name__}"
)
raise TypeError(f"Expected string from credentials, got {type(key).__name__}")
return key
return os.getenv("BREVO_API_KEY")
@@ -46,7 +46,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "CALENDLY_PAT is required", "help": "Set CALENDLY_PAT environment variable"}
return {
"error": "CALENDLY_PAT is required",
"help": "Set CALENDLY_PAT environment variable",
}
data = _get("/users/me", headers)
if "error" in data:
@@ -77,7 +80,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "CALENDLY_PAT is required", "help": "Set CALENDLY_PAT environment variable"}
return {
"error": "CALENDLY_PAT is required",
"help": "Set CALENDLY_PAT environment variable",
}
if not user_uri:
return {"error": "user_uri is required"}
@@ -129,7 +135,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "CALENDLY_PAT is required", "help": "Set CALENDLY_PAT environment variable"}
return {
"error": "CALENDLY_PAT is required",
"help": "Set CALENDLY_PAT environment variable",
}
if not user_uri:
return {"error": "user_uri is required"}
@@ -175,7 +184,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "CALENDLY_PAT is required", "help": "Set CALENDLY_PAT environment variable"}
return {
"error": "CALENDLY_PAT is required",
"help": "Set CALENDLY_PAT environment variable",
}
if not event_uri:
return {"error": "event_uri is required"}
@@ -213,7 +225,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "CALENDLY_PAT is required", "help": "Set CALENDLY_PAT environment variable"}
return {
"error": "CALENDLY_PAT is required",
"help": "Set CALENDLY_PAT environment variable",
}
if not event_uri:
return {"error": "event_uri is required"}
@@ -22,7 +22,9 @@ if TYPE_CHECKING:
from aden_tools.credentials import CredentialStoreAdapter
def _get_credentials(credentials: CredentialStoreAdapter | None) -> tuple[str | None, str | None, str | None]:
def _get_credentials(
credentials: CredentialStoreAdapter | None,
) -> tuple[str | None, str | None, str | None]:
"""Return (cloud_name, api_key, api_secret)."""
if credentials is not None:
cloud = credentials.get("cloudinary_cloud_name")
@@ -45,9 +47,7 @@ def _auth_header(api_key: str, api_secret: str) -> str:
return f"Basic {encoded}"
def _request(
method: str, url: str, api_key: str, api_secret: str, **kwargs: Any
) -> dict[str, Any]:
def _request(method: str, url: str, api_key: str, api_secret: str, **kwargs: Any) -> dict[str, Any]:
"""Make a request to the Cloudinary API."""
headers = kwargs.pop("headers", {})
headers["Authorization"] = _auth_header(api_key, api_secret)
@@ -165,15 +165,17 @@ def register_tools(
resources = []
for r in data.get("resources", []):
resources.append({
"public_id": r.get("public_id", ""),
"secure_url": r.get("secure_url", ""),
"format": r.get("format", ""),
"bytes": r.get("bytes", 0),
"width": r.get("width"),
"height": r.get("height"),
"created_at": r.get("created_at", ""),
})
resources.append(
{
"public_id": r.get("public_id", ""),
"secure_url": r.get("secure_url", ""),
"format": r.get("format", ""),
"bytes": r.get("bytes", 0),
"width": r.get("width"),
"height": r.get("height"),
"created_at": r.get("created_at", ""),
}
)
return {"resources": resources, "count": len(resources)}
@mcp.tool()
@@ -269,20 +271,24 @@ def register_tools(
"expression": expression,
"max_results": max(1, min(max_results, 500)),
}
data = _request("post", url, key, secret, json=body, headers={"Content-Type": "application/json"})
data = _request(
"post", url, key, secret, json=body, headers={"Content-Type": "application/json"}
)
if "error" in data:
return data
resources = []
for r in data.get("resources", []):
resources.append({
"public_id": r.get("public_id", ""),
"secure_url": r.get("secure_url", ""),
"format": r.get("format", ""),
"resource_type": r.get("resource_type", ""),
"bytes": r.get("bytes", 0),
"created_at": r.get("created_at", ""),
})
resources.append(
{
"public_id": r.get("public_id", ""),
"secure_url": r.get("secure_url", ""),
"format": r.get("format", ""),
"resource_type": r.get("resource_type", ""),
"bytes": r.get("bytes", 0),
"created_at": r.get("created_at", ""),
}
)
return {
"resources": resources,
"total_count": data.get("total_count", 0),
@@ -22,7 +22,9 @@ if TYPE_CHECKING:
from aden_tools.credentials import CredentialStoreAdapter
def _get_credentials(credentials: CredentialStoreAdapter | None) -> tuple[str | None, str | None, str | None]:
def _get_credentials(
credentials: CredentialStoreAdapter | None,
) -> tuple[str | None, str | None, str | None]:
"""Return (domain, email, api_token)."""
if credentials is not None:
domain = credentials.get("confluence_domain")
@@ -47,9 +49,7 @@ def _auth_header(email: str, token: str) -> str:
return f"Basic {encoded}"
def _request(
method: str, url: str, email: str, token: str, **kwargs: Any
) -> dict[str, Any]:
def _request(method: str, url: str, email: str, token: str, **kwargs: Any) -> dict[str, Any]:
"""Make a request to the Confluence API."""
headers = {
"Authorization": _auth_header(email, token),
@@ -113,13 +113,15 @@ def register_tools(
spaces = []
for s in data.get("results", []):
spaces.append({
"id": s.get("id", ""),
"key": s.get("key", ""),
"name": s.get("name", ""),
"type": s.get("type", ""),
"status": s.get("status", ""),
})
spaces.append(
{
"id": s.get("id", ""),
"key": s.get("key", ""),
"name": s.get("name", ""),
"type": s.get("type", ""),
"status": s.get("status", ""),
}
)
return {"spaces": spaces, "count": len(spaces)}
@mcp.tool()
@@ -159,14 +161,16 @@ def register_tools(
pages = []
for p in data.get("results", []):
ver = p.get("version") or {}
pages.append({
"id": p.get("id", ""),
"title": p.get("title", ""),
"space_id": p.get("spaceId", ""),
"status": p.get("status", ""),
"version": ver.get("number", 0),
"created_at": p.get("createdAt", ""),
})
pages.append(
{
"id": p.get("id", ""),
"title": p.get("title", ""),
"space_id": p.get("spaceId", ""),
"status": p.get("status", ""),
"version": ver.get("number", 0),
"created_at": p.get("createdAt", ""),
}
)
return {"pages": pages, "count": len(pages)}
@mcp.tool()
@@ -294,10 +298,16 @@ def register_tools(
cql = " AND ".join(cql_parts) + " ORDER BY lastModified desc"
url = f"{_base_url(domain)}/wiki/rest/api/search"
data = _request("get", url, email, token, params={
"cql": cql,
"limit": max(1, min(limit, 50)),
})
data = _request(
"get",
url,
email,
token,
params={
"cql": cql,
"limit": max(1, min(limit, 50)),
},
)
if "error" in data:
return data
@@ -305,12 +315,14 @@ def register_tools(
for r in data.get("results", []):
content = r.get("content") or {}
space = content.get("space") or {}
results.append({
"title": r.get("title", ""),
"excerpt": (r.get("excerpt", "") or "")[:300],
"page_id": content.get("id", ""),
"space_key": space.get("key", ""),
"space_name": space.get("name", ""),
"last_modified": r.get("lastModified", ""),
})
results.append(
{
"title": r.get("title", ""),
"excerpt": (r.get("excerpt", "") or "")[:300],
"page_id": content.get("id", ""),
"space_key": space.get("key", ""),
"space_name": space.get("name", ""),
"last_modified": r.get("lastModified", ""),
}
)
return {"results": results, "count": len(results)}
@@ -38,7 +38,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(host: str, endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{host}/api/2.0/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{host}/api/2.0/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your DATABRICKS_TOKEN."}
if resp.status_code == 403:
@@ -54,7 +56,9 @@ def _get(host: str, endpoint: str, token: str, params: dict | None = None) -> di
def _post(host: str, endpoint: str, token: str, body: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.post(f"{host}/api/2.0/{endpoint}", headers=_headers(token), json=body or {}, timeout=60.0)
resp = httpx.post(
f"{host}/api/2.0/{endpoint}", headers=_headers(token), json=body or {}, timeout=60.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your DATABRICKS_TOKEN."}
if resp.status_code not in (200, 201):
@@ -165,12 +169,14 @@ def register_tools(
jobs = []
for job in data.get("jobs", []):
settings = job.get("settings", {})
jobs.append({
"job_id": job.get("job_id", 0),
"name": settings.get("name", ""),
"creator": job.get("creator_user_name", ""),
"created_time": job.get("created_time", 0),
})
jobs.append(
{
"job_id": job.get("job_id", 0),
"name": settings.get("name", ""),
"creator": job.get("creator_user_name", ""),
"created_time": job.get("created_time", 0),
}
)
return {"jobs": jobs}
@mcp.tool()
@@ -248,14 +254,16 @@ def register_tools(
clusters = []
for c in data.get("clusters", []):
clusters.append({
"cluster_id": c.get("cluster_id", ""),
"cluster_name": c.get("cluster_name", ""),
"state": c.get("state", ""),
"spark_version": c.get("spark_version", ""),
"creator": c.get("creator_user_name", ""),
"num_workers": c.get("num_workers", 0),
})
clusters.append(
{
"cluster_id": c.get("cluster_id", ""),
"cluster_name": c.get("cluster_name", ""),
"state": c.get("state", ""),
"spark_version": c.get("spark_version", ""),
"creator": c.get("creator_user_name", ""),
"num_workers": c.get("num_workers", 0),
}
)
return {"clusters": clusters}
@mcp.tool()
@@ -325,9 +333,11 @@ def register_tools(
objects = []
for obj in data.get("objects", []):
objects.append({
"path": obj.get("path", ""),
"object_type": obj.get("object_type", ""),
"language": obj.get("language", ""),
})
objects.append(
{
"path": obj.get("path", ""),
"object_type": obj.get("object_type", ""),
"language": obj.get("language", ""),
}
)
return {"path": path, "objects": objects}
@@ -35,7 +35,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{HUB_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{HUB_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your DOCKER_HUB_TOKEN."}
if resp.status_code == 404:
@@ -91,14 +93,16 @@ def register_tools(
results = []
for r in data.get("results", []):
results.append({
"repo_name": r.get("repo_name", ""),
"short_description": r.get("short_description", ""),
"star_count": r.get("star_count", 0),
"is_official": r.get("is_official", False),
"is_automated": r.get("is_automated", False),
"pull_count": r.get("pull_count", 0),
})
results.append(
{
"repo_name": r.get("repo_name", ""),
"short_description": r.get("short_description", ""),
"star_count": r.get("star_count", 0),
"is_official": r.get("is_official", False),
"is_automated": r.get("is_automated", False),
"pull_count": r.get("pull_count", 0),
}
)
return {"query": query, "results": results}
@mcp.tool()
@@ -133,15 +137,17 @@ def register_tools(
repos = []
for r in data.get("results", []):
repos.append({
"name": r.get("name", ""),
"namespace": r.get("namespace", ""),
"description": r.get("description", ""),
"star_count": r.get("star_count", 0),
"pull_count": r.get("pull_count", 0),
"last_updated": r.get("last_updated", ""),
"is_private": r.get("is_private", False),
})
repos.append(
{
"name": r.get("name", ""),
"namespace": r.get("namespace", ""),
"description": r.get("description", ""),
"star_count": r.get("star_count", 0),
"pull_count": r.get("pull_count", 0),
"last_updated": r.get("last_updated", ""),
"is_private": r.get("is_private", False),
}
)
return {"namespace": namespace, "repos": repos}
@mcp.tool()
@@ -166,7 +172,11 @@ def register_tools(
return {"error": "repository is required"}
max_results = max(1, min(max_results, 100))
data = _get(f"repositories/{repository}/tags", token, {"page_size": max_results, "ordering": "-last_updated"})
data = _get(
f"repositories/{repository}/tags",
token,
{"page_size": max_results, "ordering": "-last_updated"},
)
if "error" in data:
return data
@@ -174,12 +184,14 @@ def register_tools(
for t in data.get("results", []):
images = t.get("images", [])
digest = images[0].get("digest", "") if images else ""
tags.append({
"name": t.get("name", ""),
"full_size": t.get("full_size", 0),
"last_updated": t.get("last_updated", ""),
"digest": digest,
})
tags.append(
{
"name": t.get("name", ""),
"full_size": t.get("full_size", 0),
"last_updated": t.get("last_updated", ""),
"digest": digest,
}
)
return {"repository": repository, "tags": tags}
@mcp.tool()
@@ -60,11 +60,13 @@ def register_tools(mcp: FastMCP) -> None:
results = list(ddgs.text(**kwargs))
items = []
for r in results:
items.append({
"title": r.get("title", ""),
"url": r.get("href", ""),
"snippet": r.get("body", ""),
})
items.append(
{
"title": r.get("title", ""),
"url": r.get("href", ""),
"snippet": r.get("body", ""),
}
)
return {"query": query, "results": items, "count": len(items)}
except Exception as e:
return {"error": f"DuckDuckGo search failed: {e!s}"}
@@ -106,13 +108,15 @@ def register_tools(mcp: FastMCP) -> None:
results = list(ddgs.news(**kwargs))
items = []
for r in results:
items.append({
"title": r.get("title", ""),
"url": r.get("url", ""),
"source": r.get("source", ""),
"date": r.get("date", ""),
"snippet": r.get("body", ""),
})
items.append(
{
"title": r.get("title", ""),
"url": r.get("url", ""),
"source": r.get("source", ""),
"date": r.get("date", ""),
"snippet": r.get("body", ""),
}
)
return {"query": query, "results": items, "count": len(items)}
except Exception as e:
return {"error": f"DuckDuckGo news search failed: {e!s}"}
@@ -157,14 +161,16 @@ def register_tools(mcp: FastMCP) -> None:
results = list(ddgs.images(**kwargs))
items = []
for r in results:
items.append({
"title": r.get("title", ""),
"image_url": r.get("image", ""),
"thumbnail_url": r.get("thumbnail", ""),
"source": r.get("source", ""),
"width": r.get("width", 0),
"height": r.get("height", 0),
})
items.append(
{
"title": r.get("title", ""),
"image_url": r.get("image", ""),
"thumbnail_url": r.get("thumbnail", ""),
"source": r.get("source", ""),
"width": r.get("width", 0),
"height": r.get("height", 0),
}
)
return {"query": query, "results": items, "count": len(items)}
except Exception as e:
return {"error": f"DuckDuckGo image search failed: {e!s}"}
@@ -34,7 +34,9 @@ def _get_credentials(credentials: CredentialStoreAdapter | None) -> tuple[str |
return url, token
def _get(base_url: str, path: str, token: str, params: dict[str, Any] | None = None) -> dict[str, Any] | list:
def _get(
base_url: str, path: str, token: str, params: dict[str, Any] | None = None
) -> dict[str, Any] | list:
"""Make an authenticated GET to the GitLab API."""
try:
resp = httpx.get(
@@ -60,7 +62,9 @@ def _get(base_url: str, path: str, token: str, params: dict[str, Any] | None = N
return {"error": f"GitLab request failed: {e!s}"}
def _post(base_url: str, path: str, token: str, json: dict[str, Any] | None = None) -> dict[str, Any] | list:
def _post(
base_url: str, path: str, token: str, json: dict[str, Any] | None = None
) -> dict[str, Any] | list:
"""Make an authenticated POST to the GitLab API."""
try:
resp = httpx.post(
@@ -135,18 +139,20 @@ def register_tools(
return data
projects = []
for p in (data if isinstance(data, list) else []):
projects.append({
"id": p.get("id"),
"name": p.get("name", ""),
"path_with_namespace": p.get("path_with_namespace", ""),
"description": (p.get("description") or "")[:200],
"visibility": p.get("visibility", ""),
"default_branch": p.get("default_branch", ""),
"web_url": p.get("web_url", ""),
"star_count": p.get("star_count", 0),
"last_activity_at": p.get("last_activity_at", ""),
})
for p in data if isinstance(data, list) else []:
projects.append(
{
"id": p.get("id"),
"name": p.get("name", ""),
"path_with_namespace": p.get("path_with_namespace", ""),
"description": (p.get("description") or "")[:200],
"visibility": p.get("visibility", ""),
"default_branch": p.get("default_branch", ""),
"web_url": p.get("web_url", ""),
"star_count": p.get("star_count", 0),
"last_activity_at": p.get("last_activity_at", ""),
}
)
return {"projects": projects, "count": len(projects)}
@mcp.tool()
@@ -233,19 +239,21 @@ def register_tools(
return data
issues = []
for i in (data if isinstance(data, list) else []):
for i in data if isinstance(data, list) else []:
assignees = [a.get("username", "") for a in i.get("assignees", [])]
issues.append({
"iid": i.get("iid"),
"title": i.get("title", ""),
"state": i.get("state", ""),
"labels": i.get("labels", []),
"assignees": assignees,
"author": (i.get("author") or {}).get("username", ""),
"created_at": i.get("created_at", ""),
"updated_at": i.get("updated_at", ""),
"web_url": i.get("web_url", ""),
})
issues.append(
{
"iid": i.get("iid"),
"title": i.get("title", ""),
"state": i.get("state", ""),
"labels": i.get("labels", []),
"assignees": assignees,
"author": (i.get("author") or {}).get("username", ""),
"created_at": i.get("created_at", ""),
"updated_at": i.get("updated_at", ""),
"web_url": i.get("web_url", ""),
}
)
return {"issues": issues, "count": len(issues)}
@mcp.tool()
@@ -375,16 +383,18 @@ def register_tools(
return data
mrs = []
for mr in (data if isinstance(data, list) else []):
mrs.append({
"iid": mr.get("iid"),
"title": mr.get("title", ""),
"state": mr.get("state", ""),
"source_branch": mr.get("source_branch", ""),
"target_branch": mr.get("target_branch", ""),
"author": (mr.get("author") or {}).get("username", ""),
"web_url": mr.get("web_url", ""),
"created_at": mr.get("created_at", ""),
"updated_at": mr.get("updated_at", ""),
})
for mr in data if isinstance(data, list) else []:
mrs.append(
{
"iid": mr.get("iid"),
"title": mr.get("title", ""),
"state": mr.get("state", ""),
"source_branch": mr.get("source_branch", ""),
"target_branch": mr.get("target_branch", ""),
"author": (mr.get("author") or {}).get("username", ""),
"web_url": mr.get("web_url", ""),
"created_at": mr.get("created_at", ""),
"updated_at": mr.get("updated_at", ""),
}
)
return {"merge_requests": mrs, "count": len(mrs)}
@@ -51,9 +51,13 @@ def _get(endpoint: str, token: str, base: str = GSC_API) -> dict[str, Any]:
return {"error": f"Request failed: {e!s}"}
def _post(endpoint: str, token: str, body: dict | None = None, base: str = GSC_API) -> dict[str, Any]:
def _post(
endpoint: str, token: str, body: dict | None = None, base: str = GSC_API
) -> dict[str, Any]:
try:
resp = httpx.post(f"{base}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0)
resp = httpx.post(
f"{base}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your GOOGLE_SEARCH_CONSOLE_TOKEN."}
if resp.status_code == 403:
@@ -77,6 +81,7 @@ def _auth_error() -> dict[str, Any]:
def _encode_site(site_url: str) -> str:
"""URL-encode the site URL for API paths."""
import urllib.parse
return urllib.parse.quote(site_url, safe="")
@@ -130,13 +135,15 @@ def register_tools(
rows = []
for r in data.get("rows", []):
rows.append({
"keys": r.get("keys", []),
"clicks": r.get("clicks", 0),
"impressions": r.get("impressions", 0),
"ctr": round(r.get("ctr", 0), 4),
"position": round(r.get("position", 0), 1),
})
rows.append(
{
"keys": r.get("keys", []),
"clicks": r.get("clicks", 0),
"impressions": r.get("impressions", 0),
"ctr": round(r.get("ctr", 0), 4),
"position": round(r.get("position", 0), 1),
}
)
return {"site_url": site_url, "rows": rows, "count": len(rows)}
@mcp.tool()
@@ -157,10 +164,12 @@ def register_tools(
sites = []
for s in data.get("siteEntry", []):
sites.append({
"site_url": s.get("siteUrl", ""),
"permission_level": s.get("permissionLevel", ""),
})
sites.append(
{
"site_url": s.get("siteUrl", ""),
"permission_level": s.get("permissionLevel", ""),
}
)
return {"sites": sites}
@mcp.tool()
@@ -187,14 +196,16 @@ def register_tools(
sitemaps = []
for s in data.get("sitemap", []):
sitemaps.append({
"path": s.get("path", ""),
"last_submitted": s.get("lastSubmitted", ""),
"is_pending": s.get("isPending", False),
"is_index": s.get("isSitemapsIndex", False),
"warnings": s.get("warnings", 0),
"errors": s.get("errors", 0),
})
sitemaps.append(
{
"path": s.get("path", ""),
"last_submitted": s.get("lastSubmitted", ""),
"is_pending": s.get("isPending", False),
"is_index": s.get("isSitemapsIndex", False),
"warnings": s.get("warnings", 0),
"errors": s.get("errors", 0),
}
)
return {"site_url": site_url, "sitemaps": sitemaps}
@mcp.tool()
@@ -42,7 +42,9 @@ def _get(path: str, api_key: str, params: dict[str, Any] | None = None) -> dict[
if resp.status_code == 400:
return {"error": f"Bad request: {resp.text[:500]}"}
if resp.status_code == 403:
return {"error": "Forbidden. The spreadsheet may not be public or the API key is invalid."}
return {
"error": "Forbidden. The spreadsheet may not be public or the API key is invalid."
}
if resp.status_code == 404:
return {"error": "Spreadsheet not found."}
if resp.status_code != 200:
@@ -99,13 +101,15 @@ def register_tools(
for s in data.get("sheets", []):
sp = s.get("properties", {})
grid = sp.get("gridProperties", {})
sheets.append({
"title": sp.get("title", ""),
"sheet_id": sp.get("sheetId"),
"index": sp.get("index", 0),
"row_count": grid.get("rowCount", 0),
"column_count": grid.get("columnCount", 0),
})
sheets.append(
{
"title": sp.get("title", ""),
"sheet_id": sp.get("sheetId"),
"index": sp.get("index", 0),
"row_count": grid.get("rowCount", 0),
"column_count": grid.get("columnCount", 0),
}
)
return {
"spreadsheet_id": data.get("spreadsheetId", ""),
@@ -190,9 +194,11 @@ def register_tools(
results = []
for vr in data.get("valueRanges", []):
values = vr.get("values", [])
results.append({
"range": vr.get("range", ""),
"values": values,
"row_count": len(values),
})
results.append(
{
"range": vr.get("range", ""),
"values": values,
"row_count": len(values),
}
)
return {"ranges": results, "count": len(results)}
@@ -107,16 +107,18 @@ def register_tools(
return data
jobs = []
for j in (data if isinstance(data, list) else []):
jobs.append({
"id": j.get("id"),
"name": j.get("name", ""),
"status": j.get("status", ""),
"departments": [d.get("name", "") for d in j.get("departments", [])],
"offices": [o.get("name", "") for o in j.get("offices", [])],
"created_at": j.get("created_at", ""),
"updated_at": j.get("updated_at", ""),
})
for j in data if isinstance(data, list) else []:
jobs.append(
{
"id": j.get("id"),
"name": j.get("name", ""),
"status": j.get("status", ""),
"departments": [d.get("name", "") for d in j.get("departments", [])],
"offices": [o.get("name", "") for o in j.get("offices", [])],
"created_at": j.get("created_at", ""),
"updated_at": j.get("updated_at", ""),
}
)
return {"jobs": jobs, "count": len(jobs)}
@mcp.tool()
@@ -150,8 +152,7 @@ def register_tools(
"departments": [d.get("name", "") for d in data.get("departments", [])],
"offices": [o.get("name", "") for o in data.get("offices", [])],
"openings": [
{"id": o.get("id"), "status": o.get("status", "")}
for o in data.get("openings", [])
{"id": o.get("id"), "status": o.get("status", "")} for o in data.get("openings", [])
],
"created_at": data.get("created_at", ""),
"updated_at": data.get("updated_at", ""),
@@ -195,17 +196,19 @@ def register_tools(
return data
candidates = []
for c in (data if isinstance(data, list) else []):
candidates.append({
"id": c.get("id"),
"first_name": c.get("first_name", ""),
"last_name": c.get("last_name", ""),
"company": c.get("company", ""),
"title": c.get("title", ""),
"tags": c.get("tags", []),
"application_ids": c.get("application_ids", []),
"created_at": c.get("created_at", ""),
})
for c in data if isinstance(data, list) else []:
candidates.append(
{
"id": c.get("id"),
"first_name": c.get("first_name", ""),
"last_name": c.get("last_name", ""),
"company": c.get("company", ""),
"title": c.get("title", ""),
"tags": c.get("tags", []),
"application_ids": c.get("application_ids", []),
"created_at": c.get("created_at", ""),
}
)
return {"candidates": candidates, "count": len(candidates)}
@mcp.tool()
@@ -285,18 +288,20 @@ def register_tools(
return data
apps = []
for a in (data if isinstance(data, list) else []):
for a in data if isinstance(data, list) else []:
stage = a.get("current_stage") or {}
jobs = [j.get("name", "") for j in a.get("jobs", [])]
apps.append({
"id": a.get("id"),
"candidate_id": a.get("candidate_id"),
"status": a.get("status", ""),
"current_stage": stage.get("name", ""),
"jobs": jobs,
"applied_at": a.get("applied_at", ""),
"last_activity_at": a.get("last_activity_at", ""),
})
apps.append(
{
"id": a.get("id"),
"candidate_id": a.get("candidate_id"),
"status": a.get("status", ""),
"current_stage": stage.get("name", ""),
"jobs": jobs,
"applied_at": a.get("applied_at", ""),
"last_activity_at": a.get("last_activity_at", ""),
}
)
return {"applications": apps, "count": len(apps)}
@mcp.tool()
@@ -29,7 +29,9 @@ def _get_token(credentials: CredentialStoreAdapter | None) -> str | None:
return os.getenv("HUGGINGFACE_TOKEN")
def _get(path: str, token: str | None, params: dict[str, Any] | None = None) -> dict[str, Any] | list:
def _get(
path: str, token: str | None, params: dict[str, Any] | None = None
) -> dict[str, Any] | list:
"""Make a GET request to the HuggingFace Hub API."""
headers: dict[str, str] = {}
if token:
@@ -106,15 +108,17 @@ def register_tools(
models = []
for m in data if isinstance(data, list) else []:
models.append({
"id": m.get("id", ""),
"author": m.get("author", ""),
"downloads": m.get("downloads", 0),
"likes": m.get("likes", 0),
"pipeline_tag": m.get("pipeline_tag", ""),
"tags": m.get("tags", [])[:10],
"last_modified": m.get("lastModified", ""),
})
models.append(
{
"id": m.get("id", ""),
"author": m.get("author", ""),
"downloads": m.get("downloads", 0),
"likes": m.get("likes", 0),
"pipeline_tag": m.get("pipeline_tag", ""),
"tags": m.get("tags", [])[:10],
"last_modified": m.get("lastModified", ""),
}
)
return {"models": models, "count": len(models)}
@mcp.tool()
@@ -193,14 +197,16 @@ def register_tools(
datasets = []
for d in data if isinstance(data, list) else []:
datasets.append({
"id": d.get("id", ""),
"author": d.get("author", ""),
"downloads": d.get("downloads", 0),
"likes": d.get("likes", 0),
"tags": d.get("tags", [])[:10],
"last_modified": d.get("lastModified", ""),
})
datasets.append(
{
"id": d.get("id", ""),
"author": d.get("author", ""),
"downloads": d.get("downloads", 0),
"likes": d.get("likes", 0),
"tags": d.get("tags", [])[:10],
"last_modified": d.get("lastModified", ""),
}
)
return {"datasets": datasets, "count": len(datasets)}
@mcp.tool()
@@ -276,14 +282,16 @@ def register_tools(
spaces = []
for s in data if isinstance(data, list) else []:
spaces.append({
"id": s.get("id", ""),
"author": s.get("author", ""),
"likes": s.get("likes", 0),
"sdk": s.get("sdk", ""),
"tags": s.get("tags", [])[:10],
"last_modified": s.get("lastModified", ""),
})
spaces.append(
{
"id": s.get("id", ""),
"author": s.get("author", ""),
"likes": s.get("likes", 0),
"sdk": s.get("sdk", ""),
"tags": s.get("tags", [])[:10],
"last_modified": s.get("lastModified", ""),
}
)
return {"spaces": spaces, "count": len(spaces)}
@mcp.tool()
@@ -304,8 +312,7 @@ def register_tools(
u = data if isinstance(data, dict) else {}
orgs = [
{"name": o.get("name", ""), "role": o.get("roleInOrg", "")}
for o in u.get("orgs", [])
{"name": o.get("name", ""), "role": o.get("roleInOrg", "")} for o in u.get("orgs", [])
]
return {
"name": u.get("name", ""),
@@ -21,7 +21,9 @@ if TYPE_CHECKING:
from aden_tools.credentials import CredentialStoreAdapter
def _get_credentials(credentials: CredentialStoreAdapter | None) -> tuple[str | None, str | None, str | None]:
def _get_credentials(
credentials: CredentialStoreAdapter | None,
) -> tuple[str | None, str | None, str | None]:
"""Return (domain, email, api_token)."""
if credentials is not None:
domain = credentials.get("jira_domain")
@@ -44,9 +46,7 @@ def _auth_header(email: str, token: str) -> str:
return f"Basic {encoded}"
def _request(
method: str, url: str, email: str, token: str, **kwargs: Any
) -> dict[str, Any]:
def _request(method: str, url: str, email: str, token: str, **kwargs: Any) -> dict[str, Any]:
"""Make a request to the Jira API."""
headers = kwargs.pop("headers", {})
headers["Authorization"] = _auth_header(email, token)
@@ -159,14 +159,16 @@ def register_tools(
assignee = f.get("assignee") or {}
priority = f.get("priority") or {}
issuetype = f.get("issuetype") or {}
issues.append({
"key": issue.get("key", ""),
"summary": f.get("summary", ""),
"status": status.get("name", ""),
"assignee": assignee.get("displayName", ""),
"priority": priority.get("name", ""),
"issuetype": issuetype.get("name", ""),
})
issues.append(
{
"key": issue.get("key", ""),
"summary": f.get("summary", ""),
"status": status.get("name", ""),
"assignee": assignee.get("displayName", ""),
"priority": priority.get("name", ""),
"issuetype": issuetype.get("name", ""),
}
)
return {"issues": issues, "count": len(issues)}
@mcp.tool()
@@ -299,12 +301,14 @@ def register_tools(
projects = []
for p in data.get("values", []):
projects.append({
"key": p.get("key", ""),
"name": p.get("name", ""),
"id": p.get("id", ""),
"project_type": p.get("projectTypeKey", ""),
})
projects.append(
{
"key": p.get("key", ""),
"name": p.get("name", ""),
"id": p.get("id", ""),
"project_type": p.get("projectTypeKey", ""),
}
)
return {"projects": projects, "count": len(projects)}
@mcp.tool()
@@ -19,9 +19,15 @@ def _get_config() -> tuple[str, str, dict] | dict:
rest_url = os.getenv("KAFKA_REST_URL", "").rstrip("/")
cluster_id = os.getenv("KAFKA_CLUSTER_ID", "")
if not rest_url:
return {"error": "KAFKA_REST_URL is required", "help": "Set KAFKA_REST_URL environment variable"}
return {
"error": "KAFKA_REST_URL is required",
"help": "Set KAFKA_REST_URL environment variable",
}
if not cluster_id:
return {"error": "KAFKA_CLUSTER_ID is required", "help": "Set KAFKA_CLUSTER_ID environment variable"}
return {
"error": "KAFKA_CLUSTER_ID is required",
"help": "Set KAFKA_CLUSTER_ID environment variable",
}
headers: dict[str, str] = {"Content-Type": "application/json"}
api_key = os.getenv("KAFKA_API_KEY", "")
@@ -210,7 +216,9 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"id": g.get("consumer_group_id"),
"is_simple": g.get("is_simple"),
"state": g.get("state"),
"coordinator_id": g.get("coordinator", {}).get("related") if isinstance(g.get("coordinator"), dict) else None,
"coordinator_id": g.get("coordinator", {}).get("related")
if isinstance(g.get("coordinator"), dict)
else None,
}
for g in groups
],
@@ -91,7 +91,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "LUSHA_API_KEY is required", "help": "Set LUSHA_API_KEY environment variable"}
return {
"error": "LUSHA_API_KEY is required",
"help": "Set LUSHA_API_KEY environment variable",
}
params: dict[str, str] = {}
if email:
@@ -125,7 +128,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "LUSHA_API_KEY is required", "help": "Set LUSHA_API_KEY environment variable"}
return {
"error": "LUSHA_API_KEY is required",
"help": "Set LUSHA_API_KEY environment variable",
}
params: dict[str, str] = {}
if domain:
@@ -164,7 +170,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "LUSHA_API_KEY is required", "help": "Set LUSHA_API_KEY environment variable"}
return {
"error": "LUSHA_API_KEY is required",
"help": "Set LUSHA_API_KEY environment variable",
}
contacts_include: dict[str, Any] = {}
companies_include: dict[str, Any] = {}
@@ -240,7 +249,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "LUSHA_API_KEY is required", "help": "Set LUSHA_API_KEY environment variable"}
return {
"error": "LUSHA_API_KEY is required",
"help": "Set LUSHA_API_KEY environment variable",
}
companies_include: dict[str, Any] = {}
if company_names:
@@ -281,7 +293,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""Get Lusha API credit usage statistics."""
headers = _get_headers()
if not headers:
return {"error": "LUSHA_API_KEY is required", "help": "Set LUSHA_API_KEY environment variable"}
return {
"error": "LUSHA_API_KEY is required",
"help": "Set LUSHA_API_KEY environment variable",
}
data = _get(f"{BASE_URL}/account/usage", headers)
if "error" in data:
@@ -43,7 +43,9 @@ def _get(endpoint: str, token: str, params: dict[str, Any] | None = None) -> dic
if resp.status_code == 401:
return {"error": "Unauthorized. Access token may be expired or invalid."}
if resp.status_code == 403:
return {"error": f"Forbidden. Missing required permission scope. Details: {resp.text[:300]}"}
return {
"error": f"Forbidden. Missing required permission scope. Details: {resp.text[:300]}"
}
if resp.status_code != 200:
return {"error": f"Microsoft Graph API error {resp.status_code}: {resp.text[:500]}"}
return resp.json()
@@ -61,7 +63,9 @@ def _post(endpoint: str, token: str, json_body: dict[str, Any]) -> dict[str, Any
if resp.status_code == 401:
return {"error": "Unauthorized. Access token may be expired or invalid."}
if resp.status_code == 403:
return {"error": f"Forbidden. Missing required permission scope. Details: {resp.text[:300]}"}
return {
"error": f"Forbidden. Missing required permission scope. Details: {resp.text[:300]}"
}
if resp.status_code not in (200, 201, 202):
return {"error": f"Microsoft Graph API error {resp.status_code}: {resp.text[:500]}"}
if resp.status_code == 202:
@@ -132,16 +136,18 @@ def register_tools(
messages = []
for msg in data.get("value", []):
from_addr = msg.get("from", {}).get("emailAddress", {})
messages.append({
"id": msg.get("id", ""),
"subject": msg.get("subject", ""),
"from_name": from_addr.get("name", ""),
"from_email": from_addr.get("address", ""),
"receivedDateTime": msg.get("receivedDateTime", ""),
"isRead": msg.get("isRead", False),
"hasAttachments": msg.get("hasAttachments", False),
"bodyPreview": msg.get("bodyPreview", ""),
})
messages.append(
{
"id": msg.get("id", ""),
"subject": msg.get("subject", ""),
"from_name": from_addr.get("name", ""),
"from_email": from_addr.get("address", ""),
"receivedDateTime": msg.get("receivedDateTime", ""),
"isRead": msg.get("isRead", False),
"hasAttachments": msg.get("hasAttachments", False),
"bodyPreview": msg.get("bodyPreview", ""),
}
)
return {"folder": folder, "messages": messages}
@mcp.tool()
@@ -170,7 +176,10 @@ def register_tools(
from_addr = data.get("from", {}).get("emailAddress", {})
to_list = [
{"name": r.get("emailAddress", {}).get("name", ""), "email": r.get("emailAddress", {}).get("address", "")}
{
"name": r.get("emailAddress", {}).get("name", ""),
"email": r.get("emailAddress", {}).get("address", ""),
}
for r in data.get("toRecipients", [])
]
return {
@@ -227,7 +236,9 @@ def register_tools(
}
if cc:
message["ccRecipients"] = [
{"emailAddress": {"address": addr.strip()}} for addr in cc.split(",") if addr.strip()
{"emailAddress": {"address": addr.strip()}}
for addr in cc.split(",")
if addr.strip()
]
payload = {"message": message, "saveToSentItems": save_to_sent}
@@ -256,11 +267,13 @@ def register_tools(
teams = []
for team in data.get("value", []):
teams.append({
"id": team.get("id", ""),
"displayName": team.get("displayName", ""),
"description": team.get("description", ""),
})
teams.append(
{
"id": team.get("id", ""),
"displayName": team.get("displayName", ""),
"description": team.get("description", ""),
}
)
return {"teams": teams}
@mcp.tool()
@@ -288,12 +301,14 @@ def register_tools(
channels = []
for ch in data.get("value", []):
channels.append({
"id": ch.get("id", ""),
"displayName": ch.get("displayName", ""),
"description": ch.get("description", ""),
"membershipType": ch.get("membershipType", ""),
})
channels.append(
{
"id": ch.get("id", ""),
"displayName": ch.get("displayName", ""),
"description": ch.get("description", ""),
"membershipType": ch.get("membershipType", ""),
}
)
return {"team_id": team_id, "channels": channels}
@mcp.tool()
@@ -363,13 +378,15 @@ def register_tools(
messages = []
for msg in data.get("value", []):
from_info = msg.get("from", {}).get("user", {})
messages.append({
"id": msg.get("id", ""),
"from_name": from_info.get("displayName", ""),
"body": msg.get("body", {}).get("content", ""),
"contentType": msg.get("body", {}).get("contentType", ""),
"createdDateTime": msg.get("createdDateTime", ""),
})
messages.append(
{
"id": msg.get("id", ""),
"from_name": from_info.get("displayName", ""),
"body": msg.get("body", {}).get("content", ""),
"contentType": msg.get("body", {}).get("contentType", ""),
"createdDateTime": msg.get("createdDateTime", ""),
}
)
return {"team_id": team_id, "channel_id": channel_id, "messages": messages}
# ── OneDrive ────────────────────────────────────────────────
@@ -403,15 +420,17 @@ def register_tools(
files = []
for item in data.get("value", []):
files.append({
"id": item.get("id", ""),
"name": item.get("name", ""),
"size": item.get("size", 0),
"lastModifiedDateTime": item.get("lastModifiedDateTime", ""),
"webUrl": item.get("webUrl", ""),
"mimeType": item.get("file", {}).get("mimeType", ""),
"path": item.get("parentReference", {}).get("path", ""),
})
files.append(
{
"id": item.get("id", ""),
"name": item.get("name", ""),
"size": item.get("size", 0),
"lastModifiedDateTime": item.get("lastModifiedDateTime", ""),
"webUrl": item.get("webUrl", ""),
"mimeType": item.get("file", {}).get("mimeType", ""),
"path": item.get("parentReference", {}).get("path", ""),
}
)
return {"query": query, "files": files}
@mcp.tool()
@@ -446,14 +465,16 @@ def register_tools(
items = []
for item in data.get("value", []):
item_type = "folder" if "folder" in item else "file"
items.append({
"id": item.get("id", ""),
"name": item.get("name", ""),
"size": item.get("size", 0),
"type": item_type,
"lastModifiedDateTime": item.get("lastModifiedDateTime", ""),
"webUrl": item.get("webUrl", ""),
})
items.append(
{
"id": item.get("id", ""),
"name": item.get("name", ""),
"size": item.get("size", 0),
"type": item_type,
"lastModifiedDateTime": item.get("lastModifiedDateTime", ""),
"webUrl": item.get("webUrl", ""),
}
)
return {"path": folder_path or "/", "items": items}
@mcp.tool()
@@ -23,7 +23,10 @@ def _get_config() -> tuple[str, str, str] | dict:
api_key = os.getenv("MONGODB_API_KEY", "")
data_source = os.getenv("MONGODB_DATA_SOURCE", "")
if not url or not api_key:
return {"error": "MONGODB_DATA_API_URL and MONGODB_API_KEY are required", "help": "Set MONGODB_DATA_API_URL and MONGODB_API_KEY environment variables"}
return {
"error": "MONGODB_DATA_API_URL and MONGODB_API_KEY are required",
"help": "Set MONGODB_DATA_API_URL and MONGODB_API_KEY environment variables",
}
return url, api_key, data_source
@@ -73,19 +73,19 @@ def register_tools(
if params["username"] and params["password"]:
# SQL Server Authentication
connection_string = (
f'DRIVER={{ODBC Driver 17 for SQL Server}};'
f'SERVER={params["server"]};'
f'DATABASE={params["database"]};'
f'UID={params["username"]};'
f'PWD={params["password"]};'
f"DRIVER={{ODBC Driver 17 for SQL Server}};"
f"SERVER={params['server']};"
f"DATABASE={params['database']};"
f"UID={params['username']};"
f"PWD={params['password']};"
)
else:
# Windows Authentication
connection_string = (
f'DRIVER={{ODBC Driver 17 for SQL Server}};'
f'SERVER={params["server"]};'
f'DATABASE={params["database"]};'
f'Trusted_Connection=yes;'
f"DRIVER={{ODBC Driver 17 for SQL Server}};"
f"SERVER={params['server']};"
f"DATABASE={params['database']};"
f"Trusted_Connection=yes;"
)
connection = pyodbc.connect(connection_string, timeout=10)
@@ -215,14 +215,14 @@ def register_tools(
if not any(query_upper.startswith(kw) for kw in allowed_keywords):
return {
"error": f"Only {', '.join(allowed_keywords)} queries are allowed. "
"Use mssql_execute_query for SELECT."
"Use mssql_execute_query for SELECT."
}
# Safety check for DELETE without WHERE
if query_upper.startswith("DELETE") and "WHERE" not in query_upper:
return {
"error": "DELETE without WHERE clause is not allowed for safety. "
"Add a WHERE clause or use DELETE FROM table WHERE 1=1 if intentional."
"Add a WHERE clause or use DELETE FROM table WHERE 1=1 if intentional."
}
connection, error = _create_connection()
@@ -320,17 +320,21 @@ def register_tools(
else:
# Get detailed table schema
# Check if table exists
cursor.execute("""
cursor.execute(
"""
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = ?
""", table_name)
""",
table_name,
)
if cursor.fetchone()[0] == 0:
return {"error": f"Table '{table_name}' not found"}
# Get columns
cursor.execute("""
cursor.execute(
"""
SELECT
c.COLUMN_NAME,
c.DATA_TYPE,
@@ -348,7 +352,10 @@ def register_tools(
) pk ON c.COLUMN_NAME = pk.COLUMN_NAME
WHERE c.TABLE_NAME = ?
ORDER BY c.ORDINAL_POSITION
""", table_name, table_name)
""",
table_name,
table_name,
)
columns = []
for row in cursor.fetchall():
@@ -356,15 +363,18 @@ def register_tools(
if row[2]: # Add length for varchar/nvarchar
col_type += f"({row[2]})"
columns.append({
"name": row[0],
"type": col_type,
"nullable": row[3] == "YES",
"primary_key": bool(row[4]),
})
columns.append(
{
"name": row[0],
"type": col_type,
"nullable": row[3] == "YES",
"primary_key": bool(row[4]),
}
)
# Get foreign keys
cursor.execute("""
cursor.execute(
"""
SELECT
kcu.COLUMN_NAME,
ccu.TABLE_NAME AS REFERENCED_TABLE,
@@ -375,14 +385,18 @@ def register_tools(
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
ON rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
WHERE kcu.TABLE_NAME = ?
""", table_name)
""",
table_name,
)
foreign_keys = []
for row in cursor.fetchall():
foreign_keys.append({
"column": row[0],
"references": f"{row[1]}({row[2]})",
})
foreign_keys.append(
{
"column": row[0],
"references": f"{row[1]}({row[2]})",
}
)
result = {
"table": table_name,
@@ -393,7 +407,8 @@ def register_tools(
# Optionally include indexes
if include_indexes:
cursor.execute("""
cursor.execute(
"""
SELECT
i.name AS INDEX_NAME,
i.type_desc AS INDEX_TYPE,
@@ -402,7 +417,9 @@ def register_tools(
JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE i.object_id = OBJECT_ID(?)
ORDER BY i.name, ic.key_ordinal
""", table_name)
""",
table_name,
)
indexes = {}
for row in cursor.fetchall():
@@ -489,10 +506,12 @@ def register_tools(
row_dict[column] = value
rows.append(row_dict)
result_sets.append({
"columns": columns,
"rows": rows,
})
result_sets.append(
{
"columns": columns,
"rows": rows,
}
)
if not cursor.nextset():
break
@@ -38,9 +38,7 @@ def _headers(token: str) -> dict[str, str]:
}
def _request(
method: str, path: str, token: str, **kwargs: Any
) -> dict[str, Any]:
def _request(method: str, path: str, token: str, **kwargs: Any) -> dict[str, Any]:
"""Make a request to the Notion API."""
try:
resp = getattr(httpx, method)(
@@ -130,14 +128,16 @@ def register_tools(
elif obj_type == "database":
title_parts = item.get("title", [])
title = "".join(p.get("text", {}).get("content", "") for p in title_parts)
results.append({
"id": item.get("id", ""),
"object": obj_type,
"title": title,
"url": item.get("url", ""),
"created_time": item.get("created_time", ""),
"last_edited_time": item.get("last_edited_time", ""),
})
results.append(
{
"id": item.get("id", ""),
"object": obj_type,
"title": title,
"url": item.get("url", ""),
"created_time": item.get("created_time", ""),
"last_edited_time": item.get("last_edited_time", ""),
}
)
return {"results": results, "count": len(results), "has_more": data.get("has_more", False)}
@mcp.tool()
@@ -245,9 +245,7 @@ def register_tools(
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{"type": "text", "text": {"content": content}}]
},
"paragraph": {"rich_text": [{"type": "text", "text": {"content": content}}]},
}
]
@@ -303,13 +301,15 @@ def register_tools(
pages = []
for item in data.get("results", []):
title = _extract_title(item.get("properties", {}))
pages.append({
"id": item.get("id", ""),
"title": title,
"url": item.get("url", ""),
"created_time": item.get("created_time", ""),
"last_edited_time": item.get("last_edited_time", ""),
})
pages.append(
{
"id": item.get("id", ""),
"title": title,
"url": item.get("url", ""),
"created_time": item.get("created_time", ""),
"last_edited_time": item.get("last_edited_time", ""),
}
)
return {"pages": pages, "count": len(pages), "has_more": data.get("has_more", False)}
@mcp.tool()
@@ -68,10 +68,7 @@ def _extract_incident(inc: dict) -> dict:
"html_url": inc.get("html_url"),
"service": inc.get("service", {}).get("summary"),
"service_id": inc.get("service", {}).get("id"),
"assignments": [
a.get("assignee", {}).get("summary")
for a in inc.get("assignments", [])
],
"assignments": [a.get("assignee", {}).get("summary") for a in inc.get("assignments", [])],
}
@@ -99,7 +96,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "PAGERDUTY_API_KEY is required", "help": "Set PAGERDUTY_API_KEY environment variable"}
return {
"error": "PAGERDUTY_API_KEY is required",
"help": "Set PAGERDUTY_API_KEY environment variable",
}
params: dict[str, Any] = {"limit": min(limit, 100)}
if status:
@@ -135,7 +135,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "PAGERDUTY_API_KEY is required", "help": "Set PAGERDUTY_API_KEY environment variable"}
return {
"error": "PAGERDUTY_API_KEY is required",
"help": "Set PAGERDUTY_API_KEY environment variable",
}
if not incident_id:
return {"error": "incident_id is required"}
@@ -167,7 +170,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers(write=True)
if headers is None:
return {"error": "PAGERDUTY_API_KEY is required", "help": "Set PAGERDUTY_API_KEY environment variable"}
return {
"error": "PAGERDUTY_API_KEY is required",
"help": "Set PAGERDUTY_API_KEY environment variable",
}
if not title or not service_id:
return {"error": "title and service_id are required"}
@@ -204,7 +210,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers(write=True)
if headers is None:
return {"error": "PAGERDUTY_API_KEY is required", "help": "Set PAGERDUTY_API_KEY environment variable"}
return {
"error": "PAGERDUTY_API_KEY is required",
"help": "Set PAGERDUTY_API_KEY environment variable",
}
if not incident_id:
return {"error": "incident_id is required"}
if not status:
@@ -237,7 +246,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "PAGERDUTY_API_KEY is required", "help": "Set PAGERDUTY_API_KEY environment variable"}
return {
"error": "PAGERDUTY_API_KEY is required",
"help": "Set PAGERDUTY_API_KEY environment variable",
}
params: dict[str, Any] = {"limit": min(limit, 100)}
if query:
@@ -119,15 +119,17 @@ def register_tools(
indexes = []
for idx in data.get("indexes", []):
indexes.append({
"name": idx.get("name", ""),
"dimension": idx.get("dimension", 0),
"metric": idx.get("metric", ""),
"host": idx.get("host", ""),
"vector_type": idx.get("vector_type", "dense"),
"state": (idx.get("status") or {}).get("state", ""),
"ready": (idx.get("status") or {}).get("ready", False),
})
indexes.append(
{
"name": idx.get("name", ""),
"dimension": idx.get("dimension", 0),
"metric": idx.get("metric", ""),
"host": idx.get("host", ""),
"vector_type": idx.get("vector_type", "dense"),
"state": (idx.get("status") or {}).get("state", ""),
"ready": (idx.get("status") or {}).get("ready", False),
}
)
return {"indexes": indexes, "count": len(indexes)}
@mcp.tool()
@@ -157,17 +157,19 @@ def register_tools(
deals = []
for d in data.get("data") or []:
deals.append({
"id": d.get("id"),
"title": d.get("title", ""),
"value": d.get("value", 0),
"currency": d.get("currency", ""),
"status": d.get("status", ""),
"person_name": (d.get("person_id") or {}).get("name", ""),
"org_name": (d.get("org_id") or {}).get("name", ""),
"stage_id": d.get("stage_id"),
"add_time": d.get("add_time", ""),
})
deals.append(
{
"id": d.get("id"),
"title": d.get("title", ""),
"value": d.get("value", 0),
"currency": d.get("currency", ""),
"status": d.get("status", ""),
"person_name": (d.get("person_id") or {}).get("name", ""),
"org_name": (d.get("org_id") or {}).get("name", ""),
"stage_id": d.get("stage_id"),
"add_time": d.get("add_time", ""),
}
)
return {"deals": deals, "count": len(deals)}
@mcp.tool()
@@ -293,14 +295,16 @@ def register_tools(
for p in data.get("data") or []:
emails = p.get("email", [])
phones = p.get("phone", [])
persons.append({
"id": p.get("id"),
"name": p.get("name", ""),
"email": emails[0].get("value", "") if emails else "",
"phone": phones[0].get("value", "") if phones else "",
"org_name": (p.get("org_id") or {}).get("name", ""),
"open_deals_count": p.get("open_deals_count", 0),
})
persons.append(
{
"id": p.get("id"),
"name": p.get("name", ""),
"email": emails[0].get("value", "") if emails else "",
"phone": phones[0].get("value", "") if phones else "",
"org_name": (p.get("org_id") or {}).get("name", ""),
"open_deals_count": p.get("open_deals_count", 0),
}
)
return {"persons": persons, "count": len(persons)}
@mcp.tool()
@@ -336,13 +340,15 @@ def register_tools(
p = item.get("item", {})
emails = p.get("emails", [])
phones = p.get("phones", [])
results.append({
"id": p.get("id"),
"name": p.get("name", ""),
"email": emails[0] if emails else "",
"phone": phones[0] if phones else "",
"org_name": (p.get("organization") or {}).get("name", ""),
})
results.append(
{
"id": p.get("id"),
"name": p.get("name", ""),
"email": emails[0] if emails else "",
"phone": phones[0] if phones else "",
"org_name": (p.get("organization") or {}).get("name", ""),
}
)
return {"query": query, "results": results}
# ── Organizations ────────────────────────────────────────────
@@ -375,13 +381,15 @@ def register_tools(
orgs = []
for o in data.get("data") or []:
orgs.append({
"id": o.get("id"),
"name": o.get("name", ""),
"address": o.get("address", ""),
"open_deals_count": o.get("open_deals_count", 0),
"people_count": o.get("people_count", 0),
})
orgs.append(
{
"id": o.get("id"),
"name": o.get("name", ""),
"address": o.get("address", ""),
"open_deals_count": o.get("open_deals_count", 0),
"people_count": o.get("people_count", 0),
}
)
return {"organizations": orgs, "count": len(orgs)}
# ── Activities ───────────────────────────────────────────────
@@ -426,18 +434,20 @@ def register_tools(
activities = []
for a in data.get("data") or []:
activities.append({
"id": a.get("id"),
"subject": a.get("subject", ""),
"type": a.get("type", ""),
"done": a.get("done", False),
"due_date": a.get("due_date", ""),
"due_time": a.get("due_time", ""),
"deal_title": a.get("deal_title", ""),
"person_name": a.get("person_name", ""),
"org_name": a.get("org_name", ""),
"note": a.get("note", "")[:200] if a.get("note") else "",
})
activities.append(
{
"id": a.get("id"),
"subject": a.get("subject", ""),
"type": a.get("type", ""),
"done": a.get("done", False),
"due_date": a.get("due_date", ""),
"due_time": a.get("due_time", ""),
"deal_title": a.get("deal_title", ""),
"person_name": a.get("person_name", ""),
"org_name": a.get("org_name", ""),
"note": a.get("note", "")[:200] if a.get("note") else "",
}
)
return {"activities": activities, "count": len(activities)}
# ── Pipelines ────────────────────────────────────────────────
@@ -462,13 +472,15 @@ def register_tools(
pipelines = []
for p in data.get("data") or []:
pipelines.append({
"id": p.get("id"),
"name": p.get("name", ""),
"active": p.get("active", False),
"deal_probability": p.get("deal_probability", False),
"order_nr": p.get("order_nr", 0),
})
pipelines.append(
{
"id": p.get("id"),
"name": p.get("name", ""),
"active": p.get("active", False),
"deal_probability": p.get("deal_probability", False),
"order_nr": p.get("order_nr", 0),
}
)
return {"pipelines": pipelines}
@mcp.tool()
@@ -498,13 +510,15 @@ def register_tools(
stages = []
for s in data.get("data") or []:
stages.append({
"id": s.get("id"),
"name": s.get("name", ""),
"pipeline_id": s.get("pipeline_id"),
"order_nr": s.get("order_nr", 0),
"active_flag": s.get("active_flag", True),
})
stages.append(
{
"id": s.get("id"),
"name": s.get("name", ""),
"pipeline_id": s.get("pipeline_id"),
"order_nr": s.get("order_nr", 0),
"active_flag": s.get("active_flag", True),
}
)
return {"stages": stages}
# ── Notes ────────────────────────────────────────────────────
@@ -41,7 +41,9 @@ def _get_env() -> str:
return os.getenv("PLAID_ENV", DEFAULT_ENV)
def _post(path: str, client_id: str, secret: str, body: dict[str, Any] | None = None) -> dict[str, Any]:
def _post(
path: str, client_id: str, secret: str, body: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Make a POST request to the Plaid API."""
env = _get_env()
base = BASE_URLS.get(env, BASE_URLS["sandbox"])
@@ -101,17 +103,19 @@ def register_tools(
accounts = []
for a in data.get("accounts", []):
bal = a.get("balances") or {}
accounts.append({
"account_id": a.get("account_id", ""),
"name": a.get("name", ""),
"official_name": a.get("official_name", ""),
"type": a.get("type", ""),
"subtype": a.get("subtype", ""),
"mask": a.get("mask", ""),
"available_balance": bal.get("available"),
"current_balance": bal.get("current"),
"currency": bal.get("iso_currency_code", ""),
})
accounts.append(
{
"account_id": a.get("account_id", ""),
"name": a.get("name", ""),
"official_name": a.get("official_name", ""),
"type": a.get("type", ""),
"subtype": a.get("subtype", ""),
"mask": a.get("mask", ""),
"available_balance": bal.get("available"),
"current_balance": bal.get("current"),
"currency": bal.get("iso_currency_code", ""),
}
)
return {"accounts": accounts, "count": len(accounts)}
@mcp.tool()
@@ -138,15 +142,17 @@ def register_tools(
accounts = []
for a in data.get("accounts", []):
bal = a.get("balances") or {}
accounts.append({
"account_id": a.get("account_id", ""),
"name": a.get("name", ""),
"type": a.get("type", ""),
"available": bal.get("available"),
"current": bal.get("current"),
"limit": bal.get("limit"),
"currency": bal.get("iso_currency_code", ""),
})
accounts.append(
{
"account_id": a.get("account_id", ""),
"name": a.get("name", ""),
"type": a.get("type", ""),
"available": bal.get("available"),
"current": bal.get("current"),
"limit": bal.get("limit"),
"currency": bal.get("iso_currency_code", ""),
}
)
return {"accounts": accounts}
@mcp.tool()
@@ -250,17 +256,19 @@ def register_tools(
txns = []
for t in data.get("transactions", []):
txns.append({
"transaction_id": t.get("transaction_id", ""),
"account_id": t.get("account_id", ""),
"amount": t.get("amount", 0),
"date": t.get("date", ""),
"name": t.get("name", ""),
"merchant_name": t.get("merchant_name", ""),
"category": t.get("category", []),
"pending": t.get("pending", False),
"currency": t.get("iso_currency_code", ""),
})
txns.append(
{
"transaction_id": t.get("transaction_id", ""),
"account_id": t.get("account_id", ""),
"amount": t.get("amount", 0),
"date": t.get("date", ""),
"name": t.get("name", ""),
"merchant_name": t.get("merchant_name", ""),
"category": t.get("category", []),
"pending": t.get("pending", False),
"currency": t.get("iso_currency_code", ""),
}
)
return {
"transactions": txns,
@@ -347,12 +355,14 @@ def register_tools(
institutions = []
for inst in data.get("institutions", []):
institutions.append({
"institution_id": inst.get("institution_id", ""),
"name": inst.get("name", ""),
"products": inst.get("products", []),
"country_codes": inst.get("country_codes", []),
"url": inst.get("url", ""),
"oauth": inst.get("oauth", False),
})
institutions.append(
{
"institution_id": inst.get("institution_id", ""),
"name": inst.get("name", ""),
"products": inst.get("products", []),
"country_codes": inst.get("country_codes", []),
"url": inst.get("url", ""),
"oauth": inst.get("oauth", False),
}
)
return {"institutions": institutions, "count": len(institutions)}
@@ -61,7 +61,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "POWERBI_ACCESS_TOKEN is required", "help": "Set POWERBI_ACCESS_TOKEN environment variable"}
return {
"error": "POWERBI_ACCESS_TOKEN is required",
"help": "Set POWERBI_ACCESS_TOKEN environment variable",
}
params: dict[str, Any] = {"$top": top, "$skip": skip}
if search:
@@ -94,7 +97,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "POWERBI_ACCESS_TOKEN is required", "help": "Set POWERBI_ACCESS_TOKEN environment variable"}
return {
"error": "POWERBI_ACCESS_TOKEN is required",
"help": "Set POWERBI_ACCESS_TOKEN environment variable",
}
if not workspace_id:
return {"error": "workspace_id is required"}
@@ -128,7 +134,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "POWERBI_ACCESS_TOKEN is required", "help": "Set POWERBI_ACCESS_TOKEN environment variable"}
return {
"error": "POWERBI_ACCESS_TOKEN is required",
"help": "Set POWERBI_ACCESS_TOKEN environment variable",
}
if not workspace_id:
return {"error": "workspace_id is required"}
@@ -167,7 +176,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "POWERBI_ACCESS_TOKEN is required", "help": "Set POWERBI_ACCESS_TOKEN environment variable"}
return {
"error": "POWERBI_ACCESS_TOKEN is required",
"help": "Set POWERBI_ACCESS_TOKEN environment variable",
}
if not workspace_id or not dataset_id:
return {"error": "workspace_id and dataset_id are required"}
@@ -194,7 +206,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if not headers:
return {"error": "POWERBI_ACCESS_TOKEN is required", "help": "Set POWERBI_ACCESS_TOKEN environment variable"}
return {
"error": "POWERBI_ACCESS_TOKEN is required",
"help": "Set POWERBI_ACCESS_TOKEN environment variable",
}
if not workspace_id or not dataset_id:
return {"error": "workspace_id and dataset_id are required"}
@@ -113,7 +113,9 @@ def register_tools(
result = resp.json()
if result.get("status") != 1:
errors = result.get("errors", [])
return {"error": f"Pushover error: {', '.join(errors) if errors else resp.text[:300]}"}
return {
"error": f"Pushover error: {', '.join(errors) if errors else resp.text[:300]}"
}
out: dict[str, Any] = {"status": "sent", "request": result.get("request", "")}
if "receipt" in result:
out["receipt"] = result["receipt"]
@@ -1,4 +1,5 @@
"""Tests for Pushover tool."""
from unittest.mock import MagicMock, patch
from aden_tools.tools.pushover_tool.pushover_tool import (
@@ -84,9 +85,7 @@ class TestPushoverClient:
@patch("aden_tools.tools.pushover_tool.pushover_tool.httpx.post")
def test_validate_user_with_device(self, mock_post):
mock_post.return_value = self._mock_response(
json_data={"status": 1, "devices": ["iphone"]}
)
mock_post.return_value = self._mock_response(json_data={"status": 1, "devices": ["iphone"]})
result = self.client.validate_user(device="iphone")
call_kwargs = mock_post.call_args[1]["data"]
assert call_kwargs["device"] == "iphone"
@@ -103,6 +102,7 @@ class TestRegisterTools:
def decorator(func):
self.tools[func.__name__] = func
return func
return decorator
self.mcp.tool = tool_decorator
@@ -127,9 +127,7 @@ class TestRegisterTools:
{"PUSHOVER_API_TOKEN": "test_token", "PUSHOVER_USER_KEY": "test_user"},
)
def test_pushover_send_notification_invalid_priority(self):
result = self.tools["pushover_send_notification"](
message="Hello!", priority=99
)
result = self.tools["pushover_send_notification"](message="Hello!", priority=99)
assert "error" in result
assert "priority" in result["error"]
@@ -22,7 +22,10 @@ def _get_config() -> tuple[str, str] | dict:
token = os.getenv("QUICKBOOKS_ACCESS_TOKEN", "")
realm_id = os.getenv("QUICKBOOKS_REALM_ID", "")
if not token or not realm_id:
return {"error": "QUICKBOOKS_ACCESS_TOKEN and QUICKBOOKS_REALM_ID are required", "help": "Set QUICKBOOKS_ACCESS_TOKEN and QUICKBOOKS_REALM_ID environment variables"}
return {
"error": "QUICKBOOKS_ACCESS_TOKEN and QUICKBOOKS_REALM_ID are required",
"help": "Set QUICKBOOKS_ACCESS_TOKEN and QUICKBOOKS_REALM_ID environment variables",
}
use_sandbox = os.getenv("QUICKBOOKS_SANDBOX", "").lower() in ("1", "true")
base = SANDBOX_URL if use_sandbox else PROD_URL
@@ -245,6 +248,8 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"company_name": info.get("CompanyName"),
"legal_name": info.get("LegalName"),
"country": info.get("Country"),
"email": info.get("Email", {}).get("Address") if isinstance(info.get("Email"), dict) else None,
"email": info.get("Email", {}).get("Address")
if isinstance(info.get("Email"), dict)
else None,
"fiscal_year_start": info.get("FiscalYearStartMonth"),
}
@@ -87,19 +87,21 @@ def _extract_posts(listing: dict) -> list[dict[str, Any]]:
if child.get("kind") != "t3":
continue
d = child.get("data", {})
posts.append({
"id": d.get("id", ""),
"title": d.get("title", ""),
"author": d.get("author", ""),
"subreddit": d.get("subreddit", ""),
"score": d.get("score", 0),
"num_comments": d.get("num_comments", 0),
"url": d.get("url", ""),
"permalink": d.get("permalink", ""),
"selftext": (d.get("selftext", "") or "")[:500],
"created_utc": d.get("created_utc", 0),
"is_self": d.get("is_self", False),
})
posts.append(
{
"id": d.get("id", ""),
"title": d.get("title", ""),
"author": d.get("author", ""),
"subreddit": d.get("subreddit", ""),
"score": d.get("score", 0),
"num_comments": d.get("num_comments", 0),
"url": d.get("url", ""),
"permalink": d.get("permalink", ""),
"selftext": (d.get("selftext", "") or "")[:500],
"created_utc": d.get("created_utc", 0),
"is_self": d.get("is_self", False),
}
)
return posts
@@ -260,13 +262,15 @@ def register_tools(
if child.get("kind") != "t1":
continue
cd = child.get("data", {})
comments.append({
"id": cd.get("id", ""),
"author": cd.get("author", ""),
"body": (cd.get("body", "") or "")[:500],
"score": cd.get("score", 0),
"created_utc": cd.get("created_utc", 0),
})
comments.append(
{
"id": cd.get("id", ""),
"author": cd.get("author", ""),
"body": (cd.get("body", "") or "")[:500],
"score": cd.get("score", 0),
"created_utc": cd.get("created_utc", 0),
}
)
return {"post": post, "comments": comments, "comment_count": len(comments)}
@@ -25,7 +25,10 @@ def _get_config() -> tuple[str, str, str] | dict:
secret_key = os.getenv("AWS_SECRET_ACCESS_KEY", "")
region = os.getenv("AWS_REGION", "us-east-1")
if not access_key or not secret_key:
return {"error": "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required", "help": "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables"}
return {
"error": "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required",
"help": "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables",
}
return access_key, secret_key, region
@@ -62,22 +65,16 @@ def _api_call(
"x-amz-target": f"RedshiftData.{action}",
}
signed_headers_str = ";".join(sorted(headers_to_sign.keys()))
canonical_headers = "".join(
f"{k}:{v}\n" for k, v in sorted(headers_to_sign.items())
)
canonical_headers = "".join(f"{k}:{v}\n" for k, v in sorted(headers_to_sign.items()))
canonical_request = (
f"POST\n/\n\n{canonical_headers}\n{signed_headers_str}\n{payload_hash}"
)
canonical_request = f"POST\n/\n\n{canonical_headers}\n{signed_headers_str}\n{payload_hash}"
credential_scope = f"{datestamp}/{region}/{SERVICE}/aws4_request"
string_to_sign = (
f"AWS4-HMAC-SHA256\n{amz_date}\n{credential_scope}\n"
+ hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
)
signing_key = _get_signing_key(secret_key, datestamp, region)
signature = hmac.new(
signing_key, string_to_sign.encode("utf-8"), hashlib.sha256
).hexdigest()
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
auth_header = (
f"AWS4-HMAC-SHA256 Credential={access_key}/{credential_scope}, "
@@ -172,9 +169,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
if not statement_id:
return {"error": "statement_id is required"}
data = _api_call(
"DescribeStatement", {"Id": statement_id}, access_key, secret_key, region
)
data = _api_call("DescribeStatement", {"Id": statement_id}, access_key, secret_key, region)
if "error" in data:
return data
@@ -202,9 +197,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
if not statement_id:
return {"error": "statement_id is required"}
data = _api_call(
"GetStatementResult", {"Id": statement_id}, access_key, secret_key, region
)
data = _api_call("GetStatementResult", {"Id": statement_id}, access_key, secret_key, region)
if "error" in data:
return data
@@ -162,16 +162,11 @@ def register_tools(
return {"error": "object_type and record_id are required"}
try:
url = (
f"{instance_url}/services/data/{API_VERSION}"
f"/sobjects/{object_type}/{record_id}"
)
url = f"{instance_url}/services/data/{API_VERSION}/sobjects/{object_type}/{record_id}"
params = {}
if fields:
params["fields"] = fields
resp = httpx.get(
url, headers=_headers(token), params=params, timeout=30.0
)
resp = httpx.get(url, headers=_headers(token), params=params, timeout=30.0)
return _handle_response(resp)
except httpx.TimeoutException:
return {"error": "Request timed out"}
@@ -204,13 +199,8 @@ def register_tools(
return {"error": "fields dict is required"}
try:
url = (
f"{instance_url}/services/data/{API_VERSION}"
f"/sobjects/{object_type}"
)
resp = httpx.post(
url, headers=_headers(token), json=fields, timeout=30.0
)
url = f"{instance_url}/services/data/{API_VERSION}/sobjects/{object_type}"
resp = httpx.post(url, headers=_headers(token), json=fields, timeout=30.0)
return _handle_response(resp)
except httpx.TimeoutException:
return {"error": "Request timed out"}
@@ -245,13 +235,8 @@ def register_tools(
return {"error": "fields dict is required"}
try:
url = (
f"{instance_url}/services/data/{API_VERSION}"
f"/sobjects/{object_type}/{record_id}"
)
resp = httpx.patch(
url, headers=_headers(token), json=fields, timeout=30.0
)
url = f"{instance_url}/services/data/{API_VERSION}/sobjects/{object_type}/{record_id}"
resp = httpx.patch(url, headers=_headers(token), json=fields, timeout=30.0)
return _handle_response(resp)
except httpx.TimeoutException:
return {"error": "Request timed out"}
@@ -280,10 +265,7 @@ def register_tools(
return {"error": "object_type is required"}
try:
url = (
f"{instance_url}/services/data/{API_VERSION}"
f"/sobjects/{object_type}/describe"
)
url = f"{instance_url}/services/data/{API_VERSION}/sobjects/{object_type}/describe"
resp = httpx.get(url, headers=_headers(token), timeout=30.0)
result = _handle_response(resp)
if "error" in result:
@@ -296,14 +278,11 @@ def register_tools(
"name": f.get("name"),
"label": f.get("label"),
"type": f.get("type"),
"required": not f.get("nillable", True)
and f.get("createable", False),
"required": not f.get("nillable", True) and f.get("createable", False),
}
if f.get("picklistValues"):
entry["picklist_values"] = [
pv["value"]
for pv in f["picklistValues"]
if pv.get("active")
pv["value"] for pv in f["picklistValues"] if pv.get("active")
]
fields_summary.append(entry)
@@ -20,7 +20,10 @@ def _get_config() -> tuple[str, dict] | dict:
username = os.getenv("SAP_USERNAME", "")
password = os.getenv("SAP_PASSWORD", "")
if not base_url or not username or not password:
return {"error": "SAP_BASE_URL, SAP_USERNAME, and SAP_PASSWORD are required", "help": "Set SAP_BASE_URL, SAP_USERNAME, and SAP_PASSWORD environment variables"}
return {
"error": "SAP_BASE_URL, SAP_USERNAME, and SAP_PASSWORD are required",
"help": "Set SAP_BASE_URL, SAP_USERNAME, and SAP_PASSWORD environment variables",
}
creds = base64.b64encode(f"{username}:{password}".encode()).decode()
headers = {"Authorization": f"Basic {creds}", "Accept": "application/json"}
return base_url, headers
@@ -19,16 +19,17 @@ def _get_config() -> tuple[str, dict] | dict:
account = os.getenv("SNOWFLAKE_ACCOUNT", "").strip()
token = os.getenv("SNOWFLAKE_TOKEN", "").strip()
if not account or not token:
return {"error": "SNOWFLAKE_ACCOUNT and SNOWFLAKE_TOKEN are required", "help": "Set SNOWFLAKE_ACCOUNT and SNOWFLAKE_TOKEN environment variables"}
return {
"error": "SNOWFLAKE_ACCOUNT and SNOWFLAKE_TOKEN are required",
"help": "Set SNOWFLAKE_ACCOUNT and SNOWFLAKE_TOKEN environment variables",
}
base_url = f"https://{account}.snowflakecomputing.com/api/v2/statements"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "aden-tools/1.0",
"X-Snowflake-Authorization-Token-Type": os.getenv(
"SNOWFLAKE_TOKEN_TYPE", "OAUTH"
),
"X-Snowflake-Authorization-Token-Type": os.getenv("SNOWFLAKE_TOKEN_TYPE", "OAUTH"),
}
return base_url, headers
@@ -148,9 +149,7 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
if not statement_handle:
return {"error": "statement_handle is required"}
resp = httpx.post(
f"{base_url}/{statement_handle}/cancel", headers=headers, timeout=30
)
resp = httpx.post(f"{base_url}/{statement_handle}/cancel", headers=headers, timeout=30)
if resp.status_code == 200:
return {"result": "cancelled", "statement_handle": statement_handle}
return {"error": f"HTTP {resp.status_code}: {resp.text[:500]}"}
@@ -393,7 +393,10 @@ def register_tools(
response_data = resp.text
if resp.status_code >= 400:
return {"error": f"Edge function error {resp.status_code}", "response": response_data}
return {
"error": f"Edge function error {resp.status_code}",
"response": response_data,
}
return {"status_code": resp.status_code, "response": response_data}
except httpx.TimeoutException:
return {"error": "Edge function invocation timed out"}
@@ -18,7 +18,10 @@ def _get_config() -> tuple[str, dict] | dict:
domain = os.getenv("TINES_DOMAIN", "").rstrip("/")
api_key = os.getenv("TINES_API_KEY", "")
if not domain or not api_key:
return {"error": "TINES_DOMAIN and TINES_API_KEY are required", "help": "Set TINES_DOMAIN and TINES_API_KEY environment variables"}
return {
"error": "TINES_DOMAIN and TINES_API_KEY are required",
"help": "Set TINES_DOMAIN and TINES_API_KEY environment variables",
}
base_url = f"https://{domain}/api/v1"
headers = {
"Authorization": f"Bearer {api_key}",
@@ -120,7 +120,10 @@ def register_tools(
url = f"{_base_url(sid)}/Messages.json"
data = _request(
"post", url, sid, token,
"post",
url,
sid,
token,
data={"To": to, "From": from_number, "Body": body},
)
if "error" in data:
@@ -156,7 +159,10 @@ def register_tools(
url = f"{_base_url(sid)}/Messages.json"
data = _request(
"post", url, sid, token,
"post",
url,
sid,
token,
data={"To": wa_to, "From": wa_from, "Body": body},
)
if "error" in data:
@@ -68,7 +68,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "X_BEARER_TOKEN is required", "help": "Set X_BEARER_TOKEN environment variable"}
return {
"error": "X_BEARER_TOKEN is required",
"help": "Set X_BEARER_TOKEN environment variable",
}
if not query:
return {"error": "query is required"}
@@ -114,7 +117,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "X_BEARER_TOKEN is required", "help": "Set X_BEARER_TOKEN environment variable"}
return {
"error": "X_BEARER_TOKEN is required",
"help": "Set X_BEARER_TOKEN environment variable",
}
if not username:
return {"error": "username is required"}
@@ -155,7 +161,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "X_BEARER_TOKEN is required", "help": "Set X_BEARER_TOKEN environment variable"}
return {
"error": "X_BEARER_TOKEN is required",
"help": "Set X_BEARER_TOKEN environment variable",
}
if not user_id:
return {"error": "user_id is required"}
@@ -187,7 +196,10 @@ def register_tools(mcp: FastMCP, credentials: Any = None) -> None:
"""
headers = _get_headers()
if headers is None:
return {"error": "X_BEARER_TOKEN is required", "help": "Set X_BEARER_TOKEN environment variable"}
return {
"error": "X_BEARER_TOKEN is required",
"help": "Set X_BEARER_TOKEN environment variable",
}
if not tweet_id:
return {"error": "tweet_id is required"}
@@ -37,7 +37,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{VERCEL_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{VERCEL_API}/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your VERCEL_TOKEN."}
if resp.status_code == 403:
@@ -53,7 +55,9 @@ def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any
def _post(endpoint: str, token: str, body: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.post(f"{VERCEL_API}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0)
resp = httpx.post(
f"{VERCEL_API}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your VERCEL_TOKEN."}
if resp.status_code not in (200, 201):
@@ -76,7 +80,10 @@ def _delete(endpoint: str, token: str) -> dict[str, Any]:
def _auth_error() -> dict[str, Any]:
return {"error": "VERCEL_TOKEN not set", "help": "Get a token at https://vercel.com/account/tokens"}
return {
"error": "VERCEL_TOKEN not set",
"help": "Get a token at https://vercel.com/account/tokens",
}
def register_tools(
@@ -118,14 +125,16 @@ def register_tools(
deployments = []
for d in data.get("deployments", []):
deployments.append({
"uid": d.get("uid", ""),
"name": d.get("name", ""),
"url": d.get("url", ""),
"state": d.get("state", ""),
"created": d.get("created", 0),
"target": d.get("target", ""),
})
deployments.append(
{
"uid": d.get("uid", ""),
"name": d.get("name", ""),
"url": d.get("url", ""),
"state": d.get("state", ""),
"created": d.get("created", 0),
"target": d.get("target", ""),
}
)
return {"deployments": deployments}
@mcp.tool()
@@ -186,13 +195,15 @@ def register_tools(
for p in data.get("projects", []):
latest = p.get("latestDeployments", [{}])
latest_url = latest[0].get("url", "") if latest else ""
projects.append({
"id": p.get("id", ""),
"name": p.get("name", ""),
"framework": p.get("framework", ""),
"updatedAt": p.get("updatedAt", 0),
"latestDeploymentUrl": latest_url,
})
projects.append(
{
"id": p.get("id", ""),
"name": p.get("name", ""),
"framework": p.get("framework", ""),
"updatedAt": p.get("updatedAt", 0),
"latestDeploymentUrl": latest_url,
}
)
return {"projects": projects}
@mcp.tool()
@@ -249,12 +260,14 @@ def register_tools(
domains = []
for d in data.get("domains", []):
domains.append({
"name": d.get("name", ""),
"redirect": d.get("redirect", ""),
"gitBranch": d.get("gitBranch", ""),
"verified": d.get("verified", False),
})
domains.append(
{
"name": d.get("name", ""),
"redirect": d.get("redirect", ""),
"gitBranch": d.get("gitBranch", ""),
"verified": d.get("verified", False),
}
)
return {"project_id": project_id, "domains": domains}
# ── Environment Variables ───────────────────────────────────
@@ -282,12 +295,14 @@ def register_tools(
env_vars = []
for e in data.get("envs", []):
env_vars.append({
"id": e.get("id", ""),
"key": e.get("key", ""),
"target": e.get("target", []),
"type": e.get("type", ""),
})
env_vars.append(
{
"id": e.get("id", ""),
"key": e.get("key", ""),
"target": e.get("target", []),
"type": e.get("type", ""),
}
)
return {"project_id": project_id, "env_vars": env_vars}
@mcp.tool()
@@ -21,6 +21,7 @@ from fastmcp import FastMCP
def _get_ticker(symbol: str) -> Any:
"""Lazily import yfinance and create a Ticker object."""
import yfinance as yf
return yf.Ticker(symbol)
@@ -96,14 +97,16 @@ def register_tools(mcp: FastMCP) -> None:
data = []
for idx, row in hist.iterrows():
data.append({
"date": str(idx.date()) if hasattr(idx, "date") else str(idx),
"open": round(row.get("Open", 0), 2),
"high": round(row.get("High", 0), 2),
"low": round(row.get("Low", 0), 2),
"close": round(row.get("Close", 0), 2),
"volume": int(row.get("Volume", 0)),
})
data.append(
{
"date": str(idx.date()) if hasattr(idx, "date") else str(idx),
"open": round(row.get("Open", 0), 2),
"high": round(row.get("High", 0), 2),
"low": round(row.get("Low", 0), 2),
"close": round(row.get("Close", 0), 2),
"volume": int(row.get("Volume", 0)),
}
)
return {"symbol": symbol.upper(), "period": period, "interval": interval, "data": data}
except Exception as e:
return {"error": f"Failed to fetch history for {symbol}: {e!s}"}
@@ -136,7 +139,9 @@ def register_tools(mcp: FastMCP) -> None:
elif statement == "cashflow":
df = ticker.cashflow
else:
return {"error": f"Invalid statement type: {statement}. Use: income, balance, cashflow"}
return {
"error": f"Invalid statement type: {statement}. Use: income, balance, cashflow"
}
if df is None or df.empty:
return {"error": f"No {statement} statement data for '{symbol}'"}
@@ -147,7 +152,9 @@ def register_tools(mcp: FastMCP) -> None:
period_data = {}
for idx, val in df[col].items():
if val is not None and str(val) != "nan":
period_data[str(idx)] = float(val) if isinstance(val, (int, float)) else str(val)
period_data[str(idx)] = (
float(val) if isinstance(val, (int, float)) else str(val)
)
result[str(col.date()) if hasattr(col, "date") else str(col)] = period_data
return {"symbol": symbol.upper(), "statement": statement, "data": result}
@@ -210,17 +217,20 @@ def register_tools(mcp: FastMCP) -> None:
try:
import yfinance as yf
search = yf.Search(query)
quotes = search.quotes if hasattr(search, "quotes") else []
results = []
for q in quotes[:20]:
results.append({
"symbol": q.get("symbol", ""),
"name": q.get("shortname", q.get("longname", "")),
"exchange": q.get("exchange", ""),
"type": q.get("quoteType", ""),
})
results.append(
{
"symbol": q.get("symbol", ""),
"name": q.get("shortname", q.get("longname", "")),
"exchange": q.get("exchange", ""),
"type": q.get("quoteType", ""),
}
)
return {"query": query, "results": results}
except Exception as e:
return {"error": f"Search failed: {e!s}"}
@@ -45,7 +45,9 @@ def _request(
if errors:
reason = errors[0].get("reason", "")
if reason == "quotaExceeded":
return {"error": "YouTube API quota exceeded. Try again tomorrow or request a quota increase."}
return {
"error": "YouTube API quota exceeded. Try again tomorrow or request a quota increase."
}
return {"error": f"Forbidden: {reason or resp.text}"}
if resp.status_code != 200:
return {"error": f"YouTube API error {resp.status_code}: {resp.text[:500]}"}
@@ -145,15 +147,17 @@ def register_tools(
results = []
for item in data.get("items", []):
snippet = item.get("snippet", {})
results.append({
"videoId": item.get("id", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"channelTitle": snippet.get("channelTitle", ""),
"channelId": snippet.get("channelId", ""),
"publishedAt": snippet.get("publishedAt", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
})
results.append(
{
"videoId": item.get("id", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"channelTitle": snippet.get("channelTitle", ""),
"channelId": snippet.get("channelId", ""),
"publishedAt": snippet.get("publishedAt", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
}
)
return {
"query": query,
"results": results,
@@ -199,22 +203,24 @@ def register_tools(
snippet = item.get("snippet", {})
stats = item.get("statistics", {})
content = item.get("contentDetails", {})
videos.append({
"videoId": item.get("id", ""),
"title": snippet.get("title", ""),
"description": snippet.get("description", ""),
"channelTitle": snippet.get("channelTitle", ""),
"channelId": snippet.get("channelId", ""),
"publishedAt": snippet.get("publishedAt", ""),
"tags": snippet.get("tags", []),
"categoryId": snippet.get("categoryId", ""),
"duration": _parse_duration(content.get("duration", "")),
"duration_raw": content.get("duration", ""),
"viewCount": int(stats.get("viewCount", 0)),
"likeCount": int(stats.get("likeCount", 0)),
"commentCount": int(stats.get("commentCount", 0)),
"thumbnail": snippet.get("thumbnails", {}).get("high", {}).get("url", ""),
})
videos.append(
{
"videoId": item.get("id", ""),
"title": snippet.get("title", ""),
"description": snippet.get("description", ""),
"channelTitle": snippet.get("channelTitle", ""),
"channelId": snippet.get("channelId", ""),
"publishedAt": snippet.get("publishedAt", ""),
"tags": snippet.get("tags", []),
"categoryId": snippet.get("categoryId", ""),
"duration": _parse_duration(content.get("duration", "")),
"duration_raw": content.get("duration", ""),
"viewCount": int(stats.get("viewCount", 0)),
"likeCount": int(stats.get("likeCount", 0)),
"commentCount": int(stats.get("commentCount", 0)),
"thumbnail": snippet.get("thumbnails", {}).get("high", {}).get("url", ""),
}
)
return {"videos": videos}
@mcp.tool()
@@ -273,7 +279,9 @@ def register_tools(
"videoCount": int(stats.get("videoCount", 0)),
"viewCount": int(stats.get("viewCount", 0)),
"thumbnail": snippet.get("thumbnails", {}).get("high", {}).get("url", ""),
"uploadsPlaylistId": item.get("contentDetails", {}).get("relatedPlaylists", {}).get("uploads", ""),
"uploadsPlaylistId": item.get("contentDetails", {})
.get("relatedPlaylists", {})
.get("uploads", ""),
}
@mcp.tool()
@@ -320,13 +328,15 @@ def register_tools(
videos = []
for item in data.get("items", []):
snippet = item.get("snippet", {})
videos.append({
"videoId": item.get("id", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"publishedAt": snippet.get("publishedAt", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
})
videos.append(
{
"videoId": item.get("id", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"publishedAt": snippet.get("publishedAt", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
}
)
return {"channel_id": channel_id, "videos": videos}
@mcp.tool()
@@ -387,13 +397,15 @@ def register_tools(
items = []
for item in items_data.get("items", []):
snippet = item.get("snippet", {})
items.append({
"videoId": snippet.get("resourceId", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"position": snippet.get("position", 0),
"channelTitle": snippet.get("videoOwnerChannelTitle", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
})
items.append(
{
"videoId": snippet.get("resourceId", {}).get("videoId", ""),
"title": snippet.get("title", ""),
"position": snippet.get("position", 0),
"channelTitle": snippet.get("videoOwnerChannelTitle", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
}
)
return {
"playlistId": playlist_id,
@@ -448,12 +460,14 @@ def register_tools(
results = []
for item in data.get("items", []):
snippet = item.get("snippet", {})
results.append({
"channelId": item.get("id", {}).get("channelId", ""),
"title": snippet.get("title", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
})
results.append(
{
"channelId": item.get("id", {}).get("channelId", ""),
"title": snippet.get("title", ""),
"description": snippet.get("description", ""),
"thumbnail": snippet.get("thumbnails", {}).get("medium", {}).get("url", ""),
}
)
return {"query": query, "results": results}
@mcp.tool()
@@ -500,13 +514,15 @@ def register_tools(
comments = []
for item in data.get("items", []):
top = item.get("snippet", {}).get("topLevelComment", {}).get("snippet", {})
comments.append({
"author": top.get("authorDisplayName", ""),
"text": top.get("textDisplay", ""),
"likeCount": top.get("likeCount", 0),
"publishedAt": top.get("publishedAt", ""),
"replyCount": item.get("snippet", {}).get("totalReplyCount", 0),
})
comments.append(
{
"author": top.get("authorDisplayName", ""),
"text": top.get("textDisplay", ""),
"likeCount": top.get("likeCount", 0),
"publishedAt": top.get("publishedAt", ""),
"replyCount": item.get("snippet", {}).get("totalReplyCount", 0),
}
)
return {"video_id": video_id, "comments": comments}
@mcp.tool()
@@ -539,8 +555,10 @@ def register_tools(
categories = []
for item in data.get("items", []):
categories.append({
"id": item.get("id", ""),
"title": item.get("snippet", {}).get("title", ""),
})
categories.append(
{
"id": item.get("id", ""),
"title": item.get("snippet", {}).get("title", ""),
}
)
return {"region_code": region_code, "categories": categories}
@@ -44,7 +44,9 @@ def register_tools(
try:
from youtube_transcript_api import YouTubeTranscriptApi
except ImportError:
return {"error": "youtube-transcript-api package not installed. Run: pip install youtube-transcript-api"}
return {
"error": "youtube-transcript-api package not installed. Run: pip install youtube-transcript-api"
}
try:
ytt_api = YouTubeTranscriptApi()
@@ -85,19 +87,23 @@ def register_tools(
try:
from youtube_transcript_api import YouTubeTranscriptApi
except ImportError:
return {"error": "youtube-transcript-api package not installed. Run: pip install youtube-transcript-api"}
return {
"error": "youtube-transcript-api package not installed. Run: pip install youtube-transcript-api"
}
try:
ytt_api = YouTubeTranscriptApi()
transcript_list = ytt_api.list(video_id)
transcripts = []
for t in transcript_list:
transcripts.append({
"language": t.language,
"language_code": t.language_code,
"is_generated": t.is_generated,
"is_translatable": t.is_translatable,
})
transcripts.append(
{
"language": t.language,
"language_code": t.language_code,
"is_generated": t.is_generated,
"is_translatable": t.is_translatable,
}
)
return {
"video_id": video_id,
"transcripts": transcripts,
@@ -21,7 +21,9 @@ if TYPE_CHECKING:
from aden_tools.credentials import CredentialStoreAdapter
def _get_credentials(credentials: CredentialStoreAdapter | None) -> tuple[str | None, str | None, str | None]:
def _get_credentials(
credentials: CredentialStoreAdapter | None,
) -> tuple[str | None, str | None, str | None]:
"""Return (subdomain, email, api_token)."""
if credentials is not None:
subdomain = credentials.get("zendesk_subdomain")
@@ -44,9 +46,7 @@ def _auth_header(email: str, token: str) -> str:
return f"Basic {encoded}"
def _request(
method: str, url: str, email: str, token: str, **kwargs: Any
) -> dict[str, Any]:
def _request(method: str, url: str, email: str, token: str, **kwargs: Any) -> dict[str, Any]:
"""Make a request to the Zendesk API."""
headers = kwargs.pop("headers", {})
headers["Authorization"] = _auth_header(email, token)
@@ -286,10 +286,12 @@ def register_tools(
results = []
for r in data.get("results", []):
results.append({
"id": r.get("id"),
"subject": r.get("subject", ""),
"status": r.get("status", ""),
"priority": r.get("priority", ""),
})
results.append(
{
"id": r.get("id"),
"subject": r.get("subject", ""),
"status": r.get("status", ""),
"priority": r.get("priority", ""),
}
)
return {"results": results, "count": data.get("count", len(results))}
@@ -38,7 +38,9 @@ def _headers(token: str) -> dict[str, str]:
def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.get(f"{_base_url()}/{endpoint}", headers=_headers(token), params=params, timeout=30.0)
resp = httpx.get(
f"{_base_url()}/{endpoint}", headers=_headers(token), params=params, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your ZOHO_CRM_ACCESS_TOKEN (may need refresh)."}
if resp.status_code == 204:
@@ -54,7 +56,9 @@ def _get(endpoint: str, token: str, params: dict | None = None) -> dict[str, Any
def _post(endpoint: str, token: str, body: dict | None = None) -> dict[str, Any]:
try:
resp = httpx.post(f"{_base_url()}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0)
resp = httpx.post(
f"{_base_url()}/{endpoint}", headers=_headers(token), json=body or {}, timeout=30.0
)
if resp.status_code == 401:
return {"error": "Unauthorized. Check your ZOHO_CRM_ACCESS_TOKEN."}
if resp.status_code not in (200, 201):
@@ -236,7 +240,9 @@ def register_tools(
if not module:
return {"error": "module is required"}
if not (criteria or email or phone or word):
return {"error": "At least one search parameter is required (criteria, email, phone, or word)"}
return {
"error": "At least one search parameter is required (criteria, email, phone, or word)"
}
params: dict[str, Any] = {
"page": page,
@@ -280,12 +286,14 @@ def register_tools(
modules = []
for m in data.get("modules", []):
modules.append({
"api_name": m.get("api_name", ""),
"module_name": m.get("module_name", ""),
"plural_label": m.get("plural_label", ""),
"editable": m.get("editable", False),
})
modules.append(
{
"api_name": m.get("api_name", ""),
"module_name": m.get("module_name", ""),
"plural_label": m.get("plural_label", ""),
"editable": m.get("editable", False),
}
)
return {"modules": modules}
@mcp.tool()
@@ -34,8 +34,7 @@ def _get_token(
return {
"error": "Zoom credentials not configured",
"help": (
"Set ZOOM_ACCESS_TOKEN environment variable "
"or configure via credential store"
"Set ZOOM_ACCESS_TOKEN environment variable or configure via credential store"
),
}
return token
+28 -21
View File
@@ -59,7 +59,8 @@ def list_all_tables(cursor):
def get_table_schema(cursor, table_name):
"""Get detailed schema for a specific table."""
# Get columns with primary key information
cursor.execute("""
cursor.execute(
"""
SELECT
c.COLUMN_NAME,
c.DATA_TYPE,
@@ -79,7 +80,10 @@ def get_table_schema(cursor, table_name):
) pk ON c.COLUMN_NAME = pk.COLUMN_NAME
WHERE c.TABLE_NAME = ?
ORDER BY c.ORDINAL_POSITION
""", table_name, table_name)
""",
table_name,
table_name,
)
columns = []
for row in cursor.fetchall():
@@ -94,15 +98,18 @@ def get_table_schema(cursor, table_name):
else:
col_type += f"({row[3]})"
columns.append({
"name": row[0],
"type": col_type,
"nullable": row[5] == "YES",
"primary_key": bool(row[6]),
})
columns.append(
{
"name": row[0],
"type": col_type,
"nullable": row[5] == "YES",
"primary_key": bool(row[6]),
}
)
# Get foreign keys
cursor.execute("""
cursor.execute(
"""
SELECT
kcu.COLUMN_NAME,
ccu.TABLE_NAME AS REFERENCED_TABLE,
@@ -113,21 +120,21 @@ def get_table_schema(cursor, table_name):
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
ON rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
WHERE kcu.TABLE_NAME = ?
""", table_name)
""",
table_name,
)
foreign_keys = []
for row in cursor.fetchall():
foreign_keys.append({
"column": row[0],
"references_table": row[1],
"references_column": row[2],
})
foreign_keys.append(
{
"column": row[0],
"references_table": row[1],
"references_column": row[2],
}
)
return {
"table": table_name,
"columns": columns,
"foreign_keys": foreign_keys
}
return {"table": table_name, "columns": columns, "foreign_keys": foreign_keys}
def print_table_schema(schema, is_last=False):
@@ -198,7 +205,7 @@ def main():
for i, table in enumerate(tables):
schema = get_table_schema(cursor, table)
is_last = (i == len(tables) - 1)
is_last = i == len(tables) - 1
print_table_schema(schema, is_last)
# Summary
+40 -11
View File
@@ -47,7 +47,10 @@ class TestAirtableListRecords:
data = {"records": [RECORD_DATA]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_list_records"](base_id="appXXX", table_name="Tasks")
@@ -58,7 +61,10 @@ class TestAirtableListRecords:
data = {"records": [RECORD_DATA], "offset": "itrXXX/recXXX"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_list_records"](base_id="appXXX", table_name="Tasks")
@@ -75,9 +81,14 @@ class TestAirtableGetRecord:
def test_successful_get(self, tool_fns):
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.get", return_value=_mock_resp(RECORD_DATA)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.get",
return_value=_mock_resp(RECORD_DATA),
),
):
result = tool_fns["airtable_get_record"](base_id="appXXX", table_name="Tasks", record_id="recABC123")
result = tool_fns["airtable_get_record"](
base_id="appXXX", table_name="Tasks", record_id="recABC123"
)
assert result["id"] == "recABC123"
assert result["fields"]["Status"] == "Active"
@@ -86,12 +97,16 @@ class TestAirtableGetRecord:
class TestAirtableCreateRecords:
def test_missing_records(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["airtable_create_records"](base_id="appXXX", table_name="Tasks", records="")
result = tool_fns["airtable_create_records"](
base_id="appXXX", table_name="Tasks", records=""
)
assert "error" in result
def test_invalid_json(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["airtable_create_records"](base_id="appXXX", table_name="Tasks", records="not json")
result = tool_fns["airtable_create_records"](
base_id="appXXX", table_name="Tasks", records="not json"
)
assert "error" in result
def test_too_many_records(self, tool_fns):
@@ -99,7 +114,9 @@ class TestAirtableCreateRecords:
records = json.dumps([{"fields": {"Name": f"Item {i}"}} for i in range(11)])
with patch.dict("os.environ", ENV):
result = tool_fns["airtable_create_records"](base_id="appXXX", table_name="Tasks", records=records)
result = tool_fns["airtable_create_records"](
base_id="appXXX", table_name="Tasks", records=records
)
assert "error" in result
assert "10" in result["error"]
@@ -107,7 +124,10 @@ class TestAirtableCreateRecords:
data = {"records": [RECORD_DATA]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_create_records"](
base_id="appXXX",
@@ -126,7 +146,10 @@ class TestAirtableUpdateRecords:
data = {"records": [updated]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.patch", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.patch",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_update_records"](
base_id="appXXX",
@@ -152,7 +175,10 @@ class TestAirtableListBases:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_list_bases"]()
@@ -181,7 +207,10 @@ class TestAirtableGetBaseSchema:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.airtable_tool.airtable_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.airtable_tool.airtable_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["airtable_get_base_schema"](base_id="appXXX")
+6 -1
View File
@@ -156,7 +156,12 @@ class TestAsanaSearchTasks:
def test_successful_search(self, tool_fns):
mock_resp = {
"data": [
{"gid": "task-1", "name": "Design homepage", "completed": False, "due_on": "2024-06-15"}
{
"gid": "task-1",
"name": "Design homepage",
"completed": False,
"due_on": "2024-06-15",
}
]
}
with (
+10 -19
View File
@@ -121,9 +121,7 @@ class TestAttioClient:
mock_request.return_value = mock_response
params = {"matching_attribute": "email_addresses"}
result = self.client._request(
"PUT", "/objects/people/records", json_body={}, params=params
)
result = self.client._request("PUT", "/objects/people/records", json_body={}, params=params)
call_kwargs = mock_request.call_args.kwargs
assert call_kwargs["params"] == params
@@ -210,7 +208,10 @@ class TestAttioClient:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": {"record_id": "rec-123"}, "values": {"name": [{"first_name": "Updated"}]}}
"data": {
"id": {"record_id": "rec-123"},
"values": {"name": [{"first_name": "Updated"}]},
}
}
mock_request.return_value = mock_response
@@ -223,9 +224,7 @@ class TestAttioClient:
def test_assert_record(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": {"record_id": "rec-upserted"}}
}
mock_response.json.return_value = {"data": {"id": {"record_id": "rec-upserted"}}}
mock_request.return_value = mock_response
values = {"email_addresses": [{"email_address": "test@example.com"}]}
@@ -241,9 +240,7 @@ class TestAttioClient:
def test_list_lists(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "list-1", "name": "Sales Pipeline"}]
}
mock_response.json.return_value = {"data": [{"id": "list-1", "name": "Sales Pipeline"}]}
mock_request.return_value = mock_response
result = self.client.list_lists()
@@ -255,9 +252,7 @@ class TestAttioClient:
def test_get_entries(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "entry-1"}, {"id": "entry-2"}]
}
mock_response.json.return_value = {"data": [{"id": "entry-1"}, {"id": "entry-2"}]}
mock_request.return_value = mock_response
result = self.client.get_entries("list-1")
@@ -332,9 +327,7 @@ class TestAttioClient:
def test_list_tasks(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [{"id": "task-1"}, {"id": "task-2"}]
}
mock_response.json.return_value = {"data": [{"id": "task-1"}, {"id": "task-2"}]}
mock_request.return_value = mock_response
result = self.client.list_tasks()
@@ -346,9 +339,7 @@ class TestAttioClient:
def test_get_task(self, mock_request):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": {"id": "task-1", "content": "Call back"}
}
mock_response.json.return_value = {"data": {"id": "task-1", "content": "Call back"}}
mock_request.return_value = mock_response
result = self.client.get_task("task-1")
+17 -4
View File
@@ -61,7 +61,10 @@ class TestS3ListBuckets:
def test_successful_list(self, tool_fns):
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.aws_s3_tool.aws_s3_tool.httpx.get", return_value=_mock_resp(LIST_BUCKETS_XML)),
patch(
"aden_tools.tools.aws_s3_tool.aws_s3_tool.httpx.get",
return_value=_mock_resp(LIST_BUCKETS_XML),
),
):
result = tool_fns["s3_list_buckets"]()
@@ -78,7 +81,10 @@ class TestS3ListObjects:
def test_successful_list(self, tool_fns):
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.aws_s3_tool.aws_s3_tool.httpx.get", return_value=_mock_resp(LIST_OBJECTS_XML)),
patch(
"aden_tools.tools.aws_s3_tool.aws_s3_tool.httpx.get",
return_value=_mock_resp(LIST_OBJECTS_XML),
),
):
result = tool_fns["s3_list_objects"](bucket="my-bucket")
@@ -97,7 +103,12 @@ class TestS3GetObject:
def test_successful_get_text(self, tool_fns):
resp = _mock_resp(
"Hello, world!",
headers={"content-type": "text/plain", "content-length": "13", "etag": '"abc"', "last-modified": "Wed, 15 Jan 2024"},
headers={
"content-type": "text/plain",
"content-length": "13",
"etag": '"abc"',
"last-modified": "Wed, 15 Jan 2024",
},
)
with (
patch.dict("os.environ", ENV),
@@ -121,7 +132,9 @@ class TestS3PutObject:
patch.dict("os.environ", ENV),
patch("aden_tools.tools.aws_s3_tool.aws_s3_tool.httpx.put", return_value=resp),
):
result = tool_fns["s3_put_object"](bucket="my-bucket", key="new-file.txt", content="Hello!")
result = tool_fns["s3_put_object"](
bucket="my-bucket", key="new-file.txt", content="Hello!"
)
assert result["result"] == "uploaded"
assert result["key"] == "new-file.txt"
+29 -8
View File
@@ -52,7 +52,10 @@ class TestAzureSQLListServers:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["azure_sql_list_servers"]()
@@ -81,7 +84,10 @@ class TestAzureSQLGetServer:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["azure_sql_get_server"](resource_group="rg", server_name="myserver")
@@ -116,9 +122,14 @@ class TestAzureSQLListDatabases:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["azure_sql_list_databases"](resource_group="rg", server_name="myserver")
result = tool_fns["azure_sql_list_databases"](
resource_group="rg", server_name="myserver"
)
assert result["count"] == 1
assert result["databases"][0]["name"] == "mydb"
@@ -129,7 +140,9 @@ class TestAzureSQLListDatabases:
class TestAzureSQLGetDatabase:
def test_missing_params(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["azure_sql_get_database"](resource_group="", server_name="", database_name="")
result = tool_fns["azure_sql_get_database"](
resource_group="", server_name="", database_name=""
)
assert "error" in result
def test_successful_get(self, tool_fns):
@@ -148,7 +161,10 @@ class TestAzureSQLGetDatabase:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["azure_sql_get_database"](
resource_group="rg", server_name="myserver", database_name="mydb"
@@ -179,9 +195,14 @@ class TestAzureSQLListFirewallRules:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.azure_sql_tool.azure_sql_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["azure_sql_list_firewall_rules"](resource_group="rg", server_name="myserver")
result = tool_fns["azure_sql_list_firewall_rules"](
resource_group="rg", server_name="myserver"
)
assert result["count"] == 1
assert result["firewall_rules"][0]["name"] == "AllowAll"
+9 -9
View File
@@ -79,9 +79,7 @@ class TestBrevoSendEmail:
mock_response = MagicMock()
mock_response.status_code = 201
mock_response.content = b'{"messageId": "<abc123@smtp-relay.brevo.com>"}'
mock_response.json.return_value = {
"messageId": "<abc123@smtp-relay.brevo.com>"
}
mock_response.json.return_value = {"messageId": "<abc123@smtp-relay.brevo.com>"}
mock_post.return_value = mock_response
result = fn(
@@ -105,9 +103,7 @@ class TestBrevoSendEmail:
mock_response = MagicMock()
mock_response.status_code = 201
mock_response.content = b'{"messageId": "<abc123@smtp-relay.brevo.com>"}'
mock_response.json.return_value = {
"messageId": "<abc123@smtp-relay.brevo.com>"
}
mock_response.json.return_value = {"messageId": "<abc123@smtp-relay.brevo.com>"}
mock_post.return_value = mock_response
fn(
@@ -201,6 +197,7 @@ class TestBrevoSendEmail:
def test_send_email_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_send_email")
@@ -284,6 +281,7 @@ class TestBrevoSendSMS:
def test_send_sms_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_send_sms")
@@ -364,6 +362,7 @@ class TestBrevoCreateContact:
def test_create_contact_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_create_contact")
@@ -447,6 +446,7 @@ class TestBrevoGetContact:
def test_get_contact_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_get_contact")
@@ -524,6 +524,7 @@ class TestBrevoUpdateContact:
def test_update_contact_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_update_contact")
@@ -556,9 +557,7 @@ class TestBrevoGetEmailStats:
"email": "user@example.com",
"subject": "Hello",
"date": "2024-01-15T10:30:00Z",
"events": [
{"name": "delivered", "time": "2024-01-15T10:30:05Z"}
],
"events": [{"name": "delivered", "time": "2024-01-15T10:30:05Z"}],
}
mock_get.return_value = mock_response
@@ -599,6 +598,7 @@ class TestBrevoGetEmailStats:
def test_get_email_stats_timeout(self, get_tool_fn, monkeypatch):
"""Timeout returns error."""
import httpx
monkeypatch.setenv("BREVO_API_KEY", "test-api-key")
fn = get_tool_fn("brevo_get_email_stats")
+21 -8
View File
@@ -48,7 +48,10 @@ class TestCalendlyGetCurrentUser:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.calendly_tool.calendly_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.calendly_tool.calendly_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["calendly_get_current_user"]()
@@ -81,7 +84,10 @@ class TestCalendlyListEventTypes:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.calendly_tool.calendly_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.calendly_tool.calendly_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["calendly_list_event_types"](user_uri=USER_URI)
@@ -114,7 +120,10 @@ class TestCalendlyListScheduledEvents:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.calendly_tool.calendly_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.calendly_tool.calendly_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["calendly_list_scheduled_events"](user_uri=USER_URI)
@@ -146,7 +155,10 @@ class TestCalendlyGetScheduledEvent:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.calendly_tool.calendly_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.calendly_tool.calendly_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["calendly_get_scheduled_event"](event_uri=EVENT_URI)
@@ -169,9 +181,7 @@ class TestCalendlyListInvitees:
"email": "jane@example.com",
"status": "active",
"timezone": "America/Chicago",
"questions_and_answers": [
{"question": "Topic?", "answer": "Product demo"}
],
"questions_and_answers": [{"question": "Topic?", "answer": "Product demo"}],
"created_at": "2024-03-10T12:00:00.000000Z",
}
],
@@ -179,7 +189,10 @@ class TestCalendlyListInvitees:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.calendly_tool.calendly_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.calendly_tool.calendly_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["calendly_list_invitees"](event_uri=EVENT_URI)
+18 -5
View File
@@ -47,7 +47,10 @@ class TestCloudinaryUpload:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post",
return_value=mock_resp,
),
):
result = tool_fns["cloudinary_upload"](file_url="https://example.com/img.jpg")
@@ -80,7 +83,9 @@ class TestCloudinaryListResources:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["cloudinary_list_resources"]()
@@ -111,7 +116,9 @@ class TestCloudinaryGetResource:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["cloudinary_get_resource"](public_id="sample1")
@@ -131,7 +138,10 @@ class TestCloudinaryDeleteResource:
mock_resp.json.return_value = {"result": "ok"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post",
return_value=mock_resp,
),
):
result = tool_fns["cloudinary_delete_resource"](public_id="sample1")
@@ -163,7 +173,10 @@ class TestCloudinarySearch:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.cloudinary_tool.cloudinary_tool.httpx.post",
return_value=mock_resp,
),
):
result = tool_fns["cloudinary_search"](expression="resource_type:image AND tags=nature")
+34 -10
View File
@@ -33,12 +33,20 @@ class TestConfluenceListSpaces:
mock_resp.content = b"{}"
mock_resp.json.return_value = {
"results": [
{"id": "123", "key": "DEV", "name": "Development", "type": "global", "status": "current"}
{
"id": "123",
"key": "DEV",
"name": "Development",
"type": "global",
"status": "current",
}
]
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["confluence_list_spaces"]()
@@ -54,14 +62,20 @@ class TestConfluenceListPages:
mock_resp.json.return_value = {
"results": [
{
"id": "page-1", "title": "Getting Started", "spaceId": "123",
"status": "current", "version": {"number": 3}, "createdAt": "2024-01-01T00:00:00Z",
"id": "page-1",
"title": "Getting Started",
"spaceId": "123",
"status": "current",
"version": {"number": 3},
"createdAt": "2024-01-01T00:00:00Z",
}
]
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["confluence_list_pages"](space_id="123")
@@ -80,14 +94,19 @@ class TestConfluenceGetPage:
mock_resp.status_code = 200
mock_resp.content = b"{}"
mock_resp.json.return_value = {
"id": "page-1", "title": "Getting Started", "spaceId": "123",
"status": "current", "version": {"number": 3},
"id": "page-1",
"title": "Getting Started",
"spaceId": "123",
"status": "current",
"version": {"number": 3},
"body": {"storage": {"value": "<p>Hello</p>"}},
"createdAt": "2024-01-01T00:00:00Z",
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["confluence_get_page"](page_id="page-1")
@@ -108,7 +127,10 @@ class TestConfluenceCreatePage:
mock_resp.json.return_value = {"id": "page-new", "title": "New Page"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.confluence_tool.confluence_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.confluence_tool.confluence_tool.httpx.post",
return_value=mock_resp,
),
):
result = tool_fns["confluence_create_page"](
space_id="123", title="New Page", body="<p>Content</p>"
@@ -139,7 +161,9 @@ class TestConfluenceSearch:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.confluence_tool.confluence_tool.httpx.get", return_value=mock_resp
),
):
result = tool_fns["confluence_search"](query="deployment")
+3 -1
View File
@@ -42,7 +42,9 @@ class TestDatabricksSqlQuery:
mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = mock_resp
mock_post.return_value.text = "{}"
result = tool_fns["databricks_sql_query"](statement="SELECT * FROM users", warehouse_id="w1")
result = tool_fns["databricks_sql_query"](
statement="SELECT * FROM users", warehouse_id="w1"
)
assert result["status"] == "SUCCEEDED"
assert result["columns"] == ["id", "name"]
+27 -7
View File
@@ -47,7 +47,10 @@ class TestGitlabListProjects:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(projects)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get",
return_value=_mock_resp(projects),
),
):
result = tool_fns["gitlab_list_projects"]()
@@ -79,7 +82,10 @@ class TestGitlabGetProject:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(project)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get",
return_value=_mock_resp(project),
),
):
result = tool_fns["gitlab_get_project"](project_id="1")
@@ -109,7 +115,10 @@ class TestGitlabListIssues:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(issues)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get",
return_value=_mock_resp(issues),
),
):
result = tool_fns["gitlab_list_issues"](project_id="1")
@@ -141,7 +150,9 @@ class TestGitlabGetIssue:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(issue)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(issue)
),
):
result = tool_fns["gitlab_get_issue"](project_id="1", issue_iid=1)
@@ -156,10 +167,17 @@ class TestGitlabCreateIssue:
assert "error" in result
def test_successful_create(self, tool_fns):
issue = {"iid": 2, "title": "New issue", "web_url": "https://gitlab.com/user/project/-/issues/2"}
issue = {
"iid": 2,
"title": "New issue",
"web_url": "https://gitlab.com/user/project/-/issues/2",
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.post", return_value=_mock_resp(issue, 201)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.post",
return_value=_mock_resp(issue, 201),
),
):
result = tool_fns["gitlab_create_issue"](project_id="1", title="New issue")
@@ -189,7 +207,9 @@ class TestGitlabListMergeRequests:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(mrs)),
patch(
"aden_tools.tools.gitlab_tool.gitlab_tool.httpx.get", return_value=_mock_resp(mrs)
),
):
result = tool_fns["gitlab_list_merge_requests"](project_id="1")
@@ -27,9 +27,7 @@ class TestGscSearchAnalytics:
def test_missing_params(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["gsc_search_analytics"](
site_url="", start_date="", end_date=""
)
result = tool_fns["gsc_search_analytics"](site_url="", start_date="", end_date="")
assert "error" in result
def test_successful_query(self, tool_fns):
@@ -46,7 +44,9 @@ class TestGscSearchAnalytics:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.post") as mock_post,
patch(
"aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.post"
) as mock_post,
):
mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = mock_resp
@@ -61,13 +61,13 @@ class TestGscSearchAnalytics:
class TestGscListSites:
def test_successful_list(self, tool_fns):
mock_resp = {
"siteEntry": [
{"siteUrl": "https://example.com", "permissionLevel": "siteOwner"}
]
"siteEntry": [{"siteUrl": "https://example.com", "permissionLevel": "siteOwner"}]
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_resp
@@ -98,7 +98,9 @@ class TestGscListSitemaps:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_resp
@@ -131,7 +133,9 @@ class TestGscInspectUrl:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.post") as mock_post,
patch(
"aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.post"
) as mock_post,
):
mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = mock_resp
@@ -153,7 +157,9 @@ class TestGscSubmitSitemap:
def test_successful_submit(self, tool_fns):
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.put") as mock_put,
patch(
"aden_tools.tools.google_search_console_tool.google_search_console_tool.httpx.put"
) as mock_put,
):
mock_put.return_value.status_code = 204
result = tool_fns["gsc_submit_sitemap"](
+15 -4
View File
@@ -53,7 +53,10 @@ class TestSheetsGetSpreadsheet:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["sheets_get_spreadsheet"](spreadsheet_id="abc123")
@@ -85,7 +88,10 @@ class TestSheetsReadRange:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["sheets_read_range"](spreadsheet_id="abc123", range="Sheet1!A1:B3")
@@ -109,9 +115,14 @@ class TestSheetsBatchRead:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.google_sheets_tool.google_sheets_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["sheets_batch_read"](spreadsheet_id="abc123", ranges="Sheet1!A1:B2,Sheet2!A1:A2")
result = tool_fns["sheets_batch_read"](
spreadsheet_id="abc123", ranges="Sheet1!A1:B2,Sheet2!A1:A2"
)
assert result["count"] == 2
assert result["ranges"][0]["row_count"] == 2
+24 -6
View File
@@ -45,7 +45,10 @@ class TestGreenhouseListJobs:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(jobs)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(jobs),
),
):
result = tool_fns["greenhouse_list_jobs"]()
@@ -75,7 +78,10 @@ class TestGreenhouseGetJob:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(job)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(job),
),
):
result = tool_fns["greenhouse_get_job"](job_id=1)
@@ -104,7 +110,10 @@ class TestGreenhouseListCandidates:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(candidates)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(candidates),
),
):
result = tool_fns["greenhouse_list_candidates"]()
@@ -134,7 +143,10 @@ class TestGreenhouseGetCandidate:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(candidate)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(candidate),
),
):
result = tool_fns["greenhouse_get_candidate"](candidate_id=100)
@@ -162,7 +174,10 @@ class TestGreenhouseListApplications:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(apps)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(apps),
),
):
result = tool_fns["greenhouse_list_applications"]()
@@ -191,7 +206,10 @@ class TestGreenhouseGetApplication:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get", return_value=_mock_resp(app)),
patch(
"aden_tools.tools.greenhouse_tool.greenhouse_tool.httpx.get",
return_value=_mock_resp(app),
),
):
result = tool_fns["greenhouse_get_application"](application_id=200)
+24 -6
View File
@@ -39,7 +39,10 @@ class TestHuggingFaceSearchModels:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_search_models"](query="llama")
@@ -70,7 +73,10 @@ class TestHuggingFaceGetModel:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_get_model"](model_id="meta-llama/Llama-3-8B")
@@ -94,7 +100,10 @@ class TestHuggingFaceSearchDatasets:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_search_datasets"](query="squad")
@@ -123,7 +132,10 @@ class TestHuggingFaceGetDataset:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_get_dataset"](dataset_id="openai/gsm8k")
@@ -146,7 +158,10 @@ class TestHuggingFaceSearchSpaces:
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_search_spaces"](query="chatbot")
@@ -173,7 +188,10 @@ class TestHuggingFaceWhoami:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get", return_value=mock_resp),
patch(
"aden_tools.tools.huggingface_tool.huggingface_tool.httpx.get",
return_value=mock_resp,
),
):
result = tool_fns["huggingface_whoami"]()
+13 -3
View File
@@ -112,10 +112,17 @@ class TestJiraCreateIssue:
assert "error" in result
def test_successful_create(self, tool_fns):
data = {"key": "TEST-2", "id": "10002", "self": "https://test.atlassian.net/rest/api/3/issue/10002"}
data = {
"key": "TEST-2",
"id": "10002",
"self": "https://test.atlassian.net/rest/api/3/issue/10002",
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.jira_tool.jira_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.jira_tool.jira_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["jira_create_issue"](project_key="TEST", summary="New task")
@@ -188,7 +195,10 @@ class TestJiraAddComment:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.jira_tool.jira_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.jira_tool.jira_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["jira_add_comment"](issue_key="TEST-1", body="Great work!")
+18 -6
View File
@@ -53,7 +53,9 @@ class TestKafkaListTopics:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_list_topics"]()
@@ -78,7 +80,9 @@ class TestKafkaGetTopic:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_get_topic"](topic_name="orders")
@@ -100,7 +104,9 @@ class TestKafkaCreateTopic:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_create_topic"](topic_name="new-topic", partitions_count=3)
@@ -123,7 +129,9 @@ class TestKafkaProduceMessage:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_produce_message"](
topic_name="orders", value='{"order_id": 123}', key="order-123"
@@ -147,7 +155,9 @@ class TestKafkaListConsumerGroups:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_list_consumer_groups"]()
@@ -173,7 +183,9 @@ class TestKafkaGetConsumerGroupLag:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.kafka_tool.kafka_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["kafka_get_consumer_group_lag"](consumer_group_id="my-group")
+24 -6
View File
@@ -54,7 +54,10 @@ class TestLangfuseListTraces:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_list_traces"]()
@@ -106,7 +109,10 @@ class TestLangfuseGetTrace:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_get_trace"](trace_id="trace-abc123")
@@ -136,7 +142,10 @@ class TestLangfuseListScores:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_list_scores"]()
@@ -155,7 +164,10 @@ class TestLangfuseCreateScore:
data = {"id": "score-new-123"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_create_score"](
trace_id="trace-abc123",
@@ -184,7 +196,10 @@ class TestLangfuseListPrompts:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_list_prompts"]()
@@ -214,7 +229,10 @@ class TestLangfuseGetPrompt:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.langfuse_tool.langfuse_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["langfuse_get_prompt"](prompt_name="movie-critic")
+18 -6
View File
@@ -50,7 +50,9 @@ class TestLushaEnrichPerson:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_enrich_person"](
first_name="Jane", last_name="Doe", company_domain="acme.com"
@@ -72,7 +74,9 @@ class TestLushaEnrichPerson:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_enrich_person"](email="jane@acme.com")
@@ -99,7 +103,9 @@ class TestLushaEnrichCompany:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_enrich_company"](domain="acme.com")
@@ -133,7 +139,9 @@ class TestLushaSearchContacts:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_search_contacts"](
seniorities="4,5", company_domains="acme.com"
@@ -166,7 +174,9 @@ class TestLushaSearchCompanies:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_search_companies"](country="United States")
@@ -184,7 +194,9 @@ class TestLushaGetUsage:
data = {"credits_used": 150, "credits_remaining": 850, "plan": "Professional"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.lusha_tool.lusha_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["lusha_get_usage"]()
+26 -14
View File
@@ -39,7 +39,9 @@ class TestOutlookListMessages:
}
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_response
@@ -72,7 +74,9 @@ class TestOutlookGetMessage:
}
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_response
@@ -92,7 +96,9 @@ class TestOutlookSendMail:
def test_successful_send(self, tool_fns):
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.post") as mock_post,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.post"
) as mock_post,
):
mock_post.return_value.status_code = 202
mock_post.return_value.json.return_value = {}
@@ -108,13 +114,13 @@ class TestOutlookSendMail:
class TestTeamsListTeams:
def test_successful_list(self, tool_fns):
mock_response = {
"value": [
{"id": "team-1", "displayName": "Engineering", "description": "Dev team"}
]
"value": [{"id": "team-1", "displayName": "Engineering", "description": "Dev team"}]
}
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_response
@@ -143,7 +149,9 @@ class TestTeamsListChannels:
}
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_response
@@ -156,15 +164,15 @@ class TestTeamsListChannels:
class TestTeamsSendChannelMessage:
def test_missing_fields(self, tool_fns):
with patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}):
result = tool_fns["teams_send_channel_message"](
team_id="", channel_id="", message=""
)
result = tool_fns["teams_send_channel_message"](team_id="", channel_id="", message="")
assert "error" in result
def test_successful_send(self, tool_fns):
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.post") as mock_post,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.post"
) as mock_post,
):
mock_post.return_value.status_code = 201
mock_post.return_value.json.return_value = {"id": "msg-123"}
@@ -199,7 +207,9 @@ class TestOneDriveSearchFiles:
}
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get") as mock_get,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.get"
) as mock_get,
):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = mock_response
@@ -219,7 +229,9 @@ class TestOneDriveUploadFile:
def test_successful_upload(self, tool_fns):
with (
patch.dict("os.environ", {"MICROSOFT_GRAPH_ACCESS_TOKEN": "test-token"}),
patch("aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.put") as mock_put,
patch(
"aden_tools.tools.microsoft_graph_tool.microsoft_graph_tool.httpx.put"
) as mock_put,
):
mock_put.return_value.status_code = 201
mock_put.return_value.json.return_value = {
+40 -11
View File
@@ -49,7 +49,10 @@ class TestMongodbFind:
data = {"documents": [{"_id": "1", "name": "Alice"}, {"_id": "2", "name": "Bob"}]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_find"](database="mydb", collection="users")
@@ -62,9 +65,14 @@ class TestMongodbFindOne:
data = {"document": {"_id": "1", "name": "Alice", "age": 30}}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_find_one"](database="mydb", collection="users", filter='{"name": "Alice"}')
result = tool_fns["mongodb_find_one"](
database="mydb", collection="users", filter='{"name": "Alice"}'
)
assert result["name"] == "Alice"
assert result["age"] == 30
@@ -73,9 +81,14 @@ class TestMongodbFindOne:
data = {"document": None}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_find_one"](database="mydb", collection="users", filter='{"name": "Nobody"}')
result = tool_fns["mongodb_find_one"](
database="mydb", collection="users", filter='{"name": "Nobody"}'
)
assert "error" in result
@@ -90,7 +103,10 @@ class TestMongodbInsertOne:
data = {"insertedId": "abc123"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_insert_one"](
database="mydb", collection="users", document='{"name": "Alice", "age": 30}'
@@ -103,14 +119,19 @@ class TestMongodbInsertOne:
class TestMongodbUpdateOne:
def test_missing_params(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["mongodb_update_one"](database="db", collection="col", filter="", update="")
result = tool_fns["mongodb_update_one"](
database="db", collection="col", filter="", update=""
)
assert "error" in result
def test_successful_update(self, tool_fns):
data = {"matchedCount": 1, "modifiedCount": 1}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_update_one"](
database="mydb",
@@ -133,7 +154,10 @@ class TestMongodbDeleteOne:
data = {"deletedCount": 1}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_delete_one"](
database="mydb", collection="users", filter='{"name": "Alice"}'
@@ -150,14 +174,19 @@ class TestMongodbAggregate:
def test_invalid_pipeline(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["mongodb_aggregate"](database="db", collection="col", pipeline='{"not": "array"}')
result = tool_fns["mongodb_aggregate"](
database="db", collection="col", pipeline='{"not": "array"}'
)
assert "error" in result
def test_successful_aggregate(self, tool_fns):
data = {"documents": [{"_id": "active", "count": 5}, {"_id": "inactive", "count": 2}]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.mongodb_tool.mongodb_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["mongodb_aggregate"](
database="mydb",
+11 -1
View File
@@ -63,7 +63,17 @@ class TestN8nListWorkflows:
def test_pagination(self, tool_fns):
data = {
"data": [{"id": "wf1", "name": "WF1", "active": True, "createdAt": "", "updatedAt": "", "tags": [], "nodes": []}],
"data": [
{
"id": "wf1",
"name": "WF1",
"active": True,
"createdAt": "",
"updatedAt": "",
"tags": [],
"nodes": [],
}
],
"nextCursor": "cursor123",
}
with (
+16 -5
View File
@@ -52,7 +52,9 @@ class TestNotionSearch:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.notion_tool.notion_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.notion_tool.notion_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["notion_search"](query="My Page")
@@ -86,7 +88,9 @@ class TestNotionGetPage:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.notion_tool.notion_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.notion_tool.notion_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["notion_get_page"](page_id="page-1")
@@ -104,7 +108,10 @@ class TestNotionCreatePage:
data = {"id": "new-page", "url": "https://notion.so/new-page"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.notion_tool.notion_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.notion_tool.notion_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["notion_create_page"](parent_database_id="db-1", title="New Page")
@@ -138,7 +145,9 @@ class TestNotionQueryDatabase:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.notion_tool.notion_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.notion_tool.notion_tool.httpx.post", return_value=_mock_resp(data)
),
):
result = tool_fns["notion_query_database"](database_id="db-1")
@@ -166,7 +175,9 @@ class TestNotionGetDatabase:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.notion_tool.notion_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.notion_tool.notion_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["notion_get_database"](database_id="db-1")
+24 -6
View File
@@ -50,7 +50,10 @@ class TestObsidianReadNote:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["obsidian_read_note"](path="Notes/meeting.md")
@@ -111,14 +114,23 @@ class TestObsidianSearch:
"filename": "Daily/2025-03-01.md",
"score": 0.85,
"matches": [
{"match": {"start": 45, "end": 52}, "context": "...attended the team meeting to discuss..."},
{"match": {"start": 120, "end": 127}, "context": "...follow-up meeting scheduled for..."},
{
"match": {"start": 45, "end": 52},
"context": "...attended the team meeting to discuss...",
},
{
"match": {"start": 120, "end": 127},
"context": "...follow-up meeting scheduled for...",
},
],
}
]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.obsidian_tool.obsidian_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.obsidian_tool.obsidian_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["obsidian_search"](query="meeting")
@@ -132,7 +144,10 @@ class TestObsidianListFiles:
data = ["Daily/", "Projects/", "README.md", "Templates/"]
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["obsidian_list_files"]()
@@ -151,7 +166,10 @@ class TestObsidianGetActive:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.obsidian_tool.obsidian_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["obsidian_get_active"]()
+26 -7
View File
@@ -51,7 +51,10 @@ class TestPagerdutyListIncidents:
data = {"incidents": [INCIDENT_DATA], "more": False}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["pagerduty_list_incidents"]()
@@ -72,7 +75,10 @@ class TestPagerdutyGetIncident:
data = {"incident": inc}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["pagerduty_get_incident"](incident_id="PT4KHLK")
@@ -90,9 +96,14 @@ class TestPagerdutyCreateIncident:
data = {"incident": INCIDENT_DATA}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["pagerduty_create_incident"](title="Server is on fire", service_id="PWIXJZS")
result = tool_fns["pagerduty_create_incident"](
title="Server is on fire", service_id="PWIXJZS"
)
assert result["result"] == "created"
assert result["id"] == "PT4KHLK"
@@ -110,9 +121,14 @@ class TestPagerdutyUpdateIncident:
data = {"incident": ack}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.put", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.put",
return_value=_mock_resp(data),
),
):
result = tool_fns["pagerduty_update_incident"](incident_id="PT4KHLK", status="acknowledged")
result = tool_fns["pagerduty_update_incident"](
incident_id="PT4KHLK", status="acknowledged"
)
assert result["status"] == "acknowledged"
@@ -139,7 +155,10 @@ class TestPagerdutyListServices:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.pagerduty_tool.pagerduty_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["pagerduty_list_services"]()
+18 -6
View File
@@ -68,7 +68,9 @@ class TestPineconeCreateIndex:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp
),
):
result = tool_fns["pinecone_create_index"](name="new-idx", dimension=768)
@@ -118,7 +120,9 @@ class TestPineconeDeleteIndex:
mock_resp.content = b""
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.delete", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.delete", return_value=mock_resp
),
):
result = tool_fns["pinecone_delete_index"](index_name="old-index")
@@ -138,7 +142,9 @@ class TestPineconeUpsertVectors:
mock_resp.json.return_value = {"upsertedCount": 2}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp
),
):
result = tool_fns["pinecone_upsert_vectors"](
index_host="my-index-abc.svc.pinecone.io",
@@ -170,7 +176,9 @@ class TestPineconeQueryVectors:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp
),
):
result = tool_fns["pinecone_query_vectors"](
index_host="my-index-abc.svc.pinecone.io",
@@ -223,7 +231,9 @@ class TestPineconeDeleteVectors:
mock_resp.json.return_value = {}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp
),
):
result = tool_fns["pinecone_delete_vectors"](
index_host="my-index-abc.svc.pinecone.io",
@@ -255,7 +265,9 @@ class TestPineconeIndexStats:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp),
patch(
"aden_tools.tools.pinecone_tool.pinecone_tool.httpx.post", return_value=mock_resp
),
):
result = tool_fns["pinecone_index_stats"](
index_host="my-index-abc.svc.pinecone.io",
+7 -4
View File
@@ -75,7 +75,12 @@ class TestPlaidGetBalance:
"account_id": "acc-1",
"name": "Savings",
"type": "depository",
"balances": {"available": 5000, "current": 5000, "limit": None, "iso_currency_code": "USD"},
"balances": {
"available": 5000,
"current": 5000,
"limit": None,
"iso_currency_code": "USD",
},
}
],
}
@@ -130,9 +135,7 @@ class TestPlaidSyncTransactions:
class TestPlaidGetTransactions:
def test_missing_params(self, tool_fns):
with patch.dict("os.environ", ENV):
result = tool_fns["plaid_get_transactions"](
access_token="", start_date="", end_date=""
)
result = tool_fns["plaid_get_transactions"](access_token="", start_date="", end_date="")
assert "error" in result
def test_successful_get(self, tool_fns):
+17 -7
View File
@@ -46,7 +46,10 @@ class TestPowerBIListWorkspaces:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["powerbi_list_workspaces"]()
@@ -77,7 +80,10 @@ class TestPowerBIListDatasets:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["powerbi_list_datasets"](workspace_id="ws-123")
@@ -107,7 +113,10 @@ class TestPowerBIListReports:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["powerbi_list_reports"](workspace_id="ws-123")
@@ -128,9 +137,7 @@ class TestPowerBIRefreshDataset:
patch.dict("os.environ", ENV),
patch("aden_tools.tools.powerbi_tool.powerbi_tool.httpx.post", return_value=resp),
):
result = tool_fns["powerbi_refresh_dataset"](
workspace_id="ws-123", dataset_id="ds-456"
)
result = tool_fns["powerbi_refresh_dataset"](workspace_id="ws-123", dataset_id="ds-456")
assert result["result"] == "accepted"
@@ -155,7 +162,10 @@ class TestPowerBIGetRefreshHistory:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.powerbi_tool.powerbi_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["powerbi_get_refresh_history"](
workspace_id="ws-123", dataset_id="ds-456"
+1 -3
View File
@@ -61,9 +61,7 @@ class TestPushoverSend:
"request": "req-2",
"receipt": "rcpt-1",
}
result = tool_fns["pushover_send"](
user_key="ukey", message="URGENT", priority=2
)
result = tool_fns["pushover_send"](user_key="ukey", message="URGENT", priority=2)
assert result["receipt"] == "rcpt-1"
+23 -6
View File
@@ -51,7 +51,10 @@ class TestQuickbooksQuery:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["quickbooks_query"](entity="Customer")
@@ -76,7 +79,10 @@ class TestQuickbooksGetEntity:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["quickbooks_get_entity"](entity="Customer", entity_id="1")
@@ -100,9 +106,14 @@ class TestQuickbooksCreateCustomer:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["quickbooks_create_customer"](display_name="New Customer", email="new@example.com")
result = tool_fns["quickbooks_create_customer"](
display_name="New Customer", email="new@example.com"
)
assert result["result"] == "created"
assert result["id"] == "59"
@@ -131,7 +142,10 @@ class TestQuickbooksCreateInvoice:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["quickbooks_create_invoice"](
customer_id="1",
@@ -161,7 +175,10 @@ class TestQuickbooksGetCompanyInfo:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.quickbooks_tool.quickbooks_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["quickbooks_get_company_info"]()
+20 -5
View File
@@ -57,7 +57,10 @@ class TestRedshiftExecuteSQL:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.redshift_tool.redshift_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.redshift_tool.redshift_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["redshift_execute_sql"](
sql="SELECT * FROM users", database="dev", cluster_identifier="my-cluster"
@@ -85,7 +88,10 @@ class TestRedshiftDescribeStatement:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.redshift_tool.redshift_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.redshift_tool.redshift_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["redshift_describe_statement"](statement_id="stmt-abc123")
@@ -114,7 +120,10 @@ class TestRedshiftGetResults:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.redshift_tool.redshift_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.redshift_tool.redshift_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["redshift_get_results"](statement_id="stmt-abc123")
@@ -133,7 +142,10 @@ class TestRedshiftListDatabases:
data = {"Databases": ["dev", "staging", "analytics"], "NextToken": ""}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.redshift_tool.redshift_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.redshift_tool.redshift_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["redshift_list_databases"](cluster_identifier="my-cluster")
@@ -157,7 +169,10 @@ class TestRedshiftListTables:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.redshift_tool.redshift_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.redshift_tool.redshift_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["redshift_list_tables"](
database="dev", cluster_identifier="my-cluster"
+46 -10
View File
@@ -50,7 +50,10 @@ class TestSalesforceSOQLQuery:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["salesforce_soql_query"](query="SELECT Id, Name FROM Lead")
@@ -67,7 +70,10 @@ class TestSalesforceSOQLQuery:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["salesforce_soql_query"](query="SELECT Id FROM Lead")
@@ -91,9 +97,14 @@ class TestSalesforceGetRecord:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["salesforce_get_record"](object_type="Contact", record_id="003xx000001")
result = tool_fns["salesforce_get_record"](
object_type="Contact", record_id="003xx000001"
)
assert result["Id"] == "003xx000001"
assert result["Email"] == "jane@example.com"
@@ -109,7 +120,10 @@ class TestSalesforceCreateRecord:
data = {"id": "00Qxx000001", "success": True, "errors": []}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["salesforce_create_record"](
object_type="Lead",
@@ -126,7 +140,9 @@ class TestSalesforceUpdateRecord:
resp.status_code = 204
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.patch", return_value=resp),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.patch", return_value=resp
),
):
result = tool_fns["salesforce_update_record"](
object_type="Lead",
@@ -169,7 +185,10 @@ class TestSalesforceDescribeObject:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["salesforce_describe_object"](object_type="Lead")
@@ -182,13 +201,30 @@ class TestSalesforceListObjects:
def test_successful_list(self, tool_fns):
data = {
"sobjects": [
{"name": "Lead", "label": "Lead", "keyPrefix": "00Q", "queryable": True, "createable": True, "custom": False},
{"name": "Account", "label": "Account", "keyPrefix": "001", "queryable": True, "createable": True, "custom": False},
{
"name": "Lead",
"label": "Lead",
"keyPrefix": "00Q",
"queryable": True,
"createable": True,
"custom": False,
},
{
"name": "Account",
"label": "Account",
"keyPrefix": "001",
"queryable": True,
"createable": True,
"custom": False,
},
]
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.salesforce_tool.salesforce_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["salesforce_list_objects"]()
+27 -7
View File
@@ -52,7 +52,10 @@ class TestShopifyListOrders:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_list_orders"]()
@@ -106,7 +109,10 @@ class TestShopifyGetOrder:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_get_order"](order_id="450789469")
@@ -134,7 +140,10 @@ class TestShopifyListProducts:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_list_products"]()
@@ -175,12 +184,17 @@ class TestShopifyGetProduct:
}
],
"options": [{"name": "Size"}, {"name": "Color"}],
"images": [{"id": 850703190, "src": "https://cdn.shopify.com/test.jpg", "position": 1}],
"images": [
{"id": 850703190, "src": "https://cdn.shopify.com/test.jpg", "position": 1}
],
}
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_get_product"](product_id="632910392")
@@ -210,7 +224,10 @@ class TestShopifyListCustomers:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_list_customers"]()
@@ -243,7 +260,10 @@ class TestShopifySearchCustomers:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.shopify_tool.shopify_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.shopify_tool.shopify_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["shopify_search_customers"](query="email:bob@example.com")
+24 -6
View File
@@ -50,7 +50,10 @@ class TestSnowflakeExecuteSQL:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["snowflake_execute_sql"](statement="SELECT * FROM users")
@@ -66,7 +69,10 @@ class TestSnowflakeExecuteSQL:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post", return_value=_mock_resp(data, 202)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post",
return_value=_mock_resp(data, 202),
),
):
result = tool_fns["snowflake_execute_sql"](statement="SELECT * FROM big_table")
@@ -91,7 +97,10 @@ class TestSnowflakeGetStatementStatus:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["snowflake_get_statement_status"](statement_handle="handle-123")
@@ -105,7 +114,10 @@ class TestSnowflakeGetStatementStatus:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get", return_value=_mock_resp(data, 202)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get",
return_value=_mock_resp(data, 202),
),
):
result = tool_fns["snowflake_get_statement_status"](statement_handle="handle-456")
@@ -118,7 +130,10 @@ class TestSnowflakeGetStatementStatus:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get", return_value=_mock_resp(data, 422)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.get",
return_value=_mock_resp(data, 422),
),
):
result = tool_fns["snowflake_get_statement_status"](statement_handle="handle-789")
@@ -136,7 +151,10 @@ class TestSnowflakeCancelStatement:
data = {"statementHandle": "handle-123"}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.snowflake_tool.snowflake_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["snowflake_cancel_statement"](statement_handle="handle-123")
+1 -3
View File
@@ -75,9 +75,7 @@ class TestSupabaseInsert:
):
mock_post.return_value.status_code = 201
mock_post.return_value.json.return_value = [{"id": 1, "name": "Alice"}]
result = tool_fns["supabase_insert"](
table="users", rows='{"name": "Alice"}'
)
result = tool_fns["supabase_insert"](table="users", rows='{"name": "Alice"}')
assert result["table"] == "users"
assert len(result["inserted"]) == 1
+20 -5
View File
@@ -63,7 +63,10 @@ class TestTerraformListWorkspaces:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.terraform_tool.terraform_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.terraform_tool.terraform_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["terraform_list_workspaces"](organization="my-org")
@@ -101,7 +104,10 @@ class TestTerraformGetWorkspace:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.terraform_tool.terraform_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.terraform_tool.terraform_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["terraform_get_workspace"](workspace_id="ws-abc123")
@@ -144,7 +150,10 @@ class TestTerraformListRuns:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.terraform_tool.terraform_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.terraform_tool.terraform_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["terraform_list_runs"](workspace_id="ws-abc123")
@@ -181,7 +190,10 @@ class TestTerraformGetRun:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.terraform_tool.terraform_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.terraform_tool.terraform_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["terraform_get_run"](run_id="run-xyz789")
@@ -215,7 +227,10 @@ class TestTerraformCreateRun:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.terraform_tool.terraform_tool.httpx.post", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.terraform_tool.terraform_tool.httpx.post",
return_value=_mock_resp(data),
),
):
result = tool_fns["terraform_create_run"](
workspace_id="ws-abc123",
+15 -5
View File
@@ -53,7 +53,9 @@ class TestTinesListStories:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["tines_list_stories"]()
@@ -85,7 +87,9 @@ class TestTinesGetStory:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["tines_get_story"](story_id=123)
@@ -111,7 +115,9 @@ class TestTinesListActions:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["tines_list_actions"](story_id=123)
@@ -142,7 +148,9 @@ class TestTinesGetAction:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["tines_get_action"](action_id=456)
@@ -170,7 +178,9 @@ class TestTinesGetActionLogs:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.tines_tool.tines_tool.httpx.get", return_value=_mock_resp(data)
),
):
result = tool_fns["tines_get_action_logs"](action_id=456)
+20 -6
View File
@@ -54,9 +54,13 @@ class TestTwilioSendSms:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twilio_tool.twilio_tool.httpx.post", return_value=_mock_resp(msg)),
patch(
"aden_tools.tools.twilio_tool.twilio_tool.httpx.post", return_value=_mock_resp(msg)
),
):
result = tool_fns["twilio_send_sms"](to="+14155552671", from_number="+15017122661", body="Hello!")
result = tool_fns["twilio_send_sms"](
to="+14155552671", from_number="+15017122661", body="Hello!"
)
assert result["sid"] == "SM123"
assert result["status"] == "queued"
@@ -78,9 +82,13 @@ class TestTwilioSendWhatsapp:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twilio_tool.twilio_tool.httpx.post", return_value=_mock_resp(msg)),
patch(
"aden_tools.tools.twilio_tool.twilio_tool.httpx.post", return_value=_mock_resp(msg)
),
):
result = tool_fns["twilio_send_whatsapp"](to="+14155552671", from_number="+14155238886", body="WhatsApp msg")
result = tool_fns["twilio_send_whatsapp"](
to="+14155552671", from_number="+14155238886", body="WhatsApp msg"
)
assert result["sid"] == "SM456"
@@ -110,7 +118,10 @@ class TestTwilioListMessages:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twilio_tool.twilio_tool.httpx.get", return_value=_mock_resp(data, 200)),
patch(
"aden_tools.tools.twilio_tool.twilio_tool.httpx.get",
return_value=_mock_resp(data, 200),
),
):
result = tool_fns["twilio_list_messages"]()
@@ -139,7 +150,10 @@ class TestTwilioGetMessage:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twilio_tool.twilio_tool.httpx.get", return_value=_mock_resp(msg, 200)),
patch(
"aden_tools.tools.twilio_tool.twilio_tool.httpx.get",
return_value=_mock_resp(msg, 200),
),
):
result = tool_fns["twilio_get_message"](message_sid="SM123")
+18 -10
View File
@@ -53,14 +53,15 @@ class TestTwitterSearchTweets:
},
}
],
"includes": {
"users": [{"id": "456", "name": "Test User", "username": "testuser"}]
},
"includes": {"users": [{"id": "456", "name": "Test User", "username": "testuser"}]},
"meta": {"result_count": 1},
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twitter_tool.twitter_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.twitter_tool.twitter_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["twitter_search_tweets"](query="hello")
@@ -95,7 +96,10 @@ class TestTwitterGetUser:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twitter_tool.twitter_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.twitter_tool.twitter_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["twitter_get_user"](username="testuser")
@@ -129,7 +133,10 @@ class TestTwitterGetUserTweets:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twitter_tool.twitter_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.twitter_tool.twitter_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["twitter_get_user_tweets"](user_id="456")
@@ -158,13 +165,14 @@ class TestTwitterGetTweet:
"impression_count": 20,
},
},
"includes": {
"users": [{"name": "Author", "username": "author"}]
},
"includes": {"users": [{"name": "Author", "username": "author"}]},
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.twitter_tool.twitter_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.twitter_tool.twitter_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["twitter_get_tweet"](tweet_id="123")
+1 -3
View File
@@ -111,9 +111,7 @@ class TestVercelListProjectDomains:
def test_successful_list(self, tool_fns):
mock_resp = {
"domains": [
{"name": "example.com", "redirect": "", "gitBranch": "", "verified": True}
]
"domains": [{"name": "example.com", "redirect": "", "gitBranch": "", "verified": True}]
}
with (
patch.dict("os.environ", ENV),
@@ -70,6 +70,7 @@ class TestYahooFinanceHistory:
# Create a mock DataFrame
import pandas as pd
mock_df = pd.DataFrame(
{
"Open": [174.0, 175.0],
+23 -6
View File
@@ -54,7 +54,10 @@ class TestZendeskListTickets:
data = {"tickets": [TICKET_DATA]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["zendesk_list_tickets"]()
@@ -72,7 +75,10 @@ class TestZendeskGetTicket:
data = {"ticket": TICKET_DATA}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["zendesk_get_ticket"](ticket_id=123)
@@ -90,7 +96,10 @@ class TestZendeskCreateTicket:
data = {"ticket": {"id": 456, "subject": "New ticket", "status": "new"}}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zendesk_tool.zendesk_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.zendesk_tool.zendesk_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["zendesk_create_ticket"](subject="New ticket", body="Help needed")
@@ -110,7 +119,10 @@ class TestZendeskUpdateTicket:
data = {"ticket": updated}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zendesk_tool.zendesk_tool.httpx.put", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.zendesk_tool.zendesk_tool.httpx.put",
return_value=_mock_resp(data),
),
):
result = tool_fns["zendesk_update_ticket"](ticket_id=123, status="pending")
@@ -125,12 +137,17 @@ class TestZendeskSearchTickets:
def test_successful_search(self, tool_fns):
data = {
"results": [{"id": 123, "subject": "Printer issue", "status": "open", "priority": "high"}],
"results": [
{"id": 123, "subject": "Printer issue", "status": "open", "priority": "high"}
],
"count": 1,
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get", return_value=_mock_resp(data)),
patch(
"aden_tools.tools.zendesk_tool.zendesk_tool.httpx.get",
return_value=_mock_resp(data),
),
):
result = tool_fns["zendesk_search_tickets"](query="status:open priority:high")
+1 -3
View File
@@ -152,9 +152,7 @@ class TestZohoCrmAddNote:
assert "error" in result
def test_successful_add(self, tool_fns):
mock_resp = {
"data": [{"status": "success", "details": {"id": "note-1"}}]
}
mock_resp = {"data": [{"status": "success", "details": {"id": "note-1"}}]}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zoho_crm_tool.zoho_crm_tool.httpx.post") as mock_post,
+18 -5
View File
@@ -87,7 +87,19 @@ class TestZoomListMeetings:
data = {
"total_records": 50,
"next_page_token": "token123",
"meetings": [{"id": 1, "uuid": "a", "topic": "M1", "type": 2, "start_time": "", "duration": 30, "timezone": "", "join_url": "", "created_at": ""}],
"meetings": [
{
"id": 1,
"uuid": "a",
"topic": "M1",
"type": 2,
"start_time": "",
"duration": 30,
"timezone": "",
"join_url": "",
"created_at": "",
}
],
}
with (
patch.dict("os.environ", ENV),
@@ -158,7 +170,10 @@ class TestZoomCreateMeeting:
}
with (
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zoom_tool.zoom_tool.httpx.post", return_value=_mock_resp(data, 201)),
patch(
"aden_tools.tools.zoom_tool.zoom_tool.httpx.post",
return_value=_mock_resp(data, 201),
),
):
result = tool_fns["zoom_create_meeting"](
topic="New Meeting",
@@ -222,9 +237,7 @@ class TestZoomListRecordings:
patch.dict("os.environ", ENV),
patch("aden_tools.tools.zoom_tool.zoom_tool.httpx.get", return_value=_mock_resp(data)),
):
result = tool_fns["zoom_list_recordings"](
from_date="2025-01-01", to_date="2025-01-31"
)
result = tool_fns["zoom_list_recordings"](from_date="2025-01-01", to_date="2025-01-31")
assert result["total_records"] == 1
assert result["recordings"][0]["recording_count"] == 2
+2
View File
@@ -21,6 +21,7 @@ DATABASE = os.getenv("MSSQL_DATABASE", "AdenTestDB")
USERNAME = os.getenv("MSSQL_USERNAME")
PASSWORD = os.getenv("MSSQL_PASSWORD")
def main():
connection = None
@@ -82,5 +83,6 @@ def main():
if connection:
connection.close()
if __name__ == "__main__":
main()