PagerDuty typed OAuth object (#718)

<!-- CURSOR_SUMMARY -->
> [!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.
> 
> <sup>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).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Francisco Liberal <francisco@arcade.dev>
This commit is contained in:
jottakka 2025-12-15 17:42:11 -03:00 committed by GitHub
parent 0fb3b75b8b
commit 7a06bdfa7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 86 additions and 45 deletions

View file

@ -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."""

View file

@ -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",

View file

@ -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",

View file

@ -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"]

View file

@ -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",

View file

@ -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 = [

View file

@ -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):

View file

@ -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,

View file

@ -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"]