quickcall-integrations 0.1.8__py3-none-any.whl → 0.2.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.
@@ -1,54 +1,110 @@
1
1
  """
2
2
  GitHub Tools - Pull requests and commits via GitHub API.
3
3
 
4
- These tools require authentication via QuickCall.
5
- Connect using connect_quickcall tool first.
4
+ Authentication (in priority order):
5
+ 1. QuickCall GitHub App (preferred) - connect via connect_quickcall
6
+ 2. Personal Access Token (PAT) - set GITHUB_TOKEN env var or use .quickcall.env file
7
+
8
+ PAT fallback is useful for:
9
+ - Users at organizations that can't install the GitHub App
10
+ - Personal repositories without app installation
11
+ - Testing and development
6
12
  """
7
13
 
8
- from typing import Optional
14
+ from typing import Optional, Tuple
9
15
  import logging
10
16
 
11
17
  from fastmcp import FastMCP
12
18
  from fastmcp.exceptions import ToolError
13
19
  from pydantic import Field
14
20
 
15
- from mcp_server.auth import get_credential_store, is_authenticated
21
+ from mcp_server.auth import (
22
+ get_credential_store,
23
+ get_github_pat,
24
+ get_github_pat_username,
25
+ )
16
26
  from mcp_server.api_clients.github_client import GitHubClient
17
27
 
18
28
  logger = logging.getLogger(__name__)
19
29
 
20
30
 
31
+ # Track whether we're using PAT mode for status reporting
32
+ _using_pat_mode: bool = False
33
+ _pat_source: Optional[str] = None
34
+
35
+
21
36
  def _get_client() -> GitHubClient:
22
- """Get the GitHub client, raising error if not configured."""
37
+ """
38
+ Get the GitHub client using the best available authentication method.
39
+
40
+ Authentication priority:
41
+ 1. QuickCall GitHub App (if connected and working)
42
+ 2. Personal Access Token from environment/config file
43
+
44
+ Raises:
45
+ ToolError: If no authentication method is available
46
+ """
47
+ global _using_pat_mode, _pat_source
48
+
23
49
  store = get_credential_store()
24
50
 
25
- if not store.is_authenticated():
26
- raise ToolError(
27
- "Not connected to QuickCall. "
28
- "Run connect_quickcall to authenticate and enable GitHub tools."
51
+ # Try QuickCall GitHub App first (preferred)
52
+ if store.is_authenticated():
53
+ creds = store.get_api_credentials()
54
+ if creds and creds.github_connected and creds.github_token:
55
+ _using_pat_mode = False
56
+ _pat_source = None
57
+ return GitHubClient(
58
+ token=creds.github_token,
59
+ default_owner=creds.github_username,
60
+ installation_id=creds.github_installation_id,
61
+ )
62
+
63
+ # Try PAT fallback
64
+ pat_token, pat_source = get_github_pat()
65
+ if pat_token:
66
+ _using_pat_mode = True
67
+ _pat_source = pat_source
68
+ pat_username = get_github_pat_username()
69
+ logger.info(f"Using GitHub PAT from {pat_source}")
70
+ return GitHubClient(
71
+ token=pat_token,
72
+ default_owner=pat_username,
73
+ installation_id=None, # No installation ID for PAT
29
74
  )
30
75
 
31
- # Fetch fresh credentials from API
32
- creds = store.get_api_credentials()
76
+ # No authentication available - provide helpful error message
77
+ _using_pat_mode = False
78
+ _pat_source = None
33
79
 
34
- if not creds or not creds.github_connected:
80
+ if store.is_authenticated():
81
+ # Connected to QuickCall but GitHub not connected
35
82
  raise ToolError(
36
- "GitHub not connected. "
37
- "Connect GitHub at quickcall.dev/assistant to enable GitHub tools."
83
+ "GitHub not connected. Options:\n"
84
+ "1. Connect GitHub App at quickcall.dev/assistant (recommended)\n"
85
+ "2. Run connect_github_via_pat with your Personal Access Token\n"
86
+ "3. Set GITHUB_TOKEN environment variable"
38
87
  )
39
-
40
- if not creds.github_token:
88
+ else:
89
+ # Not connected to QuickCall at all
41
90
  raise ToolError(
42
- "Could not fetch GitHub token. "
43
- "Try reconnecting GitHub at quickcall.dev/assistant."
91
+ "GitHub authentication required. Options:\n"
92
+ "1. Run connect_quickcall to use QuickCall (full access to GitHub + Slack)\n"
93
+ "2. Run connect_github_via_pat with a Personal Access Token (GitHub only)\n"
94
+ "3. Set GITHUB_TOKEN environment variable\n\n"
95
+ "For PAT: Create token at https://github.com/settings/tokens\n"
96
+ "Required scopes: repo (private) or public_repo (public only)"
44
97
  )
45
98
 
46
- # Create client with fresh token and installation ID
47
- return GitHubClient(
48
- token=creds.github_token,
49
- default_owner=creds.github_username,
50
- installation_id=creds.github_installation_id,
51
- )
99
+
100
+ def is_using_pat_mode() -> Tuple[bool, Optional[str]]:
101
+ """
102
+ Check if GitHub tools are using PAT mode.
103
+
104
+ Returns:
105
+ Tuple of (is_using_pat, source) where source is where the PAT was loaded from.
106
+ """
107
+ return (_using_pat_mode, _pat_source)
52
108
 
53
109
 
54
110
  def create_github_tools(mcp: FastMCP) -> None:
@@ -292,44 +348,155 @@ def create_github_tools(mcp: FastMCP) -> None:
292
348
  except Exception as e:
293
349
  raise ToolError(f"Failed to list branches: {str(e)}")
294
350
 
295
- @mcp.tool(tags={"github", "status"})
296
- def check_github_connection() -> dict:
351
+ @mcp.tool(tags={"github", "prs", "appraisal"})
352
+ def search_merged_prs(
353
+ author: Optional[str] = Field(
354
+ default=None,
355
+ description="GitHub username to filter by. Defaults to authenticated user if not specified.",
356
+ ),
357
+ days: int = Field(
358
+ default=180,
359
+ description="Number of days to look back (default: 180 for ~6 months)",
360
+ ),
361
+ org: Optional[str] = Field(
362
+ default=None,
363
+ description="GitHub org to search within. If not specified, searches all accessible repos.",
364
+ ),
365
+ repo: Optional[str] = Field(
366
+ default=None,
367
+ description="Specific repo in 'owner/repo' format (e.g., 'revolving-org/supabase'). Overrides org if specified.",
368
+ ),
369
+ limit: int = Field(
370
+ default=100,
371
+ description="Maximum PRs to return (default: 100)",
372
+ ),
373
+ ) -> dict:
297
374
  """
298
- Check if GitHub is connected and working.
375
+ Search for merged pull requests by author within a time period.
299
376
 
300
- Tests the GitHub connection by fetching your account info.
301
- Use this to verify your GitHub integration is working.
377
+ USE FOR APPRAISALS: This tool is ideal for gathering contribution data
378
+ for performance reviews. Returns basic PR info - use get_pr for full
379
+ details (additions, deletions, files) on specific PRs.
380
+
381
+ Claude should analyze the returned PRs to:
382
+
383
+ 1. CATEGORIZE by type (look at PR title/labels):
384
+ - Features: "feat:", "add:", "implement", "new", "create"
385
+ - Enhancements: "improve:", "update:", "perf:", "optimize", "enhance"
386
+ - Bug fixes: "fix:", "bugfix:", "hotfix:", "resolve", "patch"
387
+ - Chores: "chore:", "docs:", "test:", "ci:", "refactor:", "bump"
388
+
389
+ 2. IDENTIFY top PRs worth highlighting (call get_pr for detailed metrics)
390
+
391
+ 3. SUMMARIZE for appraisal with accomplishments grouped by category
392
+
393
+ Returns: number, title, body, merged_at, labels, repo, owner, html_url, author.
394
+ For full stats (additions, deletions, files), call get_pr on specific PRs.
395
+
396
+ Requires QuickCall authentication with GitHub connected.
302
397
  """
303
- store = get_credential_store()
398
+ try:
399
+ client = _get_client()
304
400
 
305
- if not store.is_authenticated():
306
- return {
307
- "connected": False,
308
- "error": "Not connected to QuickCall. Run connect_quickcall first.",
309
- }
401
+ # Calculate since_date from days
402
+ from datetime import datetime, timedelta
310
403
 
311
- creds = store.get_api_credentials()
404
+ since_date = (datetime.utcnow() - timedelta(days=days)).strftime("%Y-%m-%d")
312
405
 
313
- if not creds:
314
- return {
315
- "connected": False,
316
- "error": "Could not fetch credentials from QuickCall.",
317
- }
406
+ # Use authenticated user if author not specified
407
+ if not author:
408
+ creds = get_credential_store().get_api_credentials()
409
+ if creds and creds.github_username:
410
+ author = creds.github_username
411
+
412
+ prs = client.search_merged_prs(
413
+ author=author,
414
+ since_date=since_date,
415
+ org=org,
416
+ repo=repo,
417
+ limit=limit,
418
+ )
318
419
 
319
- if not creds.github_connected:
320
420
  return {
321
- "connected": False,
322
- "error": "GitHub not connected. Connect at quickcall.dev/assistant.",
421
+ "count": len(prs),
422
+ "period": f"Last {days} days",
423
+ "author": author,
424
+ "org": org,
425
+ "repo": repo,
426
+ "prs": prs,
323
427
  }
428
+ except ToolError:
429
+ raise
430
+ except Exception as e:
431
+ raise ToolError(f"Failed to search merged PRs: {str(e)}")
324
432
 
433
+ @mcp.tool(tags={"github", "status"})
434
+ def check_github_connection() -> dict:
435
+ """
436
+ Check if GitHub is connected and working.
437
+
438
+ Tests the GitHub connection by fetching your account info.
439
+ Shows whether using QuickCall GitHub App or PAT fallback.
440
+ Use this to verify your GitHub integration is working.
441
+ """
442
+ store = get_credential_store()
443
+
444
+ # First, try to get a working client (this handles both QuickCall and PAT)
325
445
  try:
326
446
  client = _get_client()
327
- username = client.get_authenticated_user()
447
+ using_pat, pat_source = is_using_pat_mode()
448
+
449
+ # Try to get username to verify connection works
450
+ try:
451
+ username = client.get_authenticated_user()
452
+ except Exception:
453
+ username = None
454
+
455
+ if using_pat:
456
+ return {
457
+ "connected": True,
458
+ "mode": "pat",
459
+ "pat_source": pat_source,
460
+ "username": username or get_github_pat_username(),
461
+ "note": "Using Personal Access Token (PAT) mode. "
462
+ "Some features like list_repos may have limited access.",
463
+ }
464
+ else:
465
+ creds = store.get_api_credentials()
466
+ return {
467
+ "connected": True,
468
+ "mode": "github_app",
469
+ "username": username or (creds.github_username if creds else None),
470
+ "installation_id": creds.github_installation_id if creds else None,
471
+ }
472
+ except ToolError as e:
473
+ # No authentication available
474
+ pat_token, _ = get_github_pat()
475
+ if pat_token:
476
+ # PAT exists but failed to work
477
+ return {
478
+ "connected": False,
479
+ "error": "PAT authentication failed. Token may be invalid or expired.",
480
+ "suggestion": "Check your GITHUB_TOKEN or .quickcall.env file.",
481
+ }
482
+
483
+ # Check QuickCall status for helpful error
484
+ if store.is_authenticated():
485
+ creds = store.get_api_credentials()
486
+ if creds and not creds.github_connected:
487
+ return {
488
+ "connected": False,
489
+ "error": "GitHub not connected via QuickCall.",
490
+ "suggestions": [
491
+ "Connect GitHub App at quickcall.dev/assistant",
492
+ "Or set GITHUB_TOKEN environment variable",
493
+ "Or create .quickcall.env with GITHUB_TOKEN=ghp_xxx",
494
+ ],
495
+ }
328
496
 
329
497
  return {
330
- "connected": True,
331
- "username": username,
332
- "installation_id": creds.github_installation_id,
498
+ "connected": False,
499
+ "error": str(e),
333
500
  }
334
501
  except Exception as e:
335
502
  return {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quickcall-integrations
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: MCP server with developer integrations for Claude Code and Cursor
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: fastmcp>=2.13.0
@@ -26,8 +26,9 @@ Description-Content-Type: text/markdown
26
26
  </p>
27
27
 
28
28
  <p align="center">
29
- <a href="#integrations">Integrations</a> |
30
29
  <a href="#install">Install</a> |
30
+ <a href="#capabilities">Capabilities</a> |
31
+ <a href="#integrations">Integrations</a> |
31
32
  <a href="#authentication">Authentication</a> |
32
33
  <a href="#commands">Commands</a> |
33
34
  <a href="#troubleshooting">Troubleshooting</a>
@@ -35,6 +36,42 @@ Description-Content-Type: text/markdown
35
36
 
36
37
  ---
37
38
 
39
+ ## Install
40
+
41
+ ### Claude Code
42
+
43
+ **In your terminal:**
44
+ ```bash
45
+ claude mcp add quickcall -- uvx quickcall-integrations
46
+ ```
47
+
48
+ **In Claude Code:**
49
+ ```
50
+ /plugin marketplace add quickcall-dev/quickcall-integrations
51
+ ```
52
+ ```
53
+ /plugin enable quickcall
54
+ ```
55
+
56
+ **Restart Claude Code**, then verify with `/mcp` and `/plugin list`.
57
+
58
+ ### Cursor / Other IDEs
59
+
60
+ Add to MCP config (`~/.cursor/mcp.json` or `.cursor/mcp.json`):
61
+
62
+ ```json
63
+ {
64
+ "mcpServers": {
65
+ "quickcall": {
66
+ "command": "uvx",
67
+ "args": ["quickcall-integrations"]
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ > Works with any IDE that supports MCP servers.
74
+
38
75
  ## Capabilities
39
76
 
40
77
  - **Get standup updates** from git history (commits, diffs, stats)
@@ -99,56 +136,10 @@ Description-Content-Type: text/markdown
99
136
 
100
137
  </details>
101
138
 
102
- ## Install
103
-
104
- ### Claude Code
105
-
106
- ```
107
- /plugin marketplace add quickcall-dev/quickcall-integrations
108
- /plugin install quickcall@quickcall-integrations
109
- ```
110
-
111
- <details>
112
- <summary>MCP only (without plugin)</summary>
113
-
114
- ```bash
115
- claude mcp add quickcall -- uvx quickcall-integrations
116
- ```
117
- </details>
118
-
119
- <details>
120
- <summary>Update to latest version</summary>
121
-
122
- ```
123
- /plugin marketplace update quickcall-integrations
124
- /plugin uninstall quickcall
125
- /plugin install quickcall@quickcall-integrations
126
- ```
127
-
128
- After updating, restart Claude Code or open a new terminal.
129
- </details>
130
-
131
- ### Cursor
132
-
133
- Add to your Cursor MCP config (`~/.cursor/mcp.json` for global, or `.cursor/mcp.json` for project):
134
-
135
- ```json
136
- {
137
- "mcpServers": {
138
- "quickcall": {
139
- "command": "uvx",
140
- "args": ["quickcall-integrations"]
141
- }
142
- }
143
- }
144
- ```
145
-
146
- Then restart Cursor.
147
-
148
- > Also works with [Antigravity](https://antigravity.dev) and any other IDE that supports MCP servers.
149
-
150
139
  ## Authentication
151
140
 
141
+ ### Option 1: QuickCall (Recommended)
142
+
152
143
  To use GitHub and Slack integrations, connect your QuickCall account:
153
144
 
154
145
  ```
@@ -162,6 +153,30 @@ This will guide you through:
162
153
 
163
154
  Credentials are stored locally in `~/.quickcall/credentials.json`.
164
155
 
156
+ ### Option 2: GitHub PAT (For Enterprise Users)
157
+
158
+ If your organization can't install the QuickCall GitHub App (common at enterprises with strict app policies), you can use a Personal Access Token instead:
159
+
160
+ **Environment Variable:**
161
+ ```bash
162
+ export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
163
+ ```
164
+
165
+ **Or config file** (create `.quickcall.env` in your project root or home directory):
166
+ ```bash
167
+ # .quickcall.env
168
+ GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
169
+ GITHUB_USERNAME=your-username # Optional: for better UX
170
+ ```
171
+
172
+ **Create a PAT at:** https://github.com/settings/tokens
173
+
174
+ **Required scopes:**
175
+ - `repo` - Full access to private repositories
176
+ - `public_repo` - Access to public repositories only (if you don't need private repos)
177
+
178
+ **Note:** PAT mode provides access to GitHub tools only. For Slack integration, use QuickCall authentication.
179
+
165
180
  ## Commands
166
181
 
167
182
  ### Claude Code
@@ -214,27 +229,22 @@ What did I work on this week? Send summary to #standup
214
229
 
215
230
  ## Troubleshooting
216
231
 
217
- ### Plugin Not Updating?
232
+ ### Clean Reinstall
218
233
 
219
- If new commands don't appear after updating, clear the cache:
234
+ If commands don't appear or aren't updating:
220
235
 
221
236
  ```bash
237
+ # Remove everything
222
238
  rm -rf ~/.claude/plugins/cache/quickcall-integrations
223
239
  rm -rf ~/.claude/plugins/marketplaces/quickcall-integrations
240
+ claude mcp remove quickcall
224
241
  ```
225
242
 
226
- Then restart Claude Code and reinstall:
227
-
228
- ```
229
- /plugin marketplace add quickcall-dev/quickcall-integrations
230
- /plugin install quickcall@quickcall-integrations
231
- ```
243
+ Then follow the [install steps](#claude-code) again.
232
244
 
233
245
  ### Commands Not Showing?
234
246
 
235
- Type `/quickcall:` - you should see `connect`, `status`, `updates`.
236
-
237
- If only `updates` shows, run the cleanup above and reinstall.
247
+ Type `/quickcall:` - you should see `connect`, `status`, `updates`. If not, do a clean reinstall above.
238
248
 
239
249
  ---
240
250
 
@@ -1,20 +1,20 @@
1
1
  mcp_server/__init__.py,sha256=UJBr5BLG_aU2S4s2fEbRBZYd7GUWDVejxBpqezNBo8Q,98
2
2
  mcp_server/server.py,sha256=zGrrYwp7H24pJAAGAVkHDk7Y6IydOR_wo5hIL-e6_50,3001
3
3
  mcp_server/api_clients/__init__.py,sha256=kOG5_sxIVpAx_tvf1nq_P0QCkqojAVidRE-wenLS-Wc,207
4
- mcp_server/api_clients/github_client.py,sha256=KnF0hZ8ThBSmUVF9sgviMk5hrUe6GAgmQXY-EkOPwsM,14474
4
+ mcp_server/api_clients/github_client.py,sha256=Ddnekr2Jz4_dOpf1lmgdhBHB2Kr5WjC67-W_j2AZkK0,20772
5
5
  mcp_server/api_clients/slack_client.py,sha256=w3rcGghttfYw8Ird2beNo2LEYLc3rCTbUKMH4X7QQuQ,16447
6
- mcp_server/auth/__init__.py,sha256=YQpDPH5itIaBuEm0AtwNCHxTX4L5dLutTximVamsItw,552
7
- mcp_server/auth/credentials.py,sha256=OCPs_4DcQ1zHEBgkcPDNCHVFFO36Xe6_QBx_5Jn2xgk,9379
6
+ mcp_server/auth/__init__.py,sha256=D-JS0Qe7FkeJjYx92u_AqPx8ZRoB3dKMowzzJXlX6cc,780
7
+ mcp_server/auth/credentials.py,sha256=1e1FpiaPPVc5hVdLlvIU2JbhbdHbXH9pzYBDPsUr0hI,20003
8
8
  mcp_server/auth/device_flow.py,sha256=NXNWHzd-CA4dlhEVCgUhwfpe9TpMKpLSJuyFCh70xKs,8371
9
9
  mcp_server/resources/__init__.py,sha256=JrMa3Kf-DmeCB4GwVNfmfw9OGnxF9pJJxCw9Y7u7ujQ,35
10
10
  mcp_server/resources/slack_resources.py,sha256=b_CPxAicwkF3PsBXIat4QoLbDUHM2g_iPzgzvVpwjaw,1687
11
11
  mcp_server/tools/__init__.py,sha256=vIR2ujAaTXm2DgpTsVNz3brI4G34p-Jeg44Qe0uvWc0,405
12
- mcp_server/tools/auth_tools.py,sha256=yev9UZi-i842JPx_9IgGf7pWChEQzSXRiICsHo46s9Q,17853
13
- mcp_server/tools/git_tools.py,sha256=5cZfngkP1wHNYUvGtLFcMjS7bhrFzxAC_TPz0h3CUB0,7691
14
- mcp_server/tools/github_tools.py,sha256=GomR88SByAbdi4VHk1vaUNp29hwWEIY6cX1t9QoMDOU,10972
12
+ mcp_server/tools/auth_tools.py,sha256=kCPjPC1jrVz0XaRAwPea-ue8ybjLLTxyILplBDJ9Mv4,24477
13
+ mcp_server/tools/git_tools.py,sha256=jyCTQR2eSzUFXMt0Y8x66758-VY8YCY14DDUJt7GY2U,13957
14
+ mcp_server/tools/github_tools.py,sha256=r5HgYQIxdV8KQO5G5lAR3z3XK9moyrQgA84IH0hJKI4,17727
15
15
  mcp_server/tools/slack_tools.py,sha256=-HVE_x3Z1KMeYGi1xhyppEwz5ZF-I-ZD0-Up8yBeoYE,11796
16
16
  mcp_server/tools/utility_tools.py,sha256=1WiOpJivu6Ug9OLajm77lzsmFfBPgWHs8e1hNCEX_Aw,3359
17
- quickcall_integrations-0.1.8.dist-info/METADATA,sha256=MK4ehZKL17rzpQs5Rmun3y-KN8L5FNu8c9w-Cde06wo,6576
18
- quickcall_integrations-0.1.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
19
- quickcall_integrations-0.1.8.dist-info/entry_points.txt,sha256=kkcunmJUzncYvQ1rOR35V2LPm2HcFTKzdI2l3n7NwiM,66
20
- quickcall_integrations-0.1.8.dist-info/RECORD,,
17
+ quickcall_integrations-0.2.0.dist-info/METADATA,sha256=y_LgEAseZRBLdxQGRiIl9kjlfDe6rtSY5SmEtnV6VCU,7043
18
+ quickcall_integrations-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
19
+ quickcall_integrations-0.2.0.dist-info/entry_points.txt,sha256=kkcunmJUzncYvQ1rOR35V2LPm2HcFTKzdI2l3n7NwiM,66
20
+ quickcall_integrations-0.2.0.dist-info/RECORD,,