diff --git a/Makefile b/Makefile index 7b765c40..d8100013 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,15 @@ install: ## Install the uv environment and all packages with dependencies check: ## Run code quality tools. @echo "🚀 Linting code: Running pre-commit" @uv run pre-commit run -a - @echo "🚀 Static type checking: Running mypy on libs" - @for lib in libs/arcade*/ ; do \ - echo "🔍 Type checking $$lib"; \ - (cd $$lib && uv run mypy . --exclude tests || true); \ - done + @echo "🚀 Static type checking: Running mypy on libs" + @failed_libs=""; for lib in libs/arcade*/ ; do \ + echo "🔍 Type checking $$lib"; \ + (cd $$lib && uv run mypy . --exclude tests) || failed_libs="$$failed_libs $$lib"; \ + done; \ + if [ -n "$$failed_libs" ]; then \ + echo "❌ mypy failed in:$$failed_libs"; \ + exit 1; \ + fi .PHONY: check-libs check-libs: ## Run code quality tools for each lib package diff --git a/libs/arcade-cli/arcade_cli/authn.py b/libs/arcade-cli/arcade_cli/authn.py index 301ce399..bd9c18e8 100644 --- a/libs/arcade-cli/arcade_cli/authn.py +++ b/libs/arcade-cli/arcade_cli/authn.py @@ -75,7 +75,7 @@ def _get_default_oauth_timeout_seconds() -> int: DEFAULT_OAUTH_TIMEOUT_SECONDS = _get_default_oauth_timeout_seconds() -def create_oauth_client(cli_config: CLIConfig) -> OAuth2Client: # type: ignore[no-any-unimported] +def create_oauth_client(cli_config: CLIConfig) -> OAuth2Client: """ Create an authlib OAuth2Client configured for the CLI. @@ -92,7 +92,7 @@ def create_oauth_client(cli_config: CLIConfig) -> OAuth2Client: # type: ignore[ ) -def generate_authorization_url( # type: ignore[no-any-unimported] +def generate_authorization_url( client: OAuth2Client, cli_config: CLIConfig, redirect_uri: str, @@ -123,7 +123,7 @@ def generate_authorization_url( # type: ignore[no-any-unimported] return url, code_verifier -def exchange_code_for_tokens( # type: ignore[no-any-unimported] +def exchange_code_for_tokens( client: OAuth2Client, code: str, redirect_uri: str, @@ -321,7 +321,7 @@ class _LoopbackHTTPServer(HTTPServer): def server_bind(self) -> None: socketserver.TCPServer.server_bind(self) host, port = self.server_address[:2] - self.server_name = host + self.server_name = host if isinstance(host, str) else host.decode() self.server_port = port diff --git a/libs/arcade-cli/arcade_cli/connect.py b/libs/arcade-cli/arcade_cli/connect.py index 6099367e..f22d75b9 100644 --- a/libs/arcade-cli/arcade_cli/connect.py +++ b/libs/arcade-cli/arcade_cli/connect.py @@ -6,6 +6,7 @@ import json as _json import logging import time from pathlib import Path +from typing import Any, cast import httpx from arcade_core.constants import PROD_COORDINATOR_HOST, PROD_ENGINE_HOST @@ -55,7 +56,7 @@ def _read_cache(debug: bool = False) -> dict[str, list[str]] | None: return None if debug: console.print(f" [dim]Using cached tool catalog ({age:.0f}s old)[/dim]") - return data.get("toolkits", {}) + return cast("dict[str, list[str]]", data.get("toolkits", {})) except Exception: return None @@ -318,7 +319,7 @@ def list_gateways( return [] data = resp.json() - return data.get("items", []) + return cast("list[dict[Any, Any]]", data.get("items", [])) def find_matching_gateway( @@ -401,13 +402,13 @@ def create_gateway( if resp.status_code not in (200, 201): raise RuntimeError(f"Failed to create gateway ({resp.status_code}): {resp.text}") - data = resp.json() + data: dict[Any, Any] = resp.json() # The API may return the gateway directly or wrapped in a list/items envelope if "slug" in data: return data if data.get("items"): - return data["items"][0] + return cast("dict[Any, Any]", data["items"][0]) if "id" in data: return data @@ -695,13 +696,13 @@ def _resolve_gateway_slug( if gw.get("slug", "").lower() == input_lower: if debug: console.print(f" [dim]Matched by slug: {gw['slug']}[/dim]") - return gw["slug"] + return cast("str", gw["slug"]) for gw in gateways: if gw.get("name", "").lower() == input_lower: slug = gw["slug"] if debug: console.print(f" [dim]Matched by name '{gw['name']}' -> slug: {slug}[/dim]") - return slug + return cast("str", slug) if debug: available = [f"{g.get('name')} ({g.get('slug')})" for g in gateways] console.print(f" [dim]No match for '{user_input}', available: {available}[/dim]") diff --git a/libs/arcade-cli/arcade_cli/main.py b/libs/arcade-cli/arcade_cli/main.py index b1c063d4..ca986c51 100644 --- a/libs/arcade-cli/arcade_cli/main.py +++ b/libs/arcade-cli/arcade_cli/main.py @@ -4,7 +4,7 @@ import os import subprocess import sys from pathlib import Path -from typing import Optional +from typing import Any, Optional import click import typer @@ -334,7 +334,7 @@ def mcp( # window from appearing (e.g. when an MCP client spawns this # command without an attached console). The child process still # inherits stdin/stdout/stderr for stdio transport communication. - run_kwargs: dict[str, object] = {"check": False} + run_kwargs: dict[str, Any] = {"check": False} creation_flags = get_windows_no_window_creationflags() if creation_flags: run_kwargs["creationflags"] = creation_flags diff --git a/libs/arcade-mcp-server/arcade_mcp_server/convert.py b/libs/arcade-mcp-server/arcade_mcp_server/convert.py index 66761842..3bb9451c 100644 --- a/libs/arcade-mcp-server/arcade_mcp_server/convert.py +++ b/libs/arcade-mcp-server/arcade_mcp_server/convert.py @@ -184,7 +184,9 @@ def build_input_schema_from_definition(definition: ToolDefinition) -> dict[str, if getattr(definition, "input", None) and getattr(definition.input, "parameters", None): for param in definition.input.parameters: val_schema = getattr(param, "value_schema", None) - schema = _value_schema_to_json_schema(val_schema) if val_schema else {"type": "string"} + schema: dict[str, Any] = ( + _value_schema_to_json_schema(val_schema) if val_schema else {"type": "string"} + ) if getattr(param, "description", None): schema["description"] = param.description diff --git a/libs/arcade-mcp-server/pyproject.toml b/libs/arcade-mcp-server/pyproject.toml index aae72aa3..42d09559 100644 --- a/libs/arcade-mcp-server/pyproject.toml +++ b/libs/arcade-mcp-server/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "arcade-mcp-server" -version = "1.21.0" +version = "1.21.1" description = "Model Context Protocol (MCP) server framework for Arcade.dev" readme = "README.md" authors = [{ name = "Arcade.dev" }] diff --git a/pyproject.toml b/pyproject.toml index 48d78fe1..9eef8a8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "arcade-mcp" -version = "1.14.0" +version = "1.14.1" description = "Arcade.dev - Tool Calling platform for Agents" readme = "README.md" license = { file = "LICENSE" }