Skip to content

Commit 6b281db

Browse files
MementoRCclaude
andcommitted
fix: register GitHub Issues tools in MCP server - CRITICAL GAP FIXED
MAJOR FIX: GitHub Issues tools were implemented but not registered as MCP tools Root Cause: ServerApplication.list_tools() only registered Git tools, completely missing GitHub tools despite handlers existing in core/handlers.py Changes: - Add GitHubTools enum with 9 tool definitions - Add Pydantic models for all GitHub tool parameters - Register 9 GitHub tools in list_tools(): create_issue, list_issues, update_issue, get_pr_checks, get_pr_details, list_pull_requests, get_pr_status, get_pr_files, edit_pr_description - Add GitHub tool handlers in call_tool() with proper async/await - Import GitHub API functions dynamically for each tool call Impact: GitHub Issues functionality now accessible via MCP protocol Quality: Syntax validated, ready for testing and Issue #39 resolution 🎯 Next: Test GitHub tools and address Issue #39 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e83764d commit 6b281db

2 files changed

Lines changed: 263 additions & 0 deletions

File tree

src/mcp_server_git/applications/server_application.py

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,108 @@ class GitRemoteGetUrl(BaseModel):
203203
name: str
204204

205205

206+
class GitHubTools(str, Enum):
207+
"""GitHub tool names."""
208+
209+
CREATE_ISSUE = "github_create_issue"
210+
LIST_ISSUES = "github_list_issues"
211+
UPDATE_ISSUE = "github_update_issue"
212+
GET_PR_CHECKS = "github_get_pr_checks"
213+
GET_PR_DETAILS = "github_get_pr_details"
214+
LIST_PULL_REQUESTS = "github_list_pull_requests"
215+
GET_PR_STATUS = "github_get_pr_status"
216+
GET_PR_FILES = "github_get_pr_files"
217+
EDIT_PR_DESCRIPTION = "github_edit_pr_description"
218+
219+
220+
class GitHubCreateIssue(BaseModel):
221+
repo_owner: str
222+
repo_name: str
223+
title: str
224+
body: str | None = None
225+
labels: list[str] | None = None
226+
assignees: list[str] | None = None
227+
milestone: int | None = None
228+
229+
230+
class GitHubListIssues(BaseModel):
231+
repo_owner: str
232+
repo_name: str
233+
state: str = "open" # open, closed, all
234+
labels: str | None = None
235+
assignee: str | None = None
236+
creator: str | None = None
237+
mentioned: str | None = None
238+
milestone: str | None = None
239+
sort: str = "created" # created, updated, comments
240+
direction: str = "desc" # asc, desc
241+
since: str | None = None
242+
per_page: int = 30
243+
page: int = 1
244+
245+
246+
class GitHubUpdateIssue(BaseModel):
247+
repo_owner: str
248+
repo_name: str
249+
issue_number: int
250+
title: str | None = None
251+
body: str | None = None
252+
state: str | None = None # open, closed
253+
labels: list[str] | None = None
254+
assignees: list[str] | None = None
255+
milestone: int | None = None
256+
257+
258+
class GitHubGetPrChecks(BaseModel):
259+
repo_owner: str
260+
repo_name: str
261+
pr_number: int
262+
status: str | None = None
263+
conclusion: str | None = None
264+
265+
266+
class GitHubGetPrDetails(BaseModel):
267+
repo_owner: str
268+
repo_name: str
269+
pr_number: int
270+
include_files: bool = False
271+
include_reviews: bool = False
272+
273+
274+
class GitHubListPullRequests(BaseModel):
275+
repo_owner: str
276+
repo_name: str
277+
state: str = "open" # open, closed, all
278+
head: str | None = None
279+
base: str | None = None
280+
sort: str = "created" # created, updated, popularity
281+
direction: str = "desc" # asc, desc
282+
per_page: int = 30
283+
page: int = 1
284+
285+
286+
class GitHubGetPrStatus(BaseModel):
287+
repo_owner: str
288+
repo_name: str
289+
pr_number: int
290+
291+
292+
class GitHubGetPrFiles(BaseModel):
293+
repo_owner: str
294+
repo_name: str
295+
pr_number: int
296+
per_page: int = 30
297+
page: int = 1
298+
include_patch: bool = False
299+
300+
301+
class GitHubEditPrDescription(BaseModel):
302+
repo_owner: str
303+
repo_name: str
304+
pr_number: int
305+
description: str
306+
307+
206308
class ServerApplicationConfig:
207309
"""Configuration for the server application."""
208310

@@ -1035,6 +1137,52 @@ async def list_tools() -> list[Tool]:
10351137
description="Get URL of a remote repository",
10361138
inputSchema=GitRemoteGetUrl.model_json_schema(),
10371139
),
1140+
# GitHub Tools
1141+
Tool(
1142+
name=GitHubTools.CREATE_ISSUE,
1143+
description="Create a new GitHub issue",
1144+
inputSchema=GitHubCreateIssue.model_json_schema(),
1145+
),
1146+
Tool(
1147+
name=GitHubTools.LIST_ISSUES,
1148+
description="List GitHub issues with filtering options",
1149+
inputSchema=GitHubListIssues.model_json_schema(),
1150+
),
1151+
Tool(
1152+
name=GitHubTools.UPDATE_ISSUE,
1153+
description="Update an existing GitHub issue",
1154+
inputSchema=GitHubUpdateIssue.model_json_schema(),
1155+
),
1156+
Tool(
1157+
name=GitHubTools.GET_PR_CHECKS,
1158+
description="Get check runs for a pull request",
1159+
inputSchema=GitHubGetPrChecks.model_json_schema(),
1160+
),
1161+
Tool(
1162+
name=GitHubTools.GET_PR_DETAILS,
1163+
description="Get detailed information about a pull request",
1164+
inputSchema=GitHubGetPrDetails.model_json_schema(),
1165+
),
1166+
Tool(
1167+
name=GitHubTools.LIST_PULL_REQUESTS,
1168+
description="List pull requests with filtering options",
1169+
inputSchema=GitHubListPullRequests.model_json_schema(),
1170+
),
1171+
Tool(
1172+
name=GitHubTools.GET_PR_STATUS,
1173+
description="Get the status of a pull request",
1174+
inputSchema=GitHubGetPrStatus.model_json_schema(),
1175+
),
1176+
Tool(
1177+
name=GitHubTools.GET_PR_FILES,
1178+
description="Get files changed in a pull request",
1179+
inputSchema=GitHubGetPrFiles.model_json_schema(),
1180+
),
1181+
Tool(
1182+
name=GitHubTools.EDIT_PR_DESCRIPTION,
1183+
description="Edit the description of a pull request",
1184+
inputSchema=GitHubEditPrDescription.model_json_schema(),
1185+
),
10381186
]
10391187

10401188
@server.call_tool()
@@ -1128,6 +1276,104 @@ async def call_tool(name: str, arguments: dict) -> list[dict]:
11281276
result = git_remote_list(repo)
11291277
elif name == GitTools.REMOTE_GET_URL:
11301278
result = git_remote_get_url(repo, arguments["name"])
1279+
# GitHub Tools
1280+
elif name == GitHubTools.CREATE_ISSUE:
1281+
from ..github.api import github_create_issue
1282+
result = await github_create_issue(
1283+
repo_owner=arguments["repo_owner"],
1284+
repo_name=arguments["repo_name"],
1285+
title=arguments["title"],
1286+
body=arguments.get("body"),
1287+
labels=arguments.get("labels"),
1288+
assignees=arguments.get("assignees"),
1289+
milestone=arguments.get("milestone"),
1290+
)
1291+
elif name == GitHubTools.LIST_ISSUES:
1292+
from ..github.api import github_list_issues
1293+
result = await github_list_issues(
1294+
repo_owner=arguments["repo_owner"],
1295+
repo_name=arguments["repo_name"],
1296+
state=arguments.get("state", "open"),
1297+
labels=arguments.get("labels"),
1298+
assignee=arguments.get("assignee"),
1299+
creator=arguments.get("creator"),
1300+
mentioned=arguments.get("mentioned"),
1301+
milestone=arguments.get("milestone"),
1302+
sort=arguments.get("sort", "created"),
1303+
direction=arguments.get("direction", "desc"),
1304+
since=arguments.get("since"),
1305+
per_page=arguments.get("per_page", 30),
1306+
page=arguments.get("page", 1),
1307+
)
1308+
elif name == GitHubTools.UPDATE_ISSUE:
1309+
from ..github.api import github_update_issue
1310+
result = await github_update_issue(
1311+
repo_owner=arguments["repo_owner"],
1312+
repo_name=arguments["repo_name"],
1313+
issue_number=arguments["issue_number"],
1314+
title=arguments.get("title"),
1315+
body=arguments.get("body"),
1316+
state=arguments.get("state"),
1317+
labels=arguments.get("labels"),
1318+
assignees=arguments.get("assignees"),
1319+
milestone=arguments.get("milestone"),
1320+
)
1321+
elif name == GitHubTools.GET_PR_CHECKS:
1322+
from ..github.api import github_get_pr_checks
1323+
result = await github_get_pr_checks(
1324+
repo_owner=arguments["repo_owner"],
1325+
repo_name=arguments["repo_name"],
1326+
pr_number=arguments["pr_number"],
1327+
status=arguments.get("status"),
1328+
conclusion=arguments.get("conclusion"),
1329+
)
1330+
elif name == GitHubTools.GET_PR_DETAILS:
1331+
from ..github.api import github_get_pr_details
1332+
result = await github_get_pr_details(
1333+
repo_owner=arguments["repo_owner"],
1334+
repo_name=arguments["repo_name"],
1335+
pr_number=arguments["pr_number"],
1336+
include_files=arguments.get("include_files", False),
1337+
include_reviews=arguments.get("include_reviews", False),
1338+
)
1339+
elif name == GitHubTools.LIST_PULL_REQUESTS:
1340+
from ..github.api import github_list_pull_requests
1341+
result = await github_list_pull_requests(
1342+
repo_owner=arguments["repo_owner"],
1343+
repo_name=arguments["repo_name"],
1344+
state=arguments.get("state", "open"),
1345+
head=arguments.get("head"),
1346+
base=arguments.get("base"),
1347+
sort=arguments.get("sort", "created"),
1348+
direction=arguments.get("direction", "desc"),
1349+
per_page=arguments.get("per_page", 30),
1350+
page=arguments.get("page", 1),
1351+
)
1352+
elif name == GitHubTools.GET_PR_STATUS:
1353+
from ..github.api import github_get_pr_status
1354+
result = await github_get_pr_status(
1355+
repo_owner=arguments["repo_owner"],
1356+
repo_name=arguments["repo_name"],
1357+
pr_number=arguments["pr_number"],
1358+
)
1359+
elif name == GitHubTools.GET_PR_FILES:
1360+
from ..github.api import github_get_pr_files
1361+
result = await github_get_pr_files(
1362+
repo_owner=arguments["repo_owner"],
1363+
repo_name=arguments["repo_name"],
1364+
pr_number=arguments["pr_number"],
1365+
per_page=arguments.get("per_page", 30),
1366+
page=arguments.get("page", 1),
1367+
include_patch=arguments.get("include_patch", False),
1368+
)
1369+
elif name == GitHubTools.EDIT_PR_DESCRIPTION:
1370+
from ..github.api import github_edit_pr_description
1371+
result = await github_edit_pr_description(
1372+
repo_owner=arguments["repo_owner"],
1373+
repo_name=arguments["repo_name"],
1374+
pr_number=arguments["pr_number"],
1375+
description=arguments["description"],
1376+
)
11311377
else:
11321378
raise ValueError(f"Unknown tool: {name}")
11331379

test_mcp_git.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This is a test file for testing git MCP server functionality.
2+
3+
Testing features:
4+
- Git status ✅
5+
- Git add ✅
6+
- Git commit ✅
7+
- Git diff ✅
8+
- Branch operations ✅
9+
- Remote operations ✅
10+
11+
CRITICAL FIX COMPLETED:
12+
- GitHub Issues tools now registered in MCP server ✅
13+
- Added GitHubTools enum and models ✅
14+
- Added 9 GitHub tools to list_tools() function ✅
15+
- Added GitHub tool handlers to call_tool() function ✅
16+
17+
Ready to address Issue #39!

0 commit comments

Comments
 (0)