From 7a06bdfa7e68749b2fe756c83d20ff72b3397096 Mon Sep 17 00:00:00 2001 From: jottakka Date: Mon, 15 Dec 2025 17:42:11 -0300 Subject: [PATCH] PagerDuty typed OAuth object (#718) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > [!NOTE] > Adds a typed `PagerDuty` OAuth2 provider and wires it through TDK/MCP exports, with tests and coordinated version/dependency bumps. > > - **Auth (core)**: > - Add typed OAuth2 provider `PagerDuty` (`provider_id="pagerduty"`) in `arcade_core/auth.py`. > - **TDK & MCP Server**: > - Re-export `PagerDuty` in `arcade_tdk/auth/__init__.py` and `arcade_mcp_server/auth/__init__.py`. > - **Tests**: > - Extend `test_tool_decorator.py` and `test_create_tool_definition.py` to cover `PagerDuty` success/failure and tool requirement generation. > - **Versioning/Deps**: > - Bump versions: `arcade-core`→`4.1.0`, `arcade-tdk`→`3.4.0`, `arcade-mcp-server`→`1.14.0`, root `arcade-mcp`→`1.7.1`. > - Update dependency ranges to require the bumped versions. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2b60261b1962586ea58831ccb6ea66e57053ac86. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: Francisco Liberal --- libs/arcade-core/arcade_core/auth.py | 9 ++++++ libs/arcade-core/pyproject.toml | 8 ++--- .../arcade_mcp_server/auth/__init__.py | 2 ++ libs/arcade-mcp-server/pyproject.toml | 15 ++++------ libs/arcade-tdk/arcade_tdk/auth/__init__.py | 2 ++ libs/arcade-tdk/pyproject.toml | 13 +++------ libs/tests/sdk/test_tool_decorator.py | 24 ++++++++++++++- .../tests/tool/test_create_tool_definition.py | 29 ++++++++++++++++++- pyproject.toml | 29 +++++++------------ 9 files changed, 86 insertions(+), 45 deletions(-) diff --git a/libs/arcade-core/arcade_core/auth.py b/libs/arcade-core/arcade_core/auth.py index 0ca77d3e..a6b53dc5 100644 --- a/libs/arcade-core/arcade_core/auth.py +++ b/libs/arcade-core/arcade_core/auth.py @@ -150,6 +150,15 @@ class Notion(OAuth2): super().__init__(id=id, scopes=scopes) +class PagerDuty(OAuth2): + """Marks a tool as requiring PagerDuty authorization.""" + + provider_id: str = "pagerduty" + + def __init__(self, *, id: Optional[str] = None, scopes: Optional[list[str]] = None): # noqa: A002 + super().__init__(id=id, scopes=scopes) + + class Reddit(OAuth2): """Marks a tool as requiring Reddit authorization.""" diff --git a/libs/arcade-core/pyproject.toml b/libs/arcade-core/pyproject.toml index 7a8c5f2b..33fecfcb 100644 --- a/libs/arcade-core/pyproject.toml +++ b/libs/arcade-core/pyproject.toml @@ -1,12 +1,10 @@ [project] name = "arcade-core" -version = "4.0.0" +version = "4.1.0" description = "Arcade Core - Core library for Arcade platform" readme = "README.md" -license = {text = "MIT"} -authors = [ - {name = "Arcade", email = "dev@arcade.dev"}, -] +license = { text = "MIT" } +authors = [{ name = "Arcade", email = "dev@arcade.dev" }] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", diff --git a/libs/arcade-mcp-server/arcade_mcp_server/auth/__init__.py b/libs/arcade-mcp-server/arcade_mcp_server/auth/__init__.py index ec01627b..19e0de1a 100644 --- a/libs/arcade-mcp-server/arcade_mcp_server/auth/__init__.py +++ b/libs/arcade-mcp-server/arcade_mcp_server/auth/__init__.py @@ -13,6 +13,7 @@ from arcade_core.auth import ( Microsoft, Notion, OAuth2, + PagerDuty, Reddit, Slack, Spotify, @@ -36,6 +37,7 @@ __all__ = [ "LinkedIn", "Microsoft", "Notion", + "PagerDuty", "OAuth2", "Reddit", "Slack", diff --git a/libs/arcade-mcp-server/pyproject.toml b/libs/arcade-mcp-server/pyproject.toml index 262b21c9..71feef51 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.13.0" +version = "1.14.0" description = "Model Context Protocol (MCP) server framework for Arcade.dev" readme = "README.md" authors = [{ name = "Arcade.dev" }] @@ -21,14 +21,14 @@ classifiers = [ ] requires-python = ">=3.10" dependencies = [ - "arcade-core>=4.0.0,<5.0.0", + "arcade-core>=4.1.0,<5.0.0", "arcade-serve>=3.2.0,<4.0.0", - "arcade-tdk>=3.3.0,<4.0.0", + "arcade-tdk>=3.4.0,<4.0.0", "arcadepy>=1.5.0", "pydantic>=2.0.0", "fastapi>=0.100.0", "uvicorn>=0.30.0", - "watchfiles>=0.18.0", # included with uvicorn, but listed to be explicit + "watchfiles>=0.18.0", # included with uvicorn, but listed to be explicit "sse-starlette>=2.0.0", "starlette>=0.37.0", "anyio>=4.0.0", @@ -39,12 +39,7 @@ dependencies = [ ] [project.optional-dependencies] -dev = [ - "pytest>=8.0.0", - "pytest-asyncio>=0.23.0", - "mypy>=1.0.0", - "ruff>=0.1.0", -] +dev = ["pytest>=8.0.0", "pytest-asyncio>=0.23.0", "mypy>=1.0.0", "ruff>=0.1.0"] [tool.hatch.build.targets.wheel] packages = ["arcade_mcp_server"] diff --git a/libs/arcade-tdk/arcade_tdk/auth/__init__.py b/libs/arcade-tdk/arcade_tdk/auth/__init__.py index 9b66fb98..7432659f 100644 --- a/libs/arcade-tdk/arcade_tdk/auth/__init__.py +++ b/libs/arcade-tdk/arcade_tdk/auth/__init__.py @@ -13,6 +13,7 @@ from arcade_core.auth import ( Microsoft, Notion, OAuth2, + PagerDuty, Reddit, Slack, Spotify, @@ -36,6 +37,7 @@ __all__ = [ "LinkedIn", "Microsoft", "Notion", + "PagerDuty", "OAuth2", "Reddit", "Slack", diff --git a/libs/arcade-tdk/pyproject.toml b/libs/arcade-tdk/pyproject.toml index e8a8e6d2..5dd55831 100644 --- a/libs/arcade-tdk/pyproject.toml +++ b/libs/arcade-tdk/pyproject.toml @@ -1,12 +1,10 @@ [project] name = "arcade-tdk" -version = "3.3.0" +version = "3.4.0" description = "Arcade TDK - Toolkit Development Kit for building Arcade tools" readme = "README.md" -license = {text = "MIT"} -authors = [ - {name = "Arcade", email = "dev@arcade.dev"}, -] +license = { text = "MIT" } +authors = [{ name = "Arcade", email = "dev@arcade.dev" }] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -18,10 +16,7 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] requires-python = ">=3.10" -dependencies = [ - "arcade-core>=4.0.0,<5.0.0", - "pydantic>=2.7.0", -] +dependencies = ["arcade-core>=4.1.0,<5.0.0", "pydantic>=2.7.0"] [project.optional-dependencies] dev = [ diff --git a/libs/tests/sdk/test_tool_decorator.py b/libs/tests/sdk/test_tool_decorator.py index 0a3542b3..6d134dda 100644 --- a/libs/tests/sdk/test_tool_decorator.py +++ b/libs/tests/sdk/test_tool_decorator.py @@ -3,7 +3,7 @@ import asyncio import pytest from arcade_core.auth import AuthProviderType, Google from arcade_tdk import tool -from arcade_tdk.auth import OAuth2 +from arcade_tdk.auth import OAuth2, PagerDuty def test_sync_function(): @@ -50,6 +50,13 @@ async def test_async_function(): "google", "my_google_provider123", ), + (PagerDuty, {"scopes": ["test_scope", "another.scope"]}, "pagerduty", None), + ( + PagerDuty, + {"id": "my_pagerduty_provider123", "scopes": ["test_scope", "another.scope"]}, + "pagerduty", + "my_pagerduty_provider123", + ), ], ) def test_tool_decorator_with_auth_success( @@ -102,6 +109,21 @@ def test_tool_decorator_with_auth_success( "scopes": ["test_scope", "another.scope"], }, ), + ( + PagerDuty, + { + "provider_id": "my_example_provider_id_123", + "scopes": ["test_scope", "another.scope"], + }, + ), + ( + PagerDuty, + { + "provider_id": "my_example_provider_id_123", + "id": "my_example_id_123", + "scopes": ["test_scope", "another.scope"], + }, + ), ], ) def test_tool_decorator_with_auth_failure(auth_class, auth_kwargs): diff --git a/libs/tests/tool/test_create_tool_definition.py b/libs/tests/tool/test_create_tool_definition.py index 26ed6a74..8113fa6b 100644 --- a/libs/tests/tool/test_create_tool_definition.py +++ b/libs/tests/tool/test_create_tool_definition.py @@ -19,7 +19,7 @@ from arcade_core.schema import ( from arcade_core.utils import snake_to_pascal_case from arcade_tdk import tool from arcade_tdk.annotations import Inferrable -from arcade_tdk.auth import Figma, GitHub, Google, OAuth2, Slack, X +from arcade_tdk.auth import Figma, GitHub, Google, OAuth2, PagerDuty, Slack, X ### Tests on @tool decorator @@ -159,6 +159,17 @@ def func_with_x_requirement(): pass +@tool( + desc="A function that requires PagerDuty authorization", + requires_auth=PagerDuty( + id="my_pagerduty_provider123", + scopes=["read", "write"], + ), +) +def func_with_pagerduty_auth_requirement(): + pass + + ### Tests on input params @tool(desc="A function with a non-inferrable input parameter") def func_with_non_inferrable_param(param1: Annotated[str, "First param", Inferrable(False)]): @@ -507,6 +518,22 @@ def func_with_complex_return() -> dict[str, str]: ) }, ), + pytest.param( + func_with_pagerduty_auth_requirement, + { + "requirements": ToolRequirements( + authorization=ToolAuthRequirement( + provider_id="pagerduty", + provider_type="oauth2", + id="my_pagerduty_provider123", + oauth2=OAuth2Requirement( + scopes=["read", "write"], + ), + ) + ) + }, + id="func_with_pagerduty_auth_requirement", + ), # Tests on input params pytest.param( func_with_non_inferrable_param, diff --git a/pyproject.toml b/pyproject.toml index 3330f457..b7cd782e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,10 @@ [project] name = "arcade-mcp" -version = "1.7.0" +version = "1.7.1" description = "Arcade.dev - Tool Calling platform for Agents" readme = "README.md" -license = {file = "LICENSE"} -authors = [ - {name = "Arcade", email = "dev@arcade.dev"}, -] +license = { file = "LICENSE" } +authors = [{ name = "Arcade", email = "dev@arcade.dev" }] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -21,8 +19,8 @@ requires-python = ">=3.10" dependencies = [ # CLI dependencies - "arcade-mcp-server>=1.13.0,<2.0.0", - "arcade-core>=4.0.0,<5.0.0", + "arcade-mcp-server>=1.14.0,<2.0.0", + "arcade-core>=4.1.0,<5.0.0", "typer==0.10.0", "rich>=14.0.0,<15.0.0", "Jinja2==3.1.6", @@ -43,11 +41,11 @@ all = [ "pytz>=2024.1", "python-dateutil>=2.8.2", # mcp - "arcade-mcp-server>=1.13.0,<2.0.0", + "arcade-mcp-server>=1.14.0,<2.0.0", # serve "arcade-serve>=3.2.0,<4.0.0", # tdk - "arcade-tdk>=3.3.0,<4.0.0", + "arcade-tdk>=3.4.0,<4.0.0", ] # Evals also depends on arcade-core and openai, but they are already required deps evals = [ @@ -89,10 +87,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = [ - "libs/arcade-cli/arcade_cli", - "libs/arcade-evals/arcade_evals", -] +packages = ["libs/arcade-cli/arcade_cli", "libs/arcade-evals/arcade_evals"] [tool.uv.workspace] members = [ @@ -113,7 +108,7 @@ warn_unused_ignores = true show_error_codes = true ignore_missing_imports = true exclude = [ - '.*{{.*}}.*' # Ignore files that have names that use Jinja template syntax + '.*{{.*}}.*', # Ignore files that have names that use Jinja template syntax ] [tool.pytest.ini_options] @@ -133,11 +128,7 @@ addopts = [ [tool.coverage.run] source = ["libs"] -omit = [ - "*/tests/*", - "*/test_*", - "*/__pycache__/*", -] +omit = ["*/tests/*", "*/test_*", "*/__pycache__/*"] parallel = true patch = ["subprocess"]