github-mcp-agent 0.2.0__tar.gz → 0.2.1__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.
Files changed (27) hide show
  1. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/.gitignore +2 -0
  2. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/PKG-INFO +5 -3
  3. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/README.md +4 -2
  4. github_mcp_agent-0.2.1/assets/demo1.png +0 -0
  5. github_mcp_agent-0.2.1/assets/demo2.png +0 -0
  6. github_mcp_agent-0.2.1/assets/demo3.png +0 -0
  7. github_mcp_agent-0.2.1/github_mcp_agent/providers/copilot.py +117 -0
  8. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/pyproject.toml +1 -1
  9. github_mcp_agent-0.2.0/github_mcp_agent/providers/copilot.py +0 -32
  10. github_mcp_agent-0.2.0/uv.lock +0 -2693
  11. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/.claude/settings.json +0 -0
  12. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/.claude/settings.local.json +0 -0
  13. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/.env.example +0 -0
  14. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/LICENSE +0 -0
  15. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/__init__.py +0 -0
  16. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/agent.py +0 -0
  17. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/cli.py +0 -0
  18. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/__init__.py +0 -0
  19. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/anthropic.py +0 -0
  20. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/bedrock.py +0 -0
  21. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/gemini.py +0 -0
  22. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/ollama.py +0 -0
  23. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/providers/openai.py +0 -0
  24. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/setup_wizard.py +0 -0
  25. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/system_prompt.txt +0 -0
  26. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/github_mcp_agent/tools.py +0 -0
  27. {github_mcp_agent-0.2.0 → github_mcp_agent-0.2.1}/system_prompt.txt +0 -0
@@ -2,3 +2,5 @@
2
2
  .venv/
3
3
  __pycache__/
4
4
  *.pyc
5
+ uv.lock
6
+ dist/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-mcp-agent
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Talk to your GitHub repos, issues, and project boards in plain English from your terminal
5
5
  Project-URL: Homepage, https://github.com/OmarCodes022/GitHub-MCP-Agent
6
6
  Project-URL: Repository, https://github.com/OmarCodes022/GitHub-MCP-Agent
@@ -35,6 +35,8 @@ Description-Content-Type: text/markdown
35
35
 
36
36
  Talk to your GitHub repos, issues, and project boards in plain English from your terminal.
37
37
 
38
+ ![GitHub MCP Agent demo](assets/demo1.png)
39
+
38
40
  ```
39
41
  You > list open issues in my raytracer repo
40
42
  You > set priority of issue #42 to urgent
@@ -72,7 +74,7 @@ Interactive wizard:
72
74
  - **Anthropic API** — API key from console.anthropic.com
73
75
  - **OpenAI** — API key from platform.openai.com
74
76
  - **Google Gemini** — API key from aistudio.google.com
75
- - **GitHub Copilot** — uses your GitHub token, requires a Copilot subscription
77
+ - **GitHub Copilot** — browser OAuth flow, requires a Copilot subscription
76
78
  - **Local (Ollama)** — picks from your installed models, no API key needed
77
79
  3. Model selection (scrollable menu)
78
80
  4. Pulls the GitHub MCP Docker image
@@ -142,4 +144,4 @@ Uses the [Strands Agents SDK](https://github.com/strands-agents/sdk-python) with
142
144
 
143
145
  **Ollama model not found** — run `ollama list` to confirm the model name, re-run `github-agent model`
144
146
 
145
- **`No module named github_mcp_agent`** — reinstall with `uv tool install .` from the project directory
147
+ **`No module named github_mcp_agent`** — reinstall with `pip install github-mcp-agent` or `uv tool install github-mcp-agent`
@@ -2,6 +2,8 @@
2
2
 
3
3
  Talk to your GitHub repos, issues, and project boards in plain English from your terminal.
4
4
 
5
+ ![GitHub MCP Agent demo](assets/demo1.png)
6
+
5
7
  ```
6
8
  You > list open issues in my raytracer repo
7
9
  You > set priority of issue #42 to urgent
@@ -39,7 +41,7 @@ Interactive wizard:
39
41
  - **Anthropic API** — API key from console.anthropic.com
40
42
  - **OpenAI** — API key from platform.openai.com
41
43
  - **Google Gemini** — API key from aistudio.google.com
42
- - **GitHub Copilot** — uses your GitHub token, requires a Copilot subscription
44
+ - **GitHub Copilot** — browser OAuth flow, requires a Copilot subscription
43
45
  - **Local (Ollama)** — picks from your installed models, no API key needed
44
46
  3. Model selection (scrollable menu)
45
47
  4. Pulls the GitHub MCP Docker image
@@ -109,4 +111,4 @@ Uses the [Strands Agents SDK](https://github.com/strands-agents/sdk-python) with
109
111
 
110
112
  **Ollama model not found** — run `ollama list` to confirm the model name, re-run `github-agent model`
111
113
 
112
- **`No module named github_mcp_agent`** — reinstall with `uv tool install .` from the project directory
114
+ **`No module named github_mcp_agent`** — reinstall with `pip install github-mcp-agent` or `uv tool install github-mcp-agent`
Binary file
Binary file
Binary file
@@ -0,0 +1,117 @@
1
+ import json
2
+ import time
3
+ import urllib.error
4
+ import urllib.parse
5
+ import urllib.request
6
+
7
+ import questionary
8
+
9
+ MODELS = [
10
+ ("gpt-4o", "gpt-4o", "flagship"),
11
+ ("gpt-4o-mini", "gpt-4o-mini", "fast, cheap"),
12
+ ("claude-sonnet-4-5", "claude-sonnet-4-5", "Anthropic via Copilot"),
13
+ ("o3-mini", "o3-mini", "reasoning"),
14
+ ("gemini-1.5-pro", "gemini-1.5-pro", "Google via Copilot"),
15
+ ]
16
+
17
+ _CLIENT_ID = "Iv1.b507a08c87ecfe98"
18
+
19
+
20
+ def _device_flow() -> str:
21
+ """Run GitHub device flow with the Copilot OAuth client, return an access token."""
22
+ from rich.console import Console
23
+ console = Console()
24
+
25
+ data = urllib.parse.urlencode({"client_id": _CLIENT_ID, "scope": "read:user"}).encode()
26
+ req = urllib.request.Request(
27
+ "https://github.com/login/device/code",
28
+ data=data,
29
+ headers={"Accept": "application/json"},
30
+ )
31
+ with urllib.request.urlopen(req) as r:
32
+ device = json.loads(r.read())
33
+
34
+ console.print(f"\n Open: [bold cyan]{device['verification_uri']}[/bold cyan]")
35
+ console.print(f" Code: [bold yellow]{device['user_code']}[/bold yellow]\n")
36
+
37
+ interval = device.get("interval", 5)
38
+ deadline = time.time() + device.get("expires_in", 900)
39
+
40
+ while time.time() < deadline:
41
+ time.sleep(interval)
42
+ poll_data = urllib.parse.urlencode({
43
+ "client_id": _CLIENT_ID,
44
+ "device_code": device["device_code"],
45
+ "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
46
+ }).encode()
47
+ poll_req = urllib.request.Request(
48
+ "https://github.com/login/oauth/access_token",
49
+ data=poll_data,
50
+ headers={"Accept": "application/json"},
51
+ )
52
+ with urllib.request.urlopen(poll_req) as r:
53
+ result = json.loads(r.read())
54
+
55
+ if "access_token" in result:
56
+ return result["access_token"]
57
+ error = result.get("error", "")
58
+ if error == "slow_down":
59
+ interval += 5
60
+ elif error not in ("authorization_pending",):
61
+ raise RuntimeError(f"Auth failed: {result.get('error_description', error)}")
62
+
63
+ raise RuntimeError("Authentication timed out.")
64
+
65
+
66
+ def _get_copilot_token(oauth_token: str) -> str:
67
+ """Exchange a Copilot OAuth token for a short-lived Copilot API token."""
68
+ req = urllib.request.Request("https://api.github.com/copilot_internal/v2/token")
69
+ req.add_header("Authorization", f"token {oauth_token}")
70
+ req.add_header("Accept", "application/json")
71
+ req.add_header("Editor-Version", "vscode/1.85.0")
72
+ req.add_header("Editor-Plugin-Version", "copilot/1.138.0")
73
+ req.add_header("User-Agent", "GithubCopilot/1.138.0")
74
+ try:
75
+ with urllib.request.urlopen(req) as r:
76
+ return json.loads(r.read())["token"]
77
+ except urllib.error.HTTPError as e:
78
+ raise RuntimeError(
79
+ f"Failed to get Copilot token (HTTP {e.code}).\n"
80
+ "Make sure you have an active Copilot subscription."
81
+ )
82
+
83
+
84
+ def build_model(model_id: str):
85
+ import os
86
+ from strands.models.litellm import LiteLLMModel
87
+ oauth_token = os.environ.get("COPILOT_OAUTH_TOKEN")
88
+ if not oauth_token:
89
+ raise RuntimeError("Copilot token not set. Run 'github-agent provider' and pick GitHub Copilot.")
90
+ token = _get_copilot_token(oauth_token)
91
+ return LiteLLMModel(
92
+ model_id=f"openai/{model_id}",
93
+ params={
94
+ "api_base": "https://api.githubcopilot.com",
95
+ "api_key": token,
96
+ "extra_headers": {
97
+ "Editor-Version": "vscode/1.85.0",
98
+ "Editor-Plugin-Version": "copilot/1.138.0",
99
+ "User-Agent": "GithubCopilot/1.138.0",
100
+ "Copilot-Integration-Id": "vscode-chat",
101
+ },
102
+ },
103
+ )
104
+
105
+
106
+ def setup(_ask) -> dict:
107
+ from rich.console import Console
108
+ console = Console()
109
+ console.print(" [dim]Requires an active Copilot subscription (student pack, individual, or business).[/dim]")
110
+ console.print(" [dim]Opening browser to authenticate with GitHub Copilot...[/dim]\n")
111
+
112
+ oauth_token = _device_flow()
113
+
114
+ model_choices = [f"{name} ({desc})" for _, name, desc in MODELS]
115
+ model_display = _ask(questionary.select, "Model:", choices=model_choices)
116
+ model_id = MODELS[model_choices.index(model_display)][0]
117
+ return {"COPILOT_OAUTH_TOKEN": oauth_token, "MODEL_ID": model_id}
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "github-mcp-agent"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "Talk to your GitHub repos, issues, and project boards in plain English from your terminal"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -1,32 +0,0 @@
1
- import os
2
-
3
- import questionary
4
-
5
- MODELS = [
6
- ("gpt-4o", "gpt-4o", "flagship"),
7
- ("gpt-4o-mini", "gpt-4o-mini", "fast, cheap"),
8
- ("claude-sonnet-4-5", "claude-sonnet-4-5", "Anthropic via Copilot"),
9
- ("o3-mini", "o3-mini", "reasoning"),
10
- ("gemini-1.5-pro", "gemini-1.5-pro", "Google via Copilot"),
11
- ]
12
-
13
-
14
- def build_model(model_id: str):
15
- from strands.models.litellm import LiteLLMModel
16
- token = os.environ.get("GITHUB_TOKEN")
17
- if not token:
18
- raise RuntimeError("GITHUB_TOKEN is not set. Run 'github-agent setup' to configure.")
19
- return LiteLLMModel(
20
- model_id=f"openai/{model_id}",
21
- params={"api_base": "https://api.githubcopilot.com", "api_key": token},
22
- )
23
-
24
-
25
- def setup(_ask) -> dict:
26
- from rich.console import Console
27
- console = Console()
28
- console.print(" [dim]Uses your GitHub token - no extra API key needed.[/dim]")
29
- console.print(" [dim]Requires an active Copilot subscription (student pack, individual, or business).[/dim]")
30
- model_choices = [f"{name} ({desc})" for _, name, desc in MODELS]
31
- model_display = _ask(questionary.select, "Model:", choices=model_choices)
32
- return {"MODEL_ID": MODELS[model_choices.index(model_display)][0]}