github-agent 0.31.0__tar.gz → 0.33.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {github_agent-0.31.0 → github_agent-0.33.0}/PKG-INFO +3 -3
- {github_agent-0.31.0 → github_agent-0.33.0}/README.md +1 -1
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/agent_server.py +1 -1
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_base.py +60 -3
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/github_input_models.py +7 -2
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_action.py +72 -13
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_branch.py +26 -5
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_collaborator.py +21 -5
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_commit.py +13 -2
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_content.py +16 -4
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_issue.py +29 -7
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_org.py +45 -15
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_pull.py +33 -8
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_release.py +34 -9
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_repo.py +75 -13
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/mcp_search.py +12 -3
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp_server.py +342 -89
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/PKG-INFO +3 -3
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/SOURCES.txt +2 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/requires.txt +1 -1
- {github_agent-0.31.0 → github_agent-0.33.0}/pyproject.toml +2 -2
- github_agent-0.33.0/tests/test_action_discovery.py +87 -0
- github_agent-0.33.0/tests/test_hardening.py +118 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_mcp_coverage.py +35 -42
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_pages.py +1 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/LICENSE +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/__init__.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/__main__.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/__init__.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_branches.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_commits.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_contents.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_issues.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_orgs.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_pages.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_pulls.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_releases.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_repos.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_search.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api/api_client_workflows.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/api_client.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/auth.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/github_response_models.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp/__init__.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent/mcp_config.json +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/dependency_links.txt +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/entry_points.txt +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/github_agent.egg-info/top_level.txt +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/scripts/security_sanitizer.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/scripts/validate_a2a_agent.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/scripts/verify_api_integration.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/setup.cfg +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/conftest.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_api_client_endpoints.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_api_validation.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_auth_client_edge_cases.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_concept_parity.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_github_agent_api_brute_force_coverage.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_github_agent_brute_force_coverage.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_init_dynamics.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_model_fields.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_org_crud.py +0 -0
- {github_agent-0.31.0 → github_agent-0.33.0}/tests/test_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-agent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.33.0
|
|
4
4
|
Summary: GitHub Agent for MCP
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: <3.15,>=3.11
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-utilities[agent,logfire]>=0.
|
|
15
|
+
Requires-Dist: agent-utilities[agent,logfire]>=0.51.0
|
|
16
16
|
Provides-Extra: test
|
|
17
17
|
Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
|
|
18
18
|
Requires-Dist: pytest; extra == "test"
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|

|
|
42
42
|

|
|
43
43
|
|
|
44
|
-
*Version: 0.
|
|
44
|
+
*Version: 0.33.0*
|
|
45
45
|
|
|
46
46
|
> **Documentation** — Installation, deployment, and usage across the MCP, API, and
|
|
47
47
|
> CLI interfaces, including the integrated A2A agent server, are maintained in the
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|

|
|
21
21
|

|
|
22
22
|
|
|
23
|
-
*Version: 0.
|
|
23
|
+
*Version: 0.33.0*
|
|
24
24
|
|
|
25
25
|
> **Documentation** — Installation, deployment, and usage across the MCP, API, and
|
|
26
26
|
> CLI interfaces, including the integrated A2A agent server, are maintained in the
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
import logging
|
|
3
|
+
import os
|
|
3
4
|
import re
|
|
5
|
+
from collections.abc import Mapping
|
|
4
6
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
5
7
|
from typing import TypeVar
|
|
6
8
|
|
|
@@ -18,6 +20,52 @@ logger = get_logger(__name__)
|
|
|
18
20
|
T = TypeVar("T", bound=BaseModel)
|
|
19
21
|
|
|
20
22
|
|
|
23
|
+
def _default_timeout() -> tuple[float, float]:
|
|
24
|
+
"""(connect, read) timeout for every outbound request, env-overridable.
|
|
25
|
+
|
|
26
|
+
A bounded timeout stops a single slow GitHub response from hanging an async
|
|
27
|
+
handler up to the gateway's 300s and wedging the whole server for every
|
|
28
|
+
concurrent caller (the failure mode behind stuck in-flight calls and child
|
|
29
|
+
restarts). Override with GITHUB_HTTP_CONNECT_TIMEOUT / GITHUB_HTTP_READ_TIMEOUT.
|
|
30
|
+
"""
|
|
31
|
+
connect = float(os.getenv("GITHUB_HTTP_CONNECT_TIMEOUT", "10"))
|
|
32
|
+
read = float(os.getenv("GITHUB_HTTP_READ_TIMEOUT", "30"))
|
|
33
|
+
return (connect, read)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _TimeoutAdapter(requests.adapters.HTTPAdapter):
|
|
37
|
+
"""HTTPAdapter that applies a default timeout when a request sets none.
|
|
38
|
+
|
|
39
|
+
Mounted on the session rather than subclassing Session, so test suites that
|
|
40
|
+
replace ``requests.Session`` with a mock are unaffected (``mount`` is a no-op
|
|
41
|
+
on a mock) while real requests still get a bounded timeout.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, timeout: tuple[float, float], *args, **kwargs):
|
|
45
|
+
self._timeout = timeout
|
|
46
|
+
super().__init__(*args, **kwargs)
|
|
47
|
+
|
|
48
|
+
def send(
|
|
49
|
+
self,
|
|
50
|
+
request: requests.PreparedRequest,
|
|
51
|
+
stream: bool = False,
|
|
52
|
+
timeout: None | float | tuple[float, float] | tuple[float, None] = None,
|
|
53
|
+
verify: bool | str = True,
|
|
54
|
+
cert: None | bytes | str | tuple[bytes | str, bytes | str] = None,
|
|
55
|
+
proxies: Mapping[str, str] | None = None,
|
|
56
|
+
) -> requests.Response:
|
|
57
|
+
if timeout is None:
|
|
58
|
+
timeout = self._timeout
|
|
59
|
+
return super().send(
|
|
60
|
+
request,
|
|
61
|
+
stream=stream,
|
|
62
|
+
timeout=timeout,
|
|
63
|
+
verify=verify,
|
|
64
|
+
cert=cert,
|
|
65
|
+
proxies=proxies,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
21
69
|
class BaseApiClient:
|
|
22
70
|
def __init__(
|
|
23
71
|
self,
|
|
@@ -36,6 +84,9 @@ class BaseApiClient:
|
|
|
36
84
|
raise MissingParameterError
|
|
37
85
|
|
|
38
86
|
self._session = requests.Session()
|
|
87
|
+
_adapter = _TimeoutAdapter(_default_timeout())
|
|
88
|
+
self._session.mount("https://", _adapter)
|
|
89
|
+
self._session.mount("http://", _adapter)
|
|
39
90
|
self.url = url.rstrip("/")
|
|
40
91
|
self.headers = {
|
|
41
92
|
"Accept": "application/vnd.github+json",
|
|
@@ -119,10 +170,16 @@ class BaseApiClient:
|
|
|
119
170
|
|
|
120
171
|
total_pages = self._get_total_pages(response)
|
|
121
172
|
|
|
122
|
-
|
|
123
|
-
|
|
173
|
+
# Bounded by default: an unset max_pages fetches only the first page so a
|
|
174
|
+
# single list call can't pull an entire org/run-history (the cause of
|
|
175
|
+
# multi-hundred-KB responses and gateway timeouts). Callers opt into more
|
|
176
|
+
# by passing max_pages (use max_pages<=0 to mean "all pages").
|
|
177
|
+
max_pages = getattr(model, "max_pages", None)
|
|
178
|
+
if max_pages is None:
|
|
179
|
+
max_pages = 1
|
|
180
|
+
elif max_pages <= 0 or max_pages > total_pages:
|
|
124
181
|
max_pages = total_pages
|
|
125
|
-
|
|
182
|
+
model.max_pages = max_pages # type: ignore[attr-defined]
|
|
126
183
|
|
|
127
184
|
if max_pages > 1:
|
|
128
185
|
with ThreadPoolExecutor(max_workers=5) as executor:
|
|
@@ -14,10 +14,15 @@ class BaseModelWrapper(BaseModel):
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
max_pages: int | None = Field(
|
|
17
|
-
description=
|
|
17
|
+
description=(
|
|
18
|
+
"Max number of pages to retrieve. Unset (default) fetches only the "
|
|
19
|
+
"first page to keep responses small; pass a number for more, or "
|
|
20
|
+
"max_pages<=0 to fetch all pages."
|
|
21
|
+
),
|
|
22
|
+
default=None,
|
|
18
23
|
)
|
|
19
24
|
page: int | None = Field(description="Pagination page", default=1)
|
|
20
|
-
per_page: int | None = Field(description="Results per page", default=
|
|
25
|
+
per_page: int | None = Field(description="Results per page (1-100)", default=30)
|
|
21
26
|
api_parameters: dict[str, Any] = Field(
|
|
22
27
|
description="API Parameters", default_factory=dict
|
|
23
28
|
)
|
|
@@ -3,12 +3,44 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Exact keys dropped by _slim (pure hypermedia/noise, never semantic data).
|
|
14
|
+
_SLIM_DROP_EXACT = {"_links", "url", "node_id"}
|
|
15
|
+
|
|
16
|
+
#: Valid workflow actions for the shared ``resolve_action`` discovery helper.
|
|
17
|
+
WORKFLOW_ACTIONS = (
|
|
18
|
+
"list_workflows",
|
|
19
|
+
"list_runs",
|
|
20
|
+
"get_run",
|
|
21
|
+
"trigger_dispatch",
|
|
22
|
+
"rerun",
|
|
23
|
+
"cancel",
|
|
24
|
+
"delete_run",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _slim(obj):
|
|
29
|
+
"""Recursively drop hypermedia ``*_url`` hrefs and ``_links`` noise.
|
|
30
|
+
|
|
31
|
+
Mirror of ``mcp_server._slim``; see that module for rationale.
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(obj, list):
|
|
34
|
+
return [_slim(item) for item in obj]
|
|
35
|
+
if isinstance(obj, dict):
|
|
36
|
+
return {
|
|
37
|
+
k: _slim(v)
|
|
38
|
+
for k, v in obj.items()
|
|
39
|
+
if k not in _SLIM_DROP_EXACT
|
|
40
|
+
and not (k.endswith("_url") and k != "html_url")
|
|
41
|
+
}
|
|
42
|
+
return obj
|
|
43
|
+
|
|
12
44
|
|
|
13
45
|
def register_action_tools(mcp: FastMCP):
|
|
14
46
|
@mcp.tool(tags={"actions"})
|
|
@@ -24,7 +56,15 @@ def register_action_tools(mcp: FastMCP):
|
|
|
24
56
|
default=None, description="MCP context for progress reporting"
|
|
25
57
|
),
|
|
26
58
|
) -> dict:
|
|
27
|
-
"""Manage GitHub actions workflows and runs.
|
|
59
|
+
"""Manage GitHub actions workflows and runs.
|
|
60
|
+
|
|
61
|
+
list_runs params (via params_json): owner, repo, and optional filters
|
|
62
|
+
applied server-side to keep results small — status (e.g. failure,
|
|
63
|
+
success, completed, in_progress), branch, per_page (1-100, default 30),
|
|
64
|
+
max_pages (default 1 page; max_pages<=0 = all pages), slim (default
|
|
65
|
+
true: drops hypermedia *_url/_links noise, keeps html_url and all data).
|
|
66
|
+
Prefer status=failure + branch=<default> for a CI-health sweep.
|
|
67
|
+
"""
|
|
28
68
|
if ctx:
|
|
29
69
|
await ctx.info("Executing github_actions action...")
|
|
30
70
|
import json
|
|
@@ -35,6 +75,12 @@ def register_action_tools(mcp: FastMCP):
|
|
|
35
75
|
return {"status": 400, "error": f"Invalid params_json: {e}", "data": None}
|
|
36
76
|
|
|
37
77
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
78
|
+
slim = kwargs.pop("slim", True)
|
|
79
|
+
|
|
80
|
+
resolved = resolve_action(action, WORKFLOW_ACTIONS, service="github-agent")
|
|
81
|
+
if isinstance(resolved, dict):
|
|
82
|
+
return resolved
|
|
83
|
+
action = resolved
|
|
38
84
|
|
|
39
85
|
try:
|
|
40
86
|
if action == "list_workflows":
|
|
@@ -46,18 +92,21 @@ def register_action_tools(mcp: FastMCP):
|
|
|
46
92
|
"error": "Missing required 'owner' or 'repo' parameter",
|
|
47
93
|
"data": None,
|
|
48
94
|
}
|
|
49
|
-
response =
|
|
95
|
+
response = await run_blocking(
|
|
96
|
+
client.get_workflows, owner=owner, repo=repo
|
|
97
|
+
)
|
|
50
98
|
return {
|
|
51
99
|
"status": 200,
|
|
52
100
|
"message": "Workflows retrieved successfully",
|
|
53
101
|
"data": [w.model_dump() for w in response.data],
|
|
54
102
|
}
|
|
55
103
|
elif action == "list_runs":
|
|
56
|
-
response = client.get_workflow_runs
|
|
104
|
+
response = await run_blocking(client.get_workflow_runs, **kwargs)
|
|
105
|
+
data = [r.model_dump() for r in response.data]
|
|
57
106
|
return {
|
|
58
107
|
"status": 200,
|
|
59
108
|
"message": "Workflow runs retrieved successfully",
|
|
60
|
-
"data":
|
|
109
|
+
"data": _slim(data) if slim else data,
|
|
61
110
|
}
|
|
62
111
|
elif action == "get_run":
|
|
63
112
|
owner = kwargs.get("owner")
|
|
@@ -69,8 +118,8 @@ def register_action_tools(mcp: FastMCP):
|
|
|
69
118
|
"error": "Missing required 'owner', 'repo', or 'run_id' parameter",
|
|
70
119
|
"data": None,
|
|
71
120
|
}
|
|
72
|
-
response =
|
|
73
|
-
owner=owner, repo=repo, run_id=int(run_id)
|
|
121
|
+
response = await run_blocking(
|
|
122
|
+
client.get_workflow_run, owner=owner, repo=repo, run_id=int(run_id)
|
|
74
123
|
)
|
|
75
124
|
return {
|
|
76
125
|
"status": 200,
|
|
@@ -89,7 +138,8 @@ def register_action_tools(mcp: FastMCP):
|
|
|
89
138
|
"error": "Missing 'owner', 'repo', 'workflow_id', or 'ref' parameter",
|
|
90
139
|
"data": None,
|
|
91
140
|
}
|
|
92
|
-
response =
|
|
141
|
+
response = await run_blocking(
|
|
142
|
+
client.trigger_workflow_dispatch,
|
|
93
143
|
owner=owner,
|
|
94
144
|
repo=repo,
|
|
95
145
|
workflow_id=workflow_id,
|
|
@@ -111,8 +161,11 @@ def register_action_tools(mcp: FastMCP):
|
|
|
111
161
|
"error": "Missing 'owner', 'repo', or 'run_id' parameter",
|
|
112
162
|
"data": None,
|
|
113
163
|
}
|
|
114
|
-
response =
|
|
115
|
-
|
|
164
|
+
response = await run_blocking(
|
|
165
|
+
client.rerun_workflow_run,
|
|
166
|
+
owner=owner,
|
|
167
|
+
repo=repo,
|
|
168
|
+
run_id=int(run_id),
|
|
116
169
|
)
|
|
117
170
|
return {
|
|
118
171
|
"status": 200,
|
|
@@ -129,8 +182,11 @@ def register_action_tools(mcp: FastMCP):
|
|
|
129
182
|
"error": "Missing 'owner', 'repo', or 'run_id' parameter",
|
|
130
183
|
"data": None,
|
|
131
184
|
}
|
|
132
|
-
response =
|
|
133
|
-
|
|
185
|
+
response = await run_blocking(
|
|
186
|
+
client.cancel_workflow_run,
|
|
187
|
+
owner=owner,
|
|
188
|
+
repo=repo,
|
|
189
|
+
run_id=int(run_id),
|
|
134
190
|
)
|
|
135
191
|
return {
|
|
136
192
|
"status": 200,
|
|
@@ -147,8 +203,11 @@ def register_action_tools(mcp: FastMCP):
|
|
|
147
203
|
"error": "Missing 'owner', 'repo', or 'run_id' parameter",
|
|
148
204
|
"data": None,
|
|
149
205
|
}
|
|
150
|
-
response =
|
|
151
|
-
|
|
206
|
+
response = await run_blocking(
|
|
207
|
+
client.delete_workflow_run,
|
|
208
|
+
owner=owner,
|
|
209
|
+
repo=repo,
|
|
210
|
+
run_id=int(run_id),
|
|
152
211
|
)
|
|
153
212
|
return {
|
|
154
213
|
"status": 200,
|
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Valid branch actions for the shared ``resolve_action`` discovery helper.
|
|
14
|
+
BRANCH_ACTIONS = (
|
|
15
|
+
"list",
|
|
16
|
+
"get",
|
|
17
|
+
"create",
|
|
18
|
+
"delete",
|
|
19
|
+
"get_protection",
|
|
20
|
+
"update_protection",
|
|
21
|
+
"delete_protection",
|
|
22
|
+
)
|
|
23
|
+
|
|
12
24
|
|
|
13
25
|
def register_branch_tools(mcp: FastMCP):
|
|
14
26
|
@mcp.tool(tags={"branches"})
|
|
@@ -36,9 +48,14 @@ def register_branch_tools(mcp: FastMCP):
|
|
|
36
48
|
|
|
37
49
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
38
50
|
|
|
51
|
+
resolved = resolve_action(action, BRANCH_ACTIONS, service="github-agent")
|
|
52
|
+
if isinstance(resolved, dict):
|
|
53
|
+
return resolved
|
|
54
|
+
action = resolved
|
|
55
|
+
|
|
39
56
|
try:
|
|
40
57
|
if action == "list":
|
|
41
|
-
response = client.get_branches
|
|
58
|
+
response = await run_blocking(client.get_branches, **kwargs)
|
|
42
59
|
return {
|
|
43
60
|
"status": 200,
|
|
44
61
|
"message": "Branches retrieved successfully",
|
|
@@ -54,7 +71,9 @@ def register_branch_tools(mcp: FastMCP):
|
|
|
54
71
|
"error": "Missing 'owner', 'repo', or 'branch' parameter",
|
|
55
72
|
"data": None,
|
|
56
73
|
}
|
|
57
|
-
response =
|
|
74
|
+
response = await run_blocking(
|
|
75
|
+
client.get_branch, owner=owner, repo=repo, branch=branch
|
|
76
|
+
)
|
|
58
77
|
return {
|
|
59
78
|
"status": 200,
|
|
60
79
|
"message": "Branch retrieved successfully",
|
|
@@ -71,8 +90,8 @@ def register_branch_tools(mcp: FastMCP):
|
|
|
71
90
|
"error": "Missing 'owner', 'repo', 'branch', or 'ref' parameter",
|
|
72
91
|
"data": None,
|
|
73
92
|
}
|
|
74
|
-
response =
|
|
75
|
-
owner=owner, repo=repo, branch=branch, ref=ref
|
|
93
|
+
response = await run_blocking(
|
|
94
|
+
client.create_branch, owner=owner, repo=repo, branch=branch, ref=ref
|
|
76
95
|
)
|
|
77
96
|
return {
|
|
78
97
|
"status": 201,
|
|
@@ -89,7 +108,9 @@ def register_branch_tools(mcp: FastMCP):
|
|
|
89
108
|
"error": "Missing 'owner', 'repo', or 'branch' parameter",
|
|
90
109
|
"data": None,
|
|
91
110
|
}
|
|
92
|
-
response =
|
|
111
|
+
response = await run_blocking(
|
|
112
|
+
client.delete_branch, owner=owner, repo=repo, branch=branch
|
|
113
|
+
)
|
|
93
114
|
return {
|
|
94
115
|
"status": 200,
|
|
95
116
|
"message": "Branch deleted successfully",
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Valid collaborator actions for the shared ``resolve_action`` discovery helper.
|
|
14
|
+
COLLABORATOR_ACTIONS = ("list", "add", "remove")
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def register_collaborator_tools(mcp: FastMCP):
|
|
14
18
|
@mcp.tool(tags={"collaborators"})
|
|
@@ -36,9 +40,14 @@ def register_collaborator_tools(mcp: FastMCP):
|
|
|
36
40
|
|
|
37
41
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
38
42
|
|
|
43
|
+
resolved = resolve_action(action, COLLABORATOR_ACTIONS, service="github-agent")
|
|
44
|
+
if isinstance(resolved, dict):
|
|
45
|
+
return resolved
|
|
46
|
+
action = resolved
|
|
47
|
+
|
|
39
48
|
try:
|
|
40
49
|
if action == "list":
|
|
41
|
-
response = client.get_collaborators
|
|
50
|
+
response = await run_blocking(client.get_collaborators, **kwargs)
|
|
42
51
|
return {
|
|
43
52
|
"status": 200,
|
|
44
53
|
"message": "Collaborators retrieved successfully",
|
|
@@ -55,8 +64,12 @@ def register_collaborator_tools(mcp: FastMCP):
|
|
|
55
64
|
"error": "Missing 'owner', 'repo', or 'username' parameter",
|
|
56
65
|
"data": None,
|
|
57
66
|
}
|
|
58
|
-
response =
|
|
59
|
-
|
|
67
|
+
response = await run_blocking(
|
|
68
|
+
client.add_collaborator,
|
|
69
|
+
owner=owner,
|
|
70
|
+
repo=repo,
|
|
71
|
+
username=username,
|
|
72
|
+
permission=permission,
|
|
60
73
|
)
|
|
61
74
|
return {
|
|
62
75
|
"status": 200,
|
|
@@ -73,8 +86,11 @@ def register_collaborator_tools(mcp: FastMCP):
|
|
|
73
86
|
"error": "Missing 'owner', 'repo', or 'username' parameter",
|
|
74
87
|
"data": None,
|
|
75
88
|
}
|
|
76
|
-
response =
|
|
77
|
-
|
|
89
|
+
response = await run_blocking(
|
|
90
|
+
client.remove_collaborator,
|
|
91
|
+
owner=owner,
|
|
92
|
+
repo=repo,
|
|
93
|
+
username=username,
|
|
78
94
|
)
|
|
79
95
|
return {
|
|
80
96
|
"status": 200,
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Valid commit actions for the shared ``resolve_action`` discovery helper.
|
|
14
|
+
COMMIT_ACTIONS = ("list", "get")
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def register_commit_tools(mcp: FastMCP):
|
|
14
18
|
@mcp.tool(tags={"commits"})
|
|
@@ -36,9 +40,14 @@ def register_commit_tools(mcp: FastMCP):
|
|
|
36
40
|
|
|
37
41
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
38
42
|
|
|
43
|
+
resolved = resolve_action(action, COMMIT_ACTIONS, service="github-agent")
|
|
44
|
+
if isinstance(resolved, dict):
|
|
45
|
+
return resolved
|
|
46
|
+
action = resolved
|
|
47
|
+
|
|
39
48
|
try:
|
|
40
49
|
if action == "list":
|
|
41
|
-
response = client.get_commits
|
|
50
|
+
response = await run_blocking(client.get_commits, **kwargs)
|
|
42
51
|
return {
|
|
43
52
|
"status": 200,
|
|
44
53
|
"message": "Commits retrieved successfully",
|
|
@@ -54,7 +63,9 @@ def register_commit_tools(mcp: FastMCP):
|
|
|
54
63
|
"error": "Missing 'owner', 'repo', or 'sha' parameter",
|
|
55
64
|
"data": None,
|
|
56
65
|
}
|
|
57
|
-
response =
|
|
66
|
+
response = await run_blocking(
|
|
67
|
+
client.get_commit, owner=owner, repo=repo, sha=sha
|
|
68
|
+
)
|
|
58
69
|
return {
|
|
59
70
|
"status": 200,
|
|
60
71
|
"message": "Commit retrieved successfully",
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Valid content actions for the shared ``resolve_action`` discovery helper.
|
|
14
|
+
CONTENT_ACTIONS = ("get", "create", "update", "delete")
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def register_content_tools(mcp: FastMCP):
|
|
14
18
|
@mcp.tool(tags={"contents"})
|
|
@@ -36,9 +40,14 @@ def register_content_tools(mcp: FastMCP):
|
|
|
36
40
|
|
|
37
41
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
38
42
|
|
|
43
|
+
resolved = resolve_action(action, CONTENT_ACTIONS, service="github-agent")
|
|
44
|
+
if isinstance(resolved, dict):
|
|
45
|
+
return resolved
|
|
46
|
+
action = resolved
|
|
47
|
+
|
|
39
48
|
try:
|
|
40
49
|
if action == "get":
|
|
41
|
-
response = client.get_contents
|
|
50
|
+
response = await run_blocking(client.get_contents, **kwargs)
|
|
42
51
|
if isinstance(response.data, list):
|
|
43
52
|
data = [item.model_dump() for item in response.data]
|
|
44
53
|
else:
|
|
@@ -60,7 +69,8 @@ def register_content_tools(mcp: FastMCP):
|
|
|
60
69
|
"error": "Missing 'owner', 'repo', 'path', 'message', or 'content' parameter",
|
|
61
70
|
"data": None,
|
|
62
71
|
}
|
|
63
|
-
response =
|
|
72
|
+
response = await run_blocking(
|
|
73
|
+
client.create_content,
|
|
64
74
|
owner=owner,
|
|
65
75
|
repo=repo,
|
|
66
76
|
path=path,
|
|
@@ -93,7 +103,8 @@ def register_content_tools(mcp: FastMCP):
|
|
|
93
103
|
"error": "Missing 'owner', 'repo', 'path', 'message', 'content', or 'sha' parameter",
|
|
94
104
|
"data": None,
|
|
95
105
|
}
|
|
96
|
-
response =
|
|
106
|
+
response = await run_blocking(
|
|
107
|
+
client.update_content,
|
|
97
108
|
owner=owner,
|
|
98
109
|
repo=repo,
|
|
99
110
|
path=path,
|
|
@@ -119,7 +130,8 @@ def register_content_tools(mcp: FastMCP):
|
|
|
119
130
|
"error": "Missing 'owner', 'repo', 'path', 'message', or 'sha' parameter",
|
|
120
131
|
"data": None,
|
|
121
132
|
}
|
|
122
|
-
response =
|
|
133
|
+
response = await run_blocking(
|
|
134
|
+
client.delete_content,
|
|
123
135
|
owner=owner,
|
|
124
136
|
repo=repo,
|
|
125
137
|
path=path,
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
Auto-generated from mcp_server.py during ecosystem standardization.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from agent_utilities.mcp_utilities import resolve_action, run_blocking
|
|
6
7
|
from fastmcp import Context, FastMCP
|
|
7
8
|
from fastmcp.dependencies import Depends
|
|
8
9
|
from pydantic import Field
|
|
9
10
|
|
|
10
11
|
from github_agent.auth import get_client
|
|
11
12
|
|
|
13
|
+
#: Valid issue actions for the shared ``resolve_action`` discovery helper.
|
|
14
|
+
ISSUE_ACTIONS = ("list", "get", "create", "update")
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def register_issue_tools(mcp: FastMCP):
|
|
14
18
|
@mcp.tool(tags={"issues"})
|
|
@@ -24,7 +28,14 @@ def register_issue_tools(mcp: FastMCP):
|
|
|
24
28
|
default=None, description="MCP context for progress reporting"
|
|
25
29
|
),
|
|
26
30
|
) -> dict:
|
|
27
|
-
"""Manage GitHub issues.
|
|
31
|
+
"""Manage GitHub issues.
|
|
32
|
+
|
|
33
|
+
list params (via params_json): owner, repo, and optional filters applied
|
|
34
|
+
server-side — state (open/closed/all), labels, assignee, since, per_page
|
|
35
|
+
(1-100, default 30), max_pages (default 1 page; max_pages<=0 = all pages).
|
|
36
|
+
Note: the list/search APIs return PRs alongside issues — a returned item
|
|
37
|
+
with a 'pull_request' field is a PR, not an issue.
|
|
38
|
+
"""
|
|
28
39
|
if ctx:
|
|
29
40
|
await ctx.info("Executing github_issues action...")
|
|
30
41
|
import json
|
|
@@ -36,9 +47,14 @@ def register_issue_tools(mcp: FastMCP):
|
|
|
36
47
|
|
|
37
48
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
38
49
|
|
|
50
|
+
resolved = resolve_action(action, ISSUE_ACTIONS, service="github-agent")
|
|
51
|
+
if isinstance(resolved, dict):
|
|
52
|
+
return resolved
|
|
53
|
+
action = resolved
|
|
54
|
+
|
|
39
55
|
try:
|
|
40
56
|
if action == "list":
|
|
41
|
-
response = client.get_issues
|
|
57
|
+
response = await run_blocking(client.get_issues, **kwargs)
|
|
42
58
|
return {
|
|
43
59
|
"status": 200,
|
|
44
60
|
"message": "Issues retrieved successfully",
|
|
@@ -54,7 +70,9 @@ def register_issue_tools(mcp: FastMCP):
|
|
|
54
70
|
"error": "Missing 'owner', 'repo', or 'number' parameter",
|
|
55
71
|
"data": None,
|
|
56
72
|
}
|
|
57
|
-
response =
|
|
73
|
+
response = await run_blocking(
|
|
74
|
+
client.get_issue, owner=owner, repo=repo, number=int(number)
|
|
75
|
+
)
|
|
58
76
|
return {
|
|
59
77
|
"status": 200,
|
|
60
78
|
"message": "Issue retrieved successfully",
|
|
@@ -70,8 +88,8 @@ def register_issue_tools(mcp: FastMCP):
|
|
|
70
88
|
"error": "Missing 'owner', 'repo', or 'title' parameter",
|
|
71
89
|
"data": None,
|
|
72
90
|
}
|
|
73
|
-
response =
|
|
74
|
-
owner=owner, repo=repo, title=title, **kwargs
|
|
91
|
+
response = await run_blocking(
|
|
92
|
+
client.create_issue, owner=owner, repo=repo, title=title, **kwargs
|
|
75
93
|
)
|
|
76
94
|
return {
|
|
77
95
|
"status": 201,
|
|
@@ -88,8 +106,12 @@ def register_issue_tools(mcp: FastMCP):
|
|
|
88
106
|
"error": "Missing 'owner', 'repo', or 'number' parameter",
|
|
89
107
|
"data": None,
|
|
90
108
|
}
|
|
91
|
-
response =
|
|
92
|
-
|
|
109
|
+
response = await run_blocking(
|
|
110
|
+
client.update_issue,
|
|
111
|
+
owner=owner,
|
|
112
|
+
repo=repo,
|
|
113
|
+
number=int(number),
|
|
114
|
+
**kwargs,
|
|
93
115
|
)
|
|
94
116
|
return {
|
|
95
117
|
"status": 200,
|