quickcall-integrations 0.3.9__py3-none-any.whl → 0.5.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.
@@ -114,3 +114,127 @@ def create_github_resources(mcp: FastMCP) -> None:
114
114
  )
115
115
 
116
116
  return "\n".join(lines)
117
+
118
+ @mcp.resource("github://projects")
119
+ def get_github_projects() -> str:
120
+ """
121
+ List of GitHub Projects V2 with their fields and options.
122
+
123
+ Use these for project management operations like updating issue status.
124
+ """
125
+ store = get_credential_store()
126
+
127
+ # Check if authenticated via PAT or QuickCall
128
+ pat_token, pat_source = get_github_pat()
129
+ has_pat = pat_token is not None
130
+
131
+ if not has_pat and not store.is_authenticated():
132
+ return "GitHub not connected. Options:\n- Run connect_github_via_pat with a Personal Access Token\n- Run connect_quickcall to use QuickCall"
133
+
134
+ # Check QuickCall GitHub App connection
135
+ has_app = False
136
+ if store.is_authenticated():
137
+ creds = store.get_api_credentials()
138
+ if creds and creds.github_connected and creds.github_token:
139
+ has_app = True
140
+
141
+ if not has_pat and not has_app:
142
+ return "GitHub not connected. Connect at quickcall.dev/assistant or use connect_github_via_pat."
143
+
144
+ try:
145
+ # Import here to avoid circular imports
146
+ from mcp_server.tools.github_tools import _get_client
147
+
148
+ client = _get_client()
149
+
150
+ # Determine auth mode for display
151
+ auth_mode = "PAT" if has_pat else "GitHub App"
152
+
153
+ # Get the authenticated user
154
+ username = client.get_authenticated_user()
155
+
156
+ # Collect all projects from user and their orgs
157
+ all_projects = []
158
+
159
+ # 1. Try user projects first
160
+ try:
161
+ user_projects = client.list_projects_with_fields(
162
+ owner=username, is_org=False, limit=100
163
+ )
164
+ all_projects.extend(user_projects)
165
+ except Exception:
166
+ pass
167
+
168
+ # 2. Get unique orgs from repos the user has access to
169
+ try:
170
+ repos = client.list_repos(limit=100)
171
+ org_counts: dict = {}
172
+ for repo in repos:
173
+ if repo.owner != username:
174
+ org_counts[repo.owner] = org_counts.get(repo.owner, 0) + 1
175
+
176
+ # Sort orgs by repo count (most repos first)
177
+ sorted_orgs = sorted(
178
+ org_counts.keys(), key=lambda x: org_counts[x], reverse=True
179
+ )
180
+
181
+ # Fetch projects from all orgs
182
+ for org in sorted_orgs:
183
+ try:
184
+ org_projects = client.list_projects_with_fields(
185
+ owner=org, is_org=True, limit=100
186
+ )
187
+ all_projects.extend(org_projects)
188
+ except Exception:
189
+ pass
190
+ except Exception:
191
+ pass
192
+
193
+ if not all_projects:
194
+ return (
195
+ f"GitHub Projects (via {auth_mode}):\n\n"
196
+ f"No projects found for {username} or accessible orgs.\n\n"
197
+ "To list projects for a specific org, use:\n"
198
+ " manage_issues(action='list_projects', owner='org-name')"
199
+ )
200
+
201
+ projects = all_projects
202
+
203
+ lines = [f"GitHub Projects (via {auth_mode}):", ""]
204
+
205
+ for proj in projects:
206
+ status = "closed" if proj["closed"] else "open"
207
+ lines.append(f"- #{proj['number']}: {proj['title']} ({status})")
208
+ lines.append(f" URL: {proj['url']}")
209
+
210
+ # Show fields
211
+ fields = proj.get("fields", [])
212
+ if fields:
213
+ lines.append(" Fields:")
214
+ for field in fields:
215
+ name = field.get("name", "Unknown")
216
+ data_type = field.get("data_type", "UNKNOWN")
217
+
218
+ if data_type == "SINGLE_SELECT":
219
+ options = field.get("options", [])
220
+ option_names = [opt["name"] for opt in options]
221
+ lines.append(
222
+ f" - {name} (SINGLE_SELECT): {', '.join(option_names)}"
223
+ )
224
+ else:
225
+ lines.append(f" - {name} ({data_type})")
226
+
227
+ lines.append("")
228
+
229
+ lines.append("Usage:")
230
+ lines.append(
231
+ " manage_projects(action='update_fields', issue_numbers=[42], project='1',"
232
+ )
233
+ lines.append(
234
+ " fields={'Status': 'In Progress', 'Priority': 'High'})"
235
+ )
236
+
237
+ return "\n".join(lines)
238
+ except Exception as e:
239
+ logger.error(f"Failed to fetch GitHub projects: {e}")
240
+ return f"Error fetching projects: {str(e)}"