github-issue-pr-manager 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,5 @@
1
+ """GitHub Issue PR Manager - MCP server for managing GitHub issues and pull requests, providing AI agents with tools to gather context and close issues through PR workflows"""
2
+
3
+ from .server import main, mcp
4
+
5
+ __all__ = ["main", "mcp"]
@@ -0,0 +1,299 @@
1
+ """
2
+ GitHub Issue PR Manager
3
+
4
+ MCP server for managing GitHub issues and pull requests, providing AI agents with tools to gather context and close issues through PR workflows
5
+ """
6
+
7
+ from fastmcp import FastMCP
8
+
9
+ # Initialize the MCP server
10
+ mcp = FastMCP("GitHub Issue PR Manager")
11
+
12
+ @mcp.tool()
13
+ def get_issue(owner: str, repo: str, issue_number: int) -> str:
14
+ """Get detailed information about a GitHub issue including comments and linked PRs
15
+
16
+ Args:
17
+ owner: Repository owner (username or organization)
18
+ repo: Repository name
19
+ issue_number: Issue number
20
+
21
+ Returns:
22
+ Issue details including title, body, state, labels, assignees, and comments
23
+ """
24
+ import requests
25
+ headers = {'Accept': 'application/vnd.github.v3+json'}
26
+ url = f'https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}'
27
+ response = requests.get(url, headers=headers)
28
+ if response.status_code == 200:
29
+ issue = response.json()
30
+ # Get comments
31
+ comments_url = issue['comments_url']
32
+ comments_response = requests.get(comments_url, headers=headers)
33
+ comments = comments_response.json() if comments_response.status_code == 200 else []
34
+ issue['all_comments'] = comments
35
+ return issue
36
+ else:
37
+ return {'error': f'Failed to get issue: {response.status_code}'}
38
+
39
+ @mcp.tool()
40
+ def list_issue_prs(owner: str, repo: str, issue_number: int) -> str:
41
+ """List all pull requests that reference or are linked to a specific issue
42
+
43
+ Args:
44
+ owner: Repository owner (username or organization)
45
+ repo: Repository name
46
+ issue_number: Issue number to find related PRs for
47
+
48
+ Returns:
49
+ List of pull requests that reference the issue
50
+ """
51
+ import requests
52
+ headers = {'Accept': 'application/vnd.github.v3+json'}
53
+ # Search for PRs mentioning the issue
54
+ query = f'repo:{owner}/{repo} type:pr #{issue_number}'
55
+ search_url = f'https://api.github.com/search/issues?q={query}'
56
+ response = requests.get(search_url, headers=headers)
57
+ if response.status_code == 200:
58
+ return response.json()['items']
59
+ else:
60
+ return {'error': f'Failed to search PRs: {response.status_code}'}
61
+
62
+ @mcp.tool()
63
+ def get_pull_request(owner: str, repo: str, pr_number: int) -> str:
64
+ """Get detailed information about a pull request including its status and mergability
65
+
66
+ Args:
67
+ owner: Repository owner (username or organization)
68
+ repo: Repository name
69
+ pr_number: Pull request number
70
+
71
+ Returns:
72
+ PR details including state, mergeable status, checks, and review status
73
+ """
74
+ import requests
75
+ headers = {'Accept': 'application/vnd.github.v3+json'}
76
+ url = f'https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}'
77
+ response = requests.get(url, headers=headers)
78
+ if response.status_code == 200:
79
+ pr = response.json()
80
+ # Get review status
81
+ reviews_url = f'https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/reviews'
82
+ reviews_response = requests.get(reviews_url, headers=headers)
83
+ pr['reviews'] = reviews_response.json() if reviews_response.status_code == 200 else []
84
+ return pr
85
+ else:
86
+ return {'error': f'Failed to get PR: {response.status_code}'}
87
+
88
+ @mcp.tool()
89
+ def list_repository_prs(owner: str, repo: str, state: str) -> str:
90
+ """List pull requests in a repository with optional filtering by state
91
+
92
+ Args:
93
+ owner: Repository owner (username or organization)
94
+ repo: Repository name
95
+ state: PR state filter (open, closed, all)
96
+
97
+ Returns:
98
+ List of pull requests in the repository
99
+ """
100
+ import requests
101
+ headers = {'Accept': 'application/vnd.github.v3+json'}
102
+ params = {}
103
+ if state:
104
+ params['state'] = state
105
+ url = f'https://api.github.com/repos/{owner}/{repo}/pulls'
106
+ response = requests.get(url, headers=headers, params=params)
107
+ if response.status_code == 200:
108
+ return response.json()
109
+ else:
110
+ return {'error': f'Failed to list PRs: {response.status_code}'}
111
+
112
+ @mcp.tool()
113
+ def create_pull_request(owner: str, repo: str, title: str, body: str, head: str, base: str) -> str:
114
+ """Create a new pull request
115
+
116
+ Args:
117
+ owner: Repository owner (username or organization)
118
+ repo: Repository name
119
+ title: Pull request title
120
+ body: Pull request description
121
+ head: Branch name containing the changes
122
+ base: Branch name to merge into (default: main)
123
+
124
+ Returns:
125
+ Created pull request details
126
+ """
127
+ import requests
128
+ headers = {'Accept': 'application/vnd.github.v3+json'}
129
+ data = {
130
+ 'title': title,
131
+ 'body': body,
132
+ 'head': head,
133
+ 'base': base or 'main'
134
+ }
135
+ url = f'https://api.github.com/repos/{owner}/{repo}/pulls'
136
+ response = requests.post(url, headers=headers, json=data)
137
+ if response.status_code == 201:
138
+ return response.json()
139
+ else:
140
+ return {'error': f'Failed to create PR: {response.status_code} - {response.text}'}
141
+
142
+ @mcp.tool()
143
+ def merge_pull_request(owner: str, repo: str, pr_number: int, commit_title: str, merge_method: str) -> str:
144
+ """Merge a pull request if it's ready
145
+
146
+ Args:
147
+ owner: Repository owner (username or organization)
148
+ repo: Repository name
149
+ pr_number: Pull request number
150
+ commit_title: Merge commit title (optional)
151
+ merge_method: Merge method (merge, squash, rebase)
152
+
153
+ Returns:
154
+ Merge result information
155
+ """
156
+ import requests
157
+ headers = {'Accept': 'application/vnd.github.v3+json'}
158
+ data = {}
159
+ if commit_title:
160
+ data['commit_title'] = commit_title
161
+ if merge_method:
162
+ data['merge_method'] = merge_method
163
+ url = f'https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/merge'
164
+ response = requests.put(url, headers=headers, json=data)
165
+ if response.status_code == 200:
166
+ return response.json()
167
+ else:
168
+ return {'error': f'Failed to merge PR: {response.status_code} - {response.text}'}
169
+
170
+ @mcp.tool()
171
+ def close_issue(owner: str, repo: str, issue_number: int, comment: str) -> str:
172
+ """Close an issue and optionally add a closing comment
173
+
174
+ Args:
175
+ owner: Repository owner (username or organization)
176
+ repo: Repository name
177
+ issue_number: Issue number
178
+ comment: Optional closing comment
179
+
180
+ Returns:
181
+ Updated issue information
182
+ """
183
+ import requests
184
+ headers = {'Accept': 'application/vnd.github.v3+json'}
185
+ # Add comment if provided
186
+ if comment:
187
+ comment_url = f'https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/comments'
188
+ requests.post(comment_url, headers=headers, json={'body': comment})
189
+ # Close the issue
190
+ data = {'state': 'closed'}
191
+ url = f'https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}'
192
+ response = requests.patch(url, headers=headers, json=data)
193
+ if response.status_code == 200:
194
+ return response.json()
195
+ else:
196
+ return {'error': f'Failed to close issue: {response.status_code}'}
197
+
198
+ @mcp.tool()
199
+ def add_issue_comment(owner: str, repo: str, issue_number: int, comment: str) -> str:
200
+ """Add a comment to an issue
201
+
202
+ Args:
203
+ owner: Repository owner (username or organization)
204
+ repo: Repository name
205
+ issue_number: Issue number
206
+ comment: Comment text
207
+
208
+ Returns:
209
+ Created comment information
210
+ """
211
+ import requests
212
+ headers = {'Accept': 'application/vnd.github.v3+json'}
213
+ data = {'body': comment}
214
+ url = f'https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/comments'
215
+ response = requests.post(url, headers=headers, json=data)
216
+ if response.status_code == 201:
217
+ return response.json()
218
+ else:
219
+ return {'error': f'Failed to add comment: {response.status_code}'}
220
+
221
+ @mcp.resource("docs://github-api/{endpoint}")
222
+ def github_api_docs(endpoint: str) -> str:
223
+ """GitHub API documentation reference for issues and pull requests"""
224
+ docs = {
225
+ 'issues': 'GitHub Issues API: https://docs.github.com/en/rest/issues',
226
+ 'pulls': 'GitHub Pull Requests API: https://docs.github.com/en/rest/pulls',
227
+ 'authentication': 'Use personal access tokens in headers: {"Authorization": "token YOUR_TOKEN"}',
228
+ 'rate_limits': 'GitHub API rate limit: 5000 requests per hour for authenticated users'
229
+ }
230
+ endpoint = endpoint if endpoint in docs else 'issues'
231
+ return docs[endpoint]
232
+
233
+ @mcp.resource("guide://workflow")
234
+ def workflow_guide() -> str:
235
+ """Guide for using this MCP to close issues with PRs"""
236
+ return '''GitHub Issue-PR Workflow Guide:
237
+
238
+ 1. Get issue details: Use get_issue() to understand the problem
239
+ 2. Find related PRs: Use list_issue_prs() to see existing work
240
+ 3. Check PR status: Use get_pull_request() to verify PR readiness
241
+ 4. Create PR if needed: Use create_pull_request() for new solutions
242
+ 5. Merge when ready: Use merge_pull_request() for approved PRs
243
+ 6. Close issue: Use close_issue() with a summary comment
244
+ 7. Update stakeholders: Use add_issue_comment() for status updates
245
+
246
+ Best Practices:
247
+ - Always check if PRs are mergeable and have passed checks
248
+ - Verify all required reviews are approved
249
+ - Add meaningful comments when closing issues
250
+ - Reference PR numbers when closing issues'''
251
+
252
+ @mcp.prompt()
253
+ def analyze_issue(owner: str, repo: str, issue_number: str) -> str:
254
+ """Analyze an issue and determine what actions are needed to resolve it
255
+
256
+ Args:
257
+ owner: Repository owner
258
+ repo: Repository name
259
+ issue_number: Issue number to analyze
260
+ """
261
+ return f"""Please analyze GitHub issue #{issue_number} in {owner}/{repo}.
262
+
263
+ 1. First, get the issue details to understand the problem
264
+ 2. Check for any existing pull requests that might address this issue
265
+ 3. For each related PR, check its status and mergability
266
+ 4. Provide a summary of:
267
+ - What the issue is about
268
+ - Current status of any related PRs
269
+ - What actions are needed to close this issue
270
+ - Whether the issue can be closed now or what's blocking it
271
+
272
+ Be thorough in your analysis and provide actionable recommendations."""
273
+
274
+ @mcp.prompt()
275
+ def close_issue_workflow(owner: str, repo: str, issue_number: str) -> str:
276
+ """Guide through the complete workflow to close an issue via PR
277
+
278
+ Args:
279
+ owner: Repository owner
280
+ repo: Repository name
281
+ issue_number: Issue number to close
282
+ """
283
+ return f"""Help me close GitHub issue #{issue_number} in {owner}/{repo} through the proper PR workflow:
284
+
285
+ 1. Analyze the issue and gather context
286
+ 2. Check for existing PRs that address this issue
287
+ 3. Evaluate if any PRs are ready to merge
288
+ 4. If PRs are ready and approved, merge them
289
+ 5. Close the issue with an appropriate comment
290
+ 6. Provide a summary of actions taken
291
+
292
+ Please be careful to verify that PRs have passed all checks and have proper approvals before merging. If anything is not ready, explain what needs to happen next."""
293
+
294
+ def main():
295
+ """Entry point for the MCP server."""
296
+ mcp.run()
297
+
298
+ if __name__ == "__main__":
299
+ main()
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: github-issue-pr-manager
3
+ Version: 0.1.0
4
+ Summary: MCP server for managing GitHub issues and pull requests, providing AI agents with tools to gather context and close issues through PR workflows
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: fastmcp>=2.0.0
7
+ Description-Content-Type: text/markdown
8
+
9
+ # GitHub Issue PR Manager
10
+
11
+ MCP server for managing GitHub issues and pull requests, providing AI agents with tools to gather context and close issues through PR workflows
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ uvx github-issue-pr-manager
17
+ ```
18
+
19
+ ## Tools
20
+
21
+ - `get_issue`: Get detailed information about a GitHub issue including comments and linked PRs
22
+ - `list_issue_prs`: List all pull requests that reference or are linked to a specific issue
23
+ - `get_pull_request`: Get detailed information about a pull request including its status and mergability
24
+ - `list_repository_prs`: List pull requests in a repository with optional filtering by state
25
+ - `create_pull_request`: Create a new pull request
26
+ - `merge_pull_request`: Merge a pull request if it's ready
27
+ - `close_issue`: Close an issue and optionally add a closing comment
28
+ - `add_issue_comment`: Add a comment to an issue
29
+
30
+ ## Resources
31
+
32
+ - `docs://github-api/{endpoint}`: GitHub API documentation reference for issues and pull requests
33
+ - `guide://workflow`: Guide for using this MCP to close issues with PRs
34
+
35
+ ## Prompts
36
+
37
+ - `analyze_issue`: Analyze an issue and determine what actions are needed to resolve it
38
+ - `close_issue_workflow`: Guide through the complete workflow to close an issue via PR
39
+
40
+ ## Claude Desktop Configuration
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "github-issue-pr-manager": {
46
+ "command": "uvx",
47
+ "args": ["github-issue-pr-manager"]
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ ---
54
+
55
+ Generated with MCP Builder
@@ -0,0 +1,6 @@
1
+ github_issue_pr_manager/__init__.py,sha256=pYdESZlUIJYwcaQLSepearpHwYxEYTAvReJYgCTEpAc,234
2
+ github_issue_pr_manager/server.py,sha256=zLBLxdFcLxJr1SCLzCk65jHDI8bRZ1NwwNuE6nRlgc4,11102
3
+ github_issue_pr_manager-0.1.0.dist-info/METADATA,sha256=ovN9VftRCKyho2IwjF1OY7Dfx7NXr71tYqgg5xfGoSU,1751
4
+ github_issue_pr_manager-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
5
+ github_issue_pr_manager-0.1.0.dist-info/entry_points.txt,sha256=X7_hWYqtGIizRv6zdXU6pnG9lwrdo8PDmolzy38O-t4,73
6
+ github_issue_pr_manager-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ github-issue-pr-manager = github_issue_pr_manager:main