octocode-mcp 1.0.0

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.
package/build/index.js ADDED
@@ -0,0 +1,2371 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import z from 'zod';
5
+ import { exec, execSync } from 'child_process';
6
+ import { promisify } from 'util';
7
+ import NodeCache from 'node-cache';
8
+ import crypto from 'crypto';
9
+
10
+ const TOOL_NAMES = {
11
+ SEARCH_GITHUB_CODE: 'search_github_code',
12
+ FETCH_GITHUB_FILE_CONTENT: 'fetch_github_file_content',
13
+ VIEW_REPOSITORY: 'view_repository',
14
+ NPM_VIEW: 'npm_view',
15
+ SEARCH_GITHUB_REPOS: 'search_github_repos',
16
+ SEARCH_GITHUB_COMMITS: 'search_github_commits',
17
+ SEARCH_GITHUB_PULL_REQUESTS: 'search_github_pull_requests',
18
+ GET_USER_ORGANIZATIONS: 'get_user_organizations',
19
+ NPM_SEARCH: 'npm_search',
20
+ VIEW_REPOSITORY_STRUCTURE: 'view_repository_structure',
21
+ SEARCH_GITHUB_ISSUES: 'search_github_issues',
22
+ SEARCH_GITHUB_DISCUSSIONS: 'search_github_discussions',
23
+ SEARCH_GITHUB_TOPICS: 'search_github_topics',
24
+ SEARCH_GITHUB_USERS: 'search_github_users',
25
+ };
26
+ const INDEX_MAP = {
27
+ CRITICAL: '#CRITICAL#',
28
+ WARNING: '#WARNING#',
29
+ CODE: '#CODE#',
30
+ VALIDATION: '#VALIDATION#',
31
+ USER: '#USER#',
32
+ EFFICIENCY: '#EFFICIENCY#',
33
+ };
34
+
35
+ const PROMPT_SYSTEM_PROMPT = `Expert code discovery assistant with advanced reasoning capabilities. Find production-ready code examples from GitHub/npm using sophisticated research workflows.
36
+
37
+ ## ${INDEX_MAP.CRITICAL} CORE REQUIREMENTS
38
+ - ${INDEX_MAP.CODE} **3+ COMPLETE CODE EXAMPLES** (20+ lines) with syntax highlighting
39
+ - ${INDEX_MAP.CODE} **REPOSITORY CITATIONS**: \`\`\`language:owner/repo/filepath
40
+ - ${INDEX_MAP.CODE} **WORKING IMPLEMENTATIONS** with imports/exports/context
41
+ - ${INDEX_MAP.CODE} **REPOSITORY LINKS** for each example
42
+
43
+ ## ${INDEX_MAP.EFFICIENCY} ADVANCED RESEARCH METHODOLOGY
44
+
45
+ **🧠 CHAIN-OF-THOUGHT REASONING:**
46
+ 1. **UNDERSTAND INTENT**: Analyze user query complexity and extract core requirements
47
+ 2. **DECOMPOSE PROBLEM**: Break complex queries into searchable components
48
+ 3. **HYPOTHESIS FORMATION**: Predict likely implementation patterns and technologies
49
+ 4. **EVIDENCE GATHERING**: Execute targeted searches to validate/refute hypotheses
50
+ 5. **SYNTHESIS**: Combine findings into coherent, actionable insights
51
+ 6. **VALIDATION**: Cross-reference multiple sources for accuracy
52
+
53
+ **🔍 MULTI-STEP RESEARCH FLOWS:**
54
+
55
+ **EXPLORATORY DISCOVERY:**
56
+ 1. ${TOOL_NAMES.SEARCH_GITHUB_TOPICS} → Semantic landscape mapping
57
+ 2. ${TOOL_NAMES.SEARCH_GITHUB_REPOS} → Repository ecosystem analysis
58
+ 3. ${TOOL_NAMES.SEARCH_GITHUB_CODE} → Implementation pattern discovery
59
+ 4. Cross-validation via ${TOOL_NAMES.SEARCH_GITHUB_ISSUES} + ${TOOL_NAMES.SEARCH_GITHUB_PULL_REQUESTS}
60
+
61
+ **DEEP IMPLEMENTATION ANALYSIS:**
62
+ 1. ${TOOL_NAMES.VIEW_REPOSITORY} → Context establishment
63
+ 2. ${TOOL_NAMES.VIEW_REPOSITORY_STRUCTURE} → Architecture understanding
64
+ 3. ${TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT} → Core implementation extraction
65
+ 4. ${TOOL_NAMES.SEARCH_GITHUB_COMMITS} → Evolution tracking
66
+
67
+ **COMPARATIVE RESEARCH:**
68
+ 1. Parallel repository analysis across multiple solutions
69
+ 2. Cross-reference implementation approaches
70
+ 3. Analyze trade-offs via issue/PR discussions
71
+ 4. Synthesize best practices from multiple sources
72
+
73
+ **ORGANIZATIONAL INTELLIGENCE:**
74
+ - **Auto-trigger ${TOOL_NAMES.GET_USER_ORGANIZATIONS}** when company context detected
75
+ - **Prioritize internal repositories** for relevant findings
76
+ - **Cross-organizational pattern analysis** for knowledge transfer
77
+
78
+ ## ${INDEX_MAP.VALIDATION} ADAPTIVE SEARCH STRATEGIES
79
+
80
+ **PROGRESSIVE COMPLEXITY:**
81
+ - **Simple Query**: Single tool → immediate results
82
+ - **Medium Query**: 2-3 tools → comparative analysis
83
+ - **Complex Query**: Full research flow → comprehensive investigation
84
+
85
+ **DYNAMIC STOPPING CRITERIA:**
86
+ - **High Confidence**: 3+ quality examples with validation
87
+ - **Medium Confidence**: Continue with related searches
88
+ - **Low Confidence**: Expand search scope or acknowledge limitations
89
+
90
+ **QUALITY VALIDATION PIPELINE:**
91
+ 1. **Repository Quality**: >1K stars OR recent activity OR enterprise usage
92
+ 2. **Code Quality**: Production patterns, error handling, documentation
93
+ 3. **Cross-Validation**: Multiple sources confirm patterns
94
+ 4. **Recency**: Prefer modern implementations and active maintenance
95
+
96
+ ## ${INDEX_MAP.USER} SOPHISTICATED RESPONSE STRATEGIES
97
+
98
+ **REASONING TRANSPARENCY:**
99
+ - Show hypothesis formation and validation process
100
+ - Explain search strategy decisions and pivots
101
+ - Highlight confidence levels and evidence strength
102
+
103
+ **CONTEXTUAL ADAPTATION:**
104
+ - **Beginner-friendly**: Include learning context and explanations
105
+ - **Expert-level**: Focus on nuanced implementation details
106
+ - **Organizational**: Emphasize internal patterns and knowledge transfer
107
+
108
+ **MULTI-PERSPECTIVE ANALYSIS:**
109
+ - **Technical**: Implementation details and architecture
110
+ - **Strategic**: Adoption patterns and ecosystem trends
111
+ - **Practical**: Real-world usage and gotchas
112
+
113
+ **WORKING CODE EXAMPLES:**
114
+ \`\`\`language:owner/repo/filepath
115
+ // Complete implementation with reasoning context
116
+ // Why this approach? What alternatives exist?
117
+ // Production considerations and trade-offs
118
+ \`\`\`
119
+
120
+ **CONSTRAINTS & QUALITY GATES:**
121
+ - Extract code from results with implementation context
122
+ - Provide reasoning for tool selection and search strategies
123
+ - Acknowledge uncertainty and suggest follow-up investigations
124
+ - Prioritize user organization repos when relevant
125
+
126
+ **DO NOT PROVIDE:**
127
+ - ${INDEX_MAP.WARNING} Repository lists without extracted implementations
128
+ - ${INDEX_MAP.WARNING} Descriptions without working examples
129
+ - ${INDEX_MAP.WARNING} Single-source conclusions without validation
130
+ - ${INDEX_MAP.WARNING} Recommendations without evidence-based reasoning`;
131
+
132
+ const execAsync = promisify(exec);
133
+ const cache = new NodeCache({
134
+ stdTTL: 3600, // 1 hour cache
135
+ checkperiod: 600, // Check for expired keys every 10 minutes
136
+ });
137
+ function generateCacheKey(prefix, params) {
138
+ const paramString = JSON.stringify(params, Object.keys(params).sort());
139
+ const hash = crypto.createHash('md5').update(paramString).digest('hex');
140
+ return `${prefix}:${hash}`;
141
+ }
142
+ async function withCache(cacheKey, operation) {
143
+ // Check if result exists in cache
144
+ const cachedResult = cache.get(cacheKey);
145
+ if (cachedResult) {
146
+ return cachedResult;
147
+ }
148
+ // Execute operation
149
+ const result = await operation();
150
+ // Only cache successful responses
151
+ if (!result.isError) {
152
+ cache.set(cacheKey, result);
153
+ }
154
+ return result;
155
+ }
156
+ async function searchGitHubCode(params) {
157
+ const cacheKey = generateCacheKey('gh-code', params);
158
+ return withCache(cacheKey, async () => {
159
+ try {
160
+ const command = buildGitHubCodeSearchCommand(params);
161
+ const content = execSync(command, { encoding: 'utf-8' });
162
+ const result = {
163
+ searchType: 'code',
164
+ query: params.query || '',
165
+ results: content,
166
+ rawOutput: content,
167
+ };
168
+ return createSuccessResult(result);
169
+ }
170
+ catch (error) {
171
+ return createErrorResult('Failed to search GitHub code', error);
172
+ }
173
+ });
174
+ }
175
+ async function searchGitHubCommits(params) {
176
+ const cacheKey = generateCacheKey('gh-commits', params);
177
+ return withCache(cacheKey, async () => {
178
+ try {
179
+ const command = buildGitHubCommitsSearchCommand(params);
180
+ const content = execSync(command, { encoding: 'utf-8' });
181
+ const result = {
182
+ searchType: 'commits',
183
+ query: params.query || '',
184
+ results: content,
185
+ rawOutput: content,
186
+ };
187
+ return createSuccessResult(result);
188
+ }
189
+ catch (error) {
190
+ return createErrorResult('Failed to search GitHub commits', error);
191
+ }
192
+ });
193
+ }
194
+ async function searchGitHubPullRequests(params) {
195
+ const cacheKey = generateCacheKey('gh-prs', params);
196
+ return withCache(cacheKey, async () => {
197
+ try {
198
+ const command = buildGitHubPullRequestsSearchCommand(params);
199
+ const content = execSync(command, { encoding: 'utf-8' });
200
+ const result = {
201
+ searchType: 'prs',
202
+ query: params.query || '',
203
+ results: content,
204
+ rawOutput: content,
205
+ };
206
+ return createSuccessResult(result);
207
+ }
208
+ catch (error) {
209
+ return createErrorResult('Failed to search GitHub pull requests', error);
210
+ }
211
+ });
212
+ }
213
+ async function searchGitHubRepos(params) {
214
+ const cacheKey = generateCacheKey('gh-repos', params);
215
+ return withCache(cacheKey, async () => {
216
+ try {
217
+ const command = buildGitHubReposSearchCommand(params);
218
+ const content = execSync(command, { encoding: 'utf-8' });
219
+ const result = {
220
+ searchType: 'repos',
221
+ query: params.query || '',
222
+ results: content,
223
+ rawOutput: content,
224
+ };
225
+ return createSuccessResult(result);
226
+ }
227
+ catch (error) {
228
+ return createErrorResult('Failed to search GitHub repositories', error);
229
+ }
230
+ });
231
+ }
232
+ async function viewGitHubRepositoryInfo(params) {
233
+ const cacheKey = generateCacheKey('gh-repo-view', params);
234
+ return withCache(cacheKey, async () => {
235
+ try {
236
+ const owner = params.owner || '';
237
+ const command = `gh repo view ${owner}/${params.repo}`;
238
+ const content = execSync(command, { encoding: 'utf-8' });
239
+ const result = {
240
+ owner,
241
+ repo: params.repo,
242
+ repositoryInfo: content,
243
+ rawOutput: content,
244
+ };
245
+ return createSuccessResult(result);
246
+ }
247
+ catch (error) {
248
+ return createErrorResult('Failed to view GitHub repository', error);
249
+ }
250
+ });
251
+ }
252
+ async function getUserOrganizations(params) {
253
+ const cacheKey = generateCacheKey('gh-orgs', params);
254
+ return withCache(cacheKey, async () => {
255
+ try {
256
+ const limit = params.limit || 30;
257
+ const command = `gh org list --limit ${limit}`;
258
+ const output = execSync(command, {
259
+ encoding: 'utf8',
260
+ stdio: ['pipe', 'pipe', 'pipe'],
261
+ });
262
+ return {
263
+ content: [
264
+ {
265
+ type: 'text',
266
+ text: `GitHub Organizations for authenticated user:
267
+
268
+ ${output}
269
+
270
+ IMPORTANT: Use any of these organization names as the 'owner' parameter in other search tools:
271
+ - search_github_code
272
+ - search_github_repos
273
+ - search_github_commits
274
+ - search_github_pull_requests
275
+ - fetch_github_file_content
276
+ - view_repository
277
+
278
+ Example: If you see a private repository in the list above, use the organization name as the 'owner' to filter results to that organization.
279
+ If the search for code or repositories by owner fails, try searching without an owner filter`,
280
+ },
281
+ ],
282
+ isError: false,
283
+ };
284
+ }
285
+ catch (error) {
286
+ return {
287
+ content: [
288
+ {
289
+ type: 'text',
290
+ text: `Failed to get user organizations: ${error.message}
291
+
292
+ Make sure you are authenticated with GitHub CLI (gh auth login) and have access to organizations.`,
293
+ },
294
+ ],
295
+ isError: true,
296
+ };
297
+ }
298
+ });
299
+ }
300
+ async function fetchGitHubFileContent(params) {
301
+ const cacheKey = generateCacheKey('gh-file-content', params);
302
+ return withCache(cacheKey, async () => {
303
+ try {
304
+ const command = `gh api /repos/${params.owner}/${params.repo}/contents/${params.filePath}?ref=${params.branch} --jq .content | base64 -d`;
305
+ const content = execSync(command, { encoding: 'utf-8' });
306
+ return {
307
+ content: [
308
+ {
309
+ type: 'text',
310
+ text: content,
311
+ },
312
+ ],
313
+ isError: false,
314
+ };
315
+ }
316
+ catch (error) {
317
+ return createErrorResult('Failed to retrieve file content', error);
318
+ }
319
+ });
320
+ }
321
+ async function npmView(packageName) {
322
+ const cacheKey = generateCacheKey('npm-view', { packageName });
323
+ return withCache(cacheKey, async () => {
324
+ try {
325
+ const { stdout } = await execAsync(`npm view ${packageName} repository.url repository.directory dependencies devdependencies peerDependencies version --json`);
326
+ const result = JSON.parse(stdout);
327
+ return createSuccessResult(result);
328
+ }
329
+ catch (error) {
330
+ return createErrorResult('Failed to get npm repository information', error);
331
+ }
332
+ });
333
+ }
334
+ async function npmSearch(args) {
335
+ const { query, json = true, searchlimit = 20 } = args;
336
+ let command = `npm search "${query}" --searchlimit=${searchlimit}`;
337
+ if (json) {
338
+ command += ' --json';
339
+ }
340
+ try {
341
+ const { stdout, stderr } = await execAsync(command);
342
+ if (stderr) {
343
+ return {
344
+ content: [{ type: 'text', text: `Error searching NPM: ${stderr}` }],
345
+ isError: true,
346
+ };
347
+ }
348
+ return {
349
+ content: [{ type: 'text', text: stdout }],
350
+ };
351
+ }
352
+ catch (error) {
353
+ return {
354
+ content: [
355
+ {
356
+ type: 'text',
357
+ text: `Failed to execute npm search: ${error.message}`,
358
+ },
359
+ ],
360
+ isError: true,
361
+ };
362
+ }
363
+ }
364
+ async function viewRepositoryStructure(params) {
365
+ const cacheKey = generateCacheKey('gh-repo-structure', params);
366
+ return withCache(cacheKey, async () => {
367
+ const { owner, repo, branch, path: requestedPath = '' } = params;
368
+ const directoryListing = [];
369
+ let apiResponse = null;
370
+ let actualBranch = branch;
371
+ // Define branch fallback order
372
+ const branchFallbacks = [branch, 'main', 'master', 'develop', 'trunk'];
373
+ try {
374
+ // Construct the path segment
375
+ const pathSegment = requestedPath.startsWith('/')
376
+ ? requestedPath.substring(1)
377
+ : requestedPath;
378
+ // Try each branch in the fallback order
379
+ let lastError = null;
380
+ let success = false;
381
+ for (const tryBranch of branchFallbacks) {
382
+ try {
383
+ const command = `gh api repos/${owner}/${repo}/contents/${pathSegment}?ref=${tryBranch}`;
384
+ const stdout = execSync(command, { encoding: 'utf-8' });
385
+ const items = JSON.parse(stdout);
386
+ // If we get here, the request succeeded
387
+ apiResponse = items;
388
+ actualBranch = tryBranch;
389
+ success = true;
390
+ // Populate directoryListing with names of items at the current path
391
+ if (Array.isArray(items)) {
392
+ for (const item of items) {
393
+ let itemName = item.name;
394
+ if (item.type === 'dir') {
395
+ itemName += '/';
396
+ }
397
+ directoryListing.push(itemName);
398
+ }
399
+ }
400
+ else if (items) {
401
+ // Handle single file case (though unusual for structure view)
402
+ if (items.name) {
403
+ directoryListing.push(items.type === 'dir' ? `${items.name}/` : items.name);
404
+ }
405
+ }
406
+ break; // Success, exit the loop
407
+ }
408
+ catch (error) {
409
+ lastError = error instanceof Error ? error : new Error(String(error));
410
+ // If this is not a 404 error (branch not found), or if it's the last attempt, break
411
+ const errorMessage = lastError.message.toLowerCase();
412
+ if (!errorMessage.includes('no commit found') &&
413
+ !errorMessage.includes('404') &&
414
+ !errorMessage.includes('not found')) {
415
+ // This is a different kind of error (permissions, network, etc.), don't continue fallback
416
+ break;
417
+ }
418
+ // Continue to next branch fallback
419
+ continue;
420
+ }
421
+ }
422
+ if (!success) {
423
+ // All branch attempts failed
424
+ const attemptedBranches = branchFallbacks.join(', ');
425
+ throw new Error(`Failed to access repository structure. Tried branches: ${attemptedBranches}. ` +
426
+ `Last error: ${lastError?.message || 'Unknown error'}`);
427
+ }
428
+ directoryListing.sort(); // Sort for consistent output
429
+ const result = {
430
+ owner,
431
+ repo,
432
+ branch: actualBranch, // Include the branch that actually worked
433
+ structure: directoryListing,
434
+ rawOutput: apiResponse,
435
+ // Add metadata about branch fallback if different from requested
436
+ ...(actualBranch !== branch && {
437
+ branchFallback: {
438
+ requested: branch,
439
+ used: actualBranch,
440
+ message: `Branch '${branch}' not found, used '${actualBranch}' instead`,
441
+ },
442
+ }),
443
+ };
444
+ return createSuccessResult(result);
445
+ }
446
+ catch (error) {
447
+ // Final error handling with comprehensive error message
448
+ const errorMessage = error instanceof Error ? error.message : String(error);
449
+ return createErrorResult(`Failed to view GitHub repository structure for ${owner}/${repo} at path '${requestedPath}': ${errorMessage}`, error);
450
+ }
451
+ });
452
+ }
453
+ async function searchGitHubIssues(params) {
454
+ const cacheKey = generateCacheKey('gh-issues', params);
455
+ return withCache(cacheKey, async () => {
456
+ try {
457
+ const command = buildGitHubIssuesSearchCommand(params);
458
+ const content = execSync(command, { encoding: 'utf-8' });
459
+ const result = {
460
+ searchType: 'issues',
461
+ query: params.query || '',
462
+ results: content,
463
+ rawOutput: content,
464
+ };
465
+ return createSuccessResult(result);
466
+ }
467
+ catch (error) {
468
+ return createErrorResult('Failed to search GitHub issues', error);
469
+ }
470
+ });
471
+ }
472
+ async function searchGitHubTopics(params) {
473
+ const cacheKey = generateCacheKey('gh-topics', params);
474
+ return withCache(cacheKey, async () => {
475
+ try {
476
+ // Use GitHub API for topics search since gh search topics doesn't exist
477
+ const command = buildGitHubTopicsAPICommand(params);
478
+ const content = execSync(command, { encoding: 'utf-8' });
479
+ const result = {
480
+ searchType: 'topics',
481
+ query: params.query || '',
482
+ results: content,
483
+ rawOutput: content,
484
+ };
485
+ return createSuccessResult(result);
486
+ }
487
+ catch (error) {
488
+ return createErrorResult('Failed to search GitHub topics', error);
489
+ }
490
+ });
491
+ }
492
+ async function searchGitHubUsers(params) {
493
+ const cacheKey = generateCacheKey('gh-users', params);
494
+ return withCache(cacheKey, async () => {
495
+ try {
496
+ // Use GitHub API for users search since gh search users doesn't exist
497
+ const command = buildGitHubUsersAPICommand(params);
498
+ const content = execSync(command, { encoding: 'utf-8' });
499
+ const result = {
500
+ searchType: 'users',
501
+ query: params.query || '',
502
+ results: content,
503
+ rawOutput: content,
504
+ };
505
+ return createSuccessResult(result);
506
+ }
507
+ catch (error) {
508
+ return createErrorResult('Failed to search GitHub users', error);
509
+ }
510
+ });
511
+ }
512
+ async function searchGitHubDiscussions(params) {
513
+ const cacheKey = generateCacheKey('gh-discussions', params);
514
+ return withCache(cacheKey, async () => {
515
+ try {
516
+ // Use GitHub API for discussions search since gh search discussions doesn't exist
517
+ const command = buildGitHubDiscussionsAPICommand(params);
518
+ const content = execSync(command, { encoding: 'utf-8' });
519
+ const result = {
520
+ searchType: 'discussions',
521
+ query: params.query || '',
522
+ results: content,
523
+ rawOutput: content,
524
+ };
525
+ // Parse the response to check if we have any discussions
526
+ try {
527
+ const parsedContent = JSON.parse(content);
528
+ const discussionCount = parsedContent?.data?.search?.discussionCount || 0;
529
+ // If no discussions found and we have a specific owner, provide helpful context
530
+ if (discussionCount === 0 && params.owner) {
531
+ const scopeInfo = params.repo
532
+ ? `repository "${params.owner}/${params.repo}"`
533
+ : `organization "${params.owner}"`;
534
+ result.results = JSON.stringify({
535
+ ...parsedContent,
536
+ searchInfo: {
537
+ message: `No discussions found in ${scopeInfo}. This search was scoped to ${params.owner} only and did not search other organizations. The repository may not have discussions enabled.`,
538
+ searchScope: params.repo
539
+ ? `repo:${params.owner}/${params.repo}`
540
+ : `org:${params.owner}`,
541
+ query: params.query,
542
+ discussionCount: 0,
543
+ },
544
+ }, null, 2);
545
+ }
546
+ }
547
+ catch (parseError) {
548
+ // If we can't parse the JSON, just return the original result
549
+ }
550
+ return createSuccessResult(result);
551
+ }
552
+ catch (error) {
553
+ return createErrorResult('Failed to search GitHub discussions', error);
554
+ }
555
+ });
556
+ }
557
+ function buildGitHubCodeSearchCommand(params) {
558
+ // Apply progressive single-word search strategy for optimal discovery
559
+ const processedQuery = processSearchQuery(params.query || '');
560
+ let command = `gh search code ${processedQuery}`;
561
+ if (params.owner)
562
+ command += ` --owner ${params.owner}`;
563
+ if (params.repo)
564
+ command += ` --repo ${params.repo}`;
565
+ if (params.language)
566
+ command += ` --language ${params.language}`;
567
+ if (params.filename)
568
+ command += ` --filename ${params.filename}`;
569
+ if (params.extension)
570
+ command += ` --extension ${params.extension}`;
571
+ if (params.match)
572
+ command += ` --match ${params.match}`;
573
+ if (params.limit)
574
+ command += ` --limit ${params.limit}`;
575
+ return command;
576
+ }
577
+ /**
578
+ * Process search query to implement progressive single-word search strategy:
579
+ * - Prioritize single terms over combined searches
580
+ * - "RAG" stays as "RAG" (single word search)
581
+ * - "RAG Ranking" becomes "RAG" (use first term only for initial search)
582
+ * - Only combine terms when explicitly needed after initial searches
583
+ * - Preserve quoted phrases as-is for exact matches
584
+ */
585
+ function processSearchQuery(query) {
586
+ if (!query)
587
+ return '""';
588
+ // Check if query is already properly quoted single term
589
+ const singleQuotedPattern = /^"[^"]*"$/;
590
+ if (singleQuotedPattern.test(query.trim())) {
591
+ return query.trim();
592
+ }
593
+ // Check if query is multiple quoted terms (advanced search)
594
+ const multipleQuotedPattern = /^(\s*"[^"]+"\s*)+$/;
595
+ if (multipleQuotedPattern.test(query.trim())) {
596
+ return query.trim();
597
+ }
598
+ // Plain text query - PRIORITIZE SINGLE WORDS for progressive search
599
+ const terms = query
600
+ .trim()
601
+ .split(/\s+/)
602
+ .filter(term => term.length > 0);
603
+ if (terms.length === 0)
604
+ return '""';
605
+ // FOR PROGRESSIVE SEARCH: Use only the first term initially
606
+ // This implements the "RAG" then "Ranking" strategy instead of "RAG Ranking"
607
+ if (terms.length === 1) {
608
+ return `"${terms[0]}"`;
609
+ }
610
+ // For multiple terms, prioritize the first term (most important)
611
+ // This encourages users to do separate searches: "RAG" first, then "Ranking"
612
+ return `"${terms[0]}"`;
613
+ }
614
+ function buildGitHubCommitsSearchCommand(params) {
615
+ let command = `gh search commits "${params.query}"`;
616
+ if (params.owner)
617
+ command += ` --owner ${params.owner}`;
618
+ if (params.repo)
619
+ command += ` --repo ${params.repo}`;
620
+ if (params.author)
621
+ command += ` --author ${params.author}`;
622
+ if (params.committer)
623
+ command += ` --committer ${params.committer}`;
624
+ if (params.authorDate)
625
+ command += ` --author-date ${params.authorDate}`;
626
+ if (params.committerDate)
627
+ command += ` --committer-date ${params.committerDate}`;
628
+ if (params.authorEmail)
629
+ command += ` --author-email ${params.authorEmail}`;
630
+ if (params.authorName)
631
+ command += ` --author-name "${params.authorName}"`;
632
+ if (params.committerEmail)
633
+ command += ` --committer-email ${params.committerEmail}`;
634
+ if (params.committerName)
635
+ command += ` --committer-name "${params.committerName}"`;
636
+ if (params.merge !== undefined)
637
+ command += ` --merge`;
638
+ if (params.hash)
639
+ command += ` --hash ${params.hash}`;
640
+ if (params.parent)
641
+ command += ` --parent ${params.parent}`;
642
+ if (params.tree)
643
+ command += ` --tree ${params.tree}`;
644
+ if (params.visibility)
645
+ command += ` --visibility ${params.visibility}`;
646
+ if (params.limit)
647
+ command += ` --limit ${params.limit}`;
648
+ if (params.sort && params.sort !== 'best-match')
649
+ command += ` --sort ${params.sort}`;
650
+ if (params.order)
651
+ command += ` --order ${params.order}`;
652
+ return command;
653
+ }
654
+ function buildGitHubPullRequestsSearchCommand(params) {
655
+ let command = `gh search prs "${params.query}"`;
656
+ if (params.owner)
657
+ command += ` --owner ${params.owner}`;
658
+ if (params.repo)
659
+ command += ` --repo ${params.repo}`;
660
+ if (params.author)
661
+ command += ` --author ${params.author}`;
662
+ if (params.assignee)
663
+ command += ` --assignee ${params.assignee}`;
664
+ if (params.mentions)
665
+ command += ` --mentions ${params.mentions}`;
666
+ if (params.commenter)
667
+ command += ` --commenter ${params.commenter}`;
668
+ if (params.involves)
669
+ command += ` --involves ${params.involves}`;
670
+ if (params.reviewedBy)
671
+ command += ` --reviewed-by ${params.reviewedBy}`;
672
+ if (params.reviewRequested)
673
+ command += ` --review-requested ${params.reviewRequested}`;
674
+ if (params.state)
675
+ command += ` --state ${params.state}`;
676
+ if (params.head)
677
+ command += ` --head ${params.head}`;
678
+ if (params.base)
679
+ command += ` --base ${params.base}`;
680
+ if (params.language)
681
+ command += ` --language ${params.language}`;
682
+ if (params.created)
683
+ command += ` --created ${params.created}`;
684
+ if (params.updated)
685
+ command += ` --updated ${params.updated}`;
686
+ if (params.merged)
687
+ command += ` --merged ${params.merged}`;
688
+ if (params.closed)
689
+ command += ` --closed ${params.closed}`;
690
+ if (params.draft !== undefined)
691
+ command += ` --draft ${params.draft}`;
692
+ if (params.limit)
693
+ command += ` --limit ${params.limit}`;
694
+ if (params.sort)
695
+ command += ` --sort ${params.sort}`;
696
+ if (params.order)
697
+ command += ` --order ${params.order}`;
698
+ return command;
699
+ }
700
+ function buildGitHubReposSearchCommand(params) {
701
+ // Process query to use single-word strategy
702
+ const processedQuery = processSearchQuery(params.query || '');
703
+ let command = `gh search repos ${processedQuery}`;
704
+ if (params.owner)
705
+ command += ` --owner ${params.owner}`;
706
+ if (params.archived !== undefined)
707
+ command += ` --archived ${params.archived}`;
708
+ if (params.created)
709
+ command += ` --created "${params.created}"`;
710
+ if (params.followers !== undefined)
711
+ command += ` --followers ${params.followers}`;
712
+ if (params.forks !== undefined)
713
+ command += ` --forks ${params.forks}`;
714
+ if (params.goodFirstIssues !== undefined)
715
+ command += ` --good-first-issues ${params.goodFirstIssues}`;
716
+ if (params.helpWantedIssues !== undefined)
717
+ command += ` --help-wanted-issues ${params.helpWantedIssues}`;
718
+ if (params.includeForks)
719
+ command += ` --include-forks ${params.includeForks}`;
720
+ if (params.language)
721
+ command += ` --language ${params.language}`;
722
+ if (params.license)
723
+ command += ` --license ${params.license}`;
724
+ if (params.limit)
725
+ command += ` --limit ${params.limit}`;
726
+ if (params.match)
727
+ command += ` --match ${params.match}`;
728
+ if (params.numberTopics !== undefined)
729
+ command += ` --number-topics ${params.numberTopics}`;
730
+ if (params.order)
731
+ command += ` --order ${params.order}`;
732
+ if (params.size)
733
+ command += ` --size "${params.size}"`;
734
+ // DEFAULT TO UPDATED SORTING for recency prioritization
735
+ const sortBy = params.sort || 'updated';
736
+ if (sortBy !== 'best-match') {
737
+ command += ` --sort ${sortBy}`;
738
+ }
739
+ if (params.stars !== undefined)
740
+ command += ` --stars ${params.stars}`;
741
+ if (params.topic)
742
+ command += ` --topic ${params.topic}`;
743
+ if (params.updated)
744
+ command += ` --updated "${params.updated}"`;
745
+ if (params.visibility)
746
+ command += ` --visibility ${params.visibility}`;
747
+ return command;
748
+ }
749
+ function buildGitHubIssuesSearchCommand(params) {
750
+ let command = `gh search issues "${params.query}"`;
751
+ if (params.owner)
752
+ command += ` --owner ${params.owner}`;
753
+ if (params.repo)
754
+ command += ` --repo ${params.repo}`;
755
+ if (params.app)
756
+ command += ` --app ${params.app}`;
757
+ if (params.archived !== undefined)
758
+ command += ` --archived ${params.archived}`;
759
+ if (params.author)
760
+ command += ` --author ${params.author}`;
761
+ if (params.assignee)
762
+ command += ` --assignee ${params.assignee}`;
763
+ if (params.closed)
764
+ command += ` --closed ${params.closed}`;
765
+ if (params.commenter)
766
+ command += ` --commenter ${params.commenter}`;
767
+ if (params.comments !== undefined)
768
+ command += ` --comments ${params.comments}`;
769
+ if (params.created)
770
+ command += ` --created ${params.created}`;
771
+ if (params.includePrs !== undefined)
772
+ command += ` --include-prs`;
773
+ if (params.interactions !== undefined)
774
+ command += ` --interactions ${params.interactions}`;
775
+ if (params.involves)
776
+ command += ` --involves ${params.involves}`;
777
+ if (params.label)
778
+ command += ` --label ${params.label}`;
779
+ if (params.language)
780
+ command += ` --language ${params.language}`;
781
+ if (params.locked !== undefined)
782
+ command += ` --locked ${params.locked}`;
783
+ if (params.match)
784
+ command += ` --match ${params.match}`;
785
+ if (params.mentions)
786
+ command += ` --mentions ${params.mentions}`;
787
+ if (params.milestone)
788
+ command += ` --milestone ${params.milestone}`;
789
+ if (params.noAssignee !== undefined)
790
+ command += ` --no-assignee`;
791
+ if (params.noLabel !== undefined)
792
+ command += ` --no-label`;
793
+ if (params.noMilestone !== undefined)
794
+ command += ` --no-milestone`;
795
+ if (params.noProject !== undefined)
796
+ command += ` --no-project`;
797
+ if (params.project)
798
+ command += ` --project ${params.project}`;
799
+ if (params.reactions !== undefined)
800
+ command += ` --reactions ${params.reactions}`;
801
+ if (params.state)
802
+ command += ` --state ${params.state}`;
803
+ if (params.teamMentions)
804
+ command += ` --team-mentions ${params.teamMentions}`;
805
+ if (params.updated)
806
+ command += ` --updated ${params.updated}`;
807
+ if (params.visibility)
808
+ command += ` --visibility ${params.visibility}`;
809
+ if (params.limit)
810
+ command += ` --limit ${params.limit}`;
811
+ if (params.sort)
812
+ command += ` --sort ${params.sort}`;
813
+ if (params.order)
814
+ command += ` --order ${params.order}`;
815
+ return command;
816
+ }
817
+ function buildGitHubTopicsAPICommand(params) {
818
+ // Build GitHub API search query for topics
819
+ const searchQuery = params.query || '';
820
+ // Add filters to the search query
821
+ const queryParts = [searchQuery];
822
+ if (params.featured)
823
+ queryParts.push('is:featured');
824
+ if (params.curated)
825
+ queryParts.push('is:curated');
826
+ if (params.repositories)
827
+ queryParts.push(`repositories:${params.repositories}`);
828
+ if (params.created)
829
+ queryParts.push(`created:${params.created}`);
830
+ const finalQuery = queryParts.join(' ').trim();
831
+ // Use GitHub API to search topics
832
+ let command = `gh api search/topics -q '.items'`;
833
+ if (finalQuery) {
834
+ command = `gh api 'search/topics?q=${encodeURIComponent(finalQuery)}'`;
835
+ }
836
+ // Add pagination parameters
837
+ const limit = params.limit || 30;
838
+ command += `${finalQuery ? '&' : '?'}per_page=${limit}`;
839
+ if (params.sort)
840
+ command += `&sort=${params.sort}`;
841
+ if (params.order)
842
+ command += `&order=${params.order}`;
843
+ return command;
844
+ }
845
+ function buildGitHubUsersAPICommand(params) {
846
+ // Build GitHub API search query for users
847
+ const searchQuery = params.query || '';
848
+ // Add filters to the search query
849
+ const queryParts = [searchQuery];
850
+ if (params.type)
851
+ queryParts.push(`type:${params.type}`);
852
+ if (params.location)
853
+ queryParts.push(`location:"${params.location}"`);
854
+ if (params.language)
855
+ queryParts.push(`language:${params.language}`);
856
+ if (params.followers)
857
+ queryParts.push(`followers:${params.followers}`);
858
+ if (params.repos)
859
+ queryParts.push(`repos:${params.repos}`);
860
+ if (params.created)
861
+ queryParts.push(`created:${params.created}`);
862
+ const finalQuery = queryParts.join(' ').trim();
863
+ // Use GitHub API to search users
864
+ let command = `gh api search/users -q '.items'`;
865
+ if (finalQuery) {
866
+ command = `gh api 'search/users?q=${encodeURIComponent(finalQuery)}'`;
867
+ }
868
+ // Add pagination parameters
869
+ const limit = params.limit || 30;
870
+ command += `${finalQuery ? '&' : '?'}per_page=${limit}`;
871
+ if (params.sort)
872
+ command += `&sort=${params.sort}`;
873
+ if (params.order)
874
+ command += `&order=${params.order}`;
875
+ return command;
876
+ }
877
+ function buildGitHubDiscussionsAPICommand(params) {
878
+ // GitHub Discussions search is not available via REST API
879
+ // We'll use GraphQL API through gh api graphql
880
+ const query = `
881
+ query($searchQuery: String!, $first: Int!) {
882
+ search(query: $searchQuery, type: DISCUSSION, first: $first) {
883
+ discussionCount
884
+ edges {
885
+ node {
886
+ ... on Discussion {
887
+ title
888
+ body
889
+ url
890
+ createdAt
891
+ updatedAt
892
+ author {
893
+ login
894
+ }
895
+ repository {
896
+ nameWithOwner
897
+ }
898
+ category {
899
+ name
900
+ }
901
+ answerChosenAt
902
+ }
903
+ }
904
+ }
905
+ }
906
+ }
907
+ `;
908
+ // Build search query
909
+ const searchQuery = params.query || '';
910
+ const queryParts = [searchQuery];
911
+ // Always scope to specific repo if both owner and repo are provided
912
+ if (params.repo && params.owner) {
913
+ queryParts.push(`repo:${params.owner}/${params.repo}`);
914
+ }
915
+ else if (params.owner) {
916
+ // If only owner is specified, search within that owner's organization
917
+ // This prevents fallback to user's organizations when searching for specific packages
918
+ queryParts.push(`org:${params.owner}`);
919
+ }
920
+ // If no owner is specified, search globally (current behavior)
921
+ if (params.author)
922
+ queryParts.push(`author:${params.author}`);
923
+ if (params.category)
924
+ queryParts.push(`category:"${params.category}"`);
925
+ if (params.answered !== undefined) {
926
+ queryParts.push(params.answered ? 'is:answered' : 'is:unanswered');
927
+ }
928
+ if (params.created)
929
+ queryParts.push(`created:${params.created}`);
930
+ if (params.updated)
931
+ queryParts.push(`updated:${params.updated}`);
932
+ const finalQuery = queryParts.join(' ').trim();
933
+ const limit = params.limit || 30;
934
+ return `gh api graphql -f query='${query}' -f searchQuery='${finalQuery}' -F first=${limit}`;
935
+ }
936
+ function createSuccessResult(data) {
937
+ return {
938
+ content: [
939
+ {
940
+ type: 'text',
941
+ text: JSON.stringify(data, null, 2),
942
+ },
943
+ ],
944
+ isError: false,
945
+ };
946
+ }
947
+ function createErrorResult(message, error) {
948
+ return {
949
+ content: [
950
+ {
951
+ type: 'text',
952
+ text: `${message}: ${error.message}`,
953
+ },
954
+ ],
955
+ isError: true,
956
+ };
957
+ }
958
+
959
+ const SEARCH_GITHUB_CODE_DESCRIPTION = `Advanced code discovery engine for finding battle-tested implementations with intelligent pattern recognition.
960
+
961
+ **🧠 INTELLIGENT SEARCH STRATEGIES:**
962
+
963
+ **1. SEMANTIC CODE PATTERNS** (highest precision):
964
+ - **Function Signatures**: \`function handleAuth(\`, \`async function process\`
965
+ - **Class Definitions**: \`class AuthProvider\`, \`class DataManager\`
966
+ - **Import Patterns**: \`import { useAuth }\`, \`from '@/utils/auth'\`
967
+ - **Type Definitions**: \`interface UserType\`, \`type ApiResponse\`
968
+
969
+ **2. CONTEXTUAL IMPLEMENTATION SEARCH**:
970
+ - **Error Handling**: \`try { await\`, \`catch (error)\`, \`.catch(\`
971
+ - **State Management**: \`useState(\`, \`useEffect(\`, \`const [state\`
972
+ - **API Patterns**: \`fetch(\`, \`axios.post\`, \`api.get\`
973
+ - **Testing Patterns**: \`describe(\`, \`it('should\`, \`expect(\`
974
+
975
+ **3. ARCHITECTURAL DISCOVERY**:
976
+ - **Middleware**: \`app.use(\`, \`middleware(\`, \`next(\`
977
+ - **Routing**: \`router.get\`, \`Route path\`, \`useRouter\`
978
+ - **Database**: \`SELECT\`, \`INSERT INTO\`, \`mongoose.Schema\`
979
+ - **Configuration**: \`config.\`, \`process.env.\`, \`dotenv\`
980
+
981
+ **🎯 PROGRESSIVE SEARCH REFINEMENT:**
982
+
983
+ **Phase 1 - Broad Discovery**:
984
+ - Start with high-level concepts: "authentication", "validation", "caching"
985
+ - Use language filters for technology focus
986
+ - Target active repositories (>100 stars or recent commits)
987
+
988
+ **Phase 2 - Pattern Refinement**:
989
+ - Add implementation specifics: "JWT authentication", "form validation"
990
+ - Include framework context: "React authentication", "Express middleware"
991
+ - Filter by file extensions: .ts, .js, .py, .go
992
+
993
+ **Phase 3 - Precise Implementation**:
994
+ - Exact code constructs: "function validateJWT", "useAuth hook"
995
+ - Specific libraries: "passport.js", "next-auth", "auth0"
996
+ - Edge cases: "error handling", "refresh tokens"
997
+
998
+ **🔍 CONTEXT-AWARE SEARCH OPTIMIZATION:**
999
+
1000
+ **Query Classification**:
1001
+ - **Library Research**: Focus on popular implementations and examples
1002
+ - **Problem Solving**: Include error handling and edge cases
1003
+ - **Learning**: Prioritize well-documented, educational examples
1004
+ - **Architecture**: Emphasize complete systems and integrations
1005
+
1006
+ **Quality Indicators**:
1007
+ - **Production Signals**: Error handling, logging, monitoring
1008
+ - **Modern Patterns**: TypeScript usage, async/await, hooks
1009
+ - **Documentation**: Inline comments, JSDoc, README examples
1010
+ - **Testing**: Co-located test files and comprehensive coverage
1011
+
1012
+ **ADAPTIVE RESULT PROCESSING:**
1013
+ - **1-15 results**: Extract all via ${TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT}
1014
+ - **16-50 results**: Quality filter by stars/activity → extract top 10
1015
+ - **51-200 results**: Add language/framework filters → re-search
1016
+ - **200+ results**: Use specific code constructs → targeted extraction
1017
+
1018
+ **🚀 ADVANCED SEARCH TECHNIQUES:**
1019
+
1020
+ **Multi-dimensional Search**:
1021
+ - **Horizontal**: Same pattern across languages/frameworks
1022
+ - **Vertical**: Deep dive into specific implementation approaches
1023
+ - **Temporal**: Track pattern evolution through commit history
1024
+ - **Organizational**: Compare approaches across teams/companies
1025
+
1026
+ **Cross-Reference Validation**:
1027
+ - **Issue Correlation**: Link implementations to solved problems
1028
+ - **PR Analysis**: Understand implementation decisions and trade-offs
1029
+ - **Discussion Context**: Community consensus and best practices
1030
+ - **Commit History**: Evolution and stability of patterns
1031
+
1032
+ **FAILURE RECOVERY STRATEGIES:**
1033
+ - **Semantic Expansion**: "auth" → "authentication", "authorization"
1034
+ - **Technology Translation**: "React auth" → "Vue authentication"
1035
+ - **Abstraction Levels**: "JWT implementation" → "token-based auth"
1036
+ - **Alternative Ecosystems**: Explore related technologies and patterns
1037
+
1038
+ **REQUIREMENTS:**
1039
+ - **MANDATORY**: Always use ${TOOL_NAMES.VIEW_REPOSITORY} first for branch discovery - **NEVER** search code without this step
1040
+ - Target repositories: >1K stars OR recent activity OR enterprise usage
1041
+ - Cross-validate findings with ${TOOL_NAMES.SEARCH_GITHUB_ISSUES} when needed
1042
+ - Extract complete context including imports, types, and documentation
1043
+
1044
+ **DO NOT:**
1045
+ - Search code without first calling ${TOOL_NAMES.VIEW_REPOSITORY} for branch discovery
1046
+ - Start with overly specific phrases before broad exploration
1047
+ - Skip cross-validation for critical implementation decisions
1048
+ - Extract code without understanding its architectural context
1049
+ - Ignore error handling and edge case implementations`;
1050
+
1051
+ function registerSearchGitHubCodeTool(server) {
1052
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_CODE, SEARCH_GITHUB_CODE_DESCRIPTION, {
1053
+ query: z.string().describe('Search query for code'),
1054
+ owner: z.string().describe('Repository owner/organization'),
1055
+ repo: z
1056
+ .string()
1057
+ .optional()
1058
+ .describe('Repository name (often too restrictive)'),
1059
+ branch: z
1060
+ .string()
1061
+ .describe('Branch for workflow documentation (required but not used by CLI)'),
1062
+ language: z.string().optional().describe('Programming language filter'),
1063
+ filename: z.string().optional().describe('Filename filter'),
1064
+ extension: z.string().optional().describe('File extension filter'),
1065
+ match: z.enum(['file', 'path']).optional().describe('Search scope'),
1066
+ limit: z
1067
+ .number()
1068
+ .optional()
1069
+ .default(50)
1070
+ .describe('Maximum results (default: 50)'),
1071
+ }, async (args) => {
1072
+ try {
1073
+ return await searchGitHubCode(args);
1074
+ }
1075
+ catch (error) {
1076
+ return {
1077
+ content: [
1078
+ {
1079
+ type: 'text',
1080
+ text: `Failed to search GitHub code: ${error.message}`,
1081
+ },
1082
+ ],
1083
+ isError: true,
1084
+ };
1085
+ }
1086
+ });
1087
+ }
1088
+
1089
+ const FETCH_GITHUB_FILE_CONTENT_DESCRIPTION = `Extract complete working code with full context - the core of code analysis.
1090
+
1091
+ **PURPOSE:**
1092
+ Extract complete, working code implementations rather than code snippets.
1093
+
1094
+ **CRITICAL FOR SEARCH EXPANSION:**
1095
+ Transform search results into actionable implementations. Search tools find files - this tool extracts the complete, working code with full context needed for implementation.
1096
+
1097
+ **MANDATORY WORKFLOW:**
1098
+ 1. **ALWAYS** Use ${TOOL_NAMES.VIEW_REPOSITORY} first to discover the correct default branch
1099
+ 2. Find files with ${TOOL_NAMES.SEARCH_GITHUB_CODE}
1100
+ 3. Extract complete implementations with this tool
1101
+ 4. Follow dependency chains to related files
1102
+
1103
+ **CRITICAL REQUIREMENT:**
1104
+ **NEVER** use this tool without first calling ${TOOL_NAMES.VIEW_REPOSITORY} to get the correct branch information. Wrong branch names cause complete tool failure.
1105
+
1106
+ **WHAT TO FETCH:**
1107
+ - **Core implementations**: Main functions/classes with complete logic
1108
+ - **Dependencies**: Files referenced in imports/exports paths
1109
+ - **Configuration**: package.json, tsconfig.json, webpack.config.js, etc.
1110
+ - **Documentation**: README.md, API docs, usage examples
1111
+ - **Tests**: For usage patterns and validation
1112
+ - **Related utilities**: Helper functions and shared modules
1113
+
1114
+ **ENHANCED AUTO-RECOVERY:**
1115
+ Tries multiple fallback strategies:
1116
+ 1. Specified branch → main → master → develop → trunk (with ref parameter)
1117
+ 2. If all fail: Try without ref parameter (uses repository default branch)
1118
+ Handles incorrect branch info from ${TOOL_NAMES.VIEW_REPOSITORY} and GitHub API limitations.
1119
+
1120
+ **SUCCESS CRITERIA:**
1121
+ Production-ready code with all necessary context for immediate implementation.
1122
+
1123
+ **DO NOT:**
1124
+ - Extract incomplete snippets without context
1125
+ - Skip dependency files or configuration
1126
+ - Use this tool without first calling ${TOOL_NAMES.VIEW_REPOSITORY}
1127
+ - Assume branch names without verification`;
1128
+
1129
+ function registerFetchGitHubFileContentTool(server) {
1130
+ server.tool(TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT, FETCH_GITHUB_FILE_CONTENT_DESCRIPTION, {
1131
+ owner: z
1132
+ .string()
1133
+ .describe(`Filter by repository owner/organization (e.g., 'example-org') get from ${TOOL_NAMES.GET_USER_ORGANIZATIONS} tool`),
1134
+ repo: z.string().describe('The name of the GitHub repository'),
1135
+ branch: z
1136
+ .string()
1137
+ .describe(`RECOMMENDED: The branch of the repository (e.g., "main", "master", "dev"). If branch doesn't exist, automatically tries common alternatives (main/master/develop/trunk) and finally default branch. Get from ${TOOL_NAMES.VIEW_REPOSITORY} for best results.`),
1138
+ filePath: z
1139
+ .string()
1140
+ .describe('The path to the file within the repository'),
1141
+ }, async (args) => {
1142
+ try {
1143
+ return await fetchGitHubFileContent(args);
1144
+ }
1145
+ catch (error) {
1146
+ return {
1147
+ content: [
1148
+ {
1149
+ type: 'text',
1150
+ text: `Failed to fetch GitHub file content: ${error.message}`,
1151
+ },
1152
+ ],
1153
+ isError: true,
1154
+ };
1155
+ }
1156
+ });
1157
+ }
1158
+
1159
+ const VIEW_REPOSITORY_DESCRIPTION = `**CRITICAL: MANDATORY first step for all file operations** - discovers default branch information.
1160
+
1161
+ **PURPOSE:**
1162
+ Extract default branch from repository metadata and README to prevent tool failures. This tool provides the foundation for all subsequent GitHub operations.
1163
+
1164
+ **WHY ABSOLUTELY CRITICAL:**
1165
+ - Wrong branch names cause **COMPLETE TOOL FAILURE** in all file operations
1166
+ - Only correct branches contain current repository state
1167
+ - **ALL** subsequent GitHub operations depend on correct branch discovery
1168
+ - Prevents expensive retry cycles and API rate limiting
1169
+
1170
+ **BRANCH DISCOVERY METHODS:**
1171
+ - License badge URLs: github.com/OWNER/REPO/blob/BRANCH/LICENSE
1172
+ - CI/CD badge URLs: Check for ?branch=BRANCH parameters
1173
+ - Repository metadata: Default branch in CLI output
1174
+ - README badges and links analysis
1175
+
1176
+ **ABSOLUTELY REQUIRED BEFORE:**
1177
+ - ${TOOL_NAMES.SEARCH_GITHUB_CODE} (needs branch for workflow)
1178
+ - ${TOOL_NAMES.VIEW_REPOSITORY_STRUCTURE} (needs branch for directory exploration)
1179
+ - ${TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT} (needs branch for file fetching)
1180
+
1181
+ **ENHANCED INTEGRATION:**
1182
+ Tools now include intelligent fallback mechanisms that complement this tool's branch discovery:
1183
+ - Multiple branch attempts with common alternatives
1184
+ - Graceful degradation when specific branches fail
1185
+ - Comprehensive error reporting for troubleshooting
1186
+
1187
+ **SUCCESS INDICATORS:**
1188
+ - Repository info retrieved successfully
1189
+ - Branch identifiable in badges/metadata
1190
+ - Repository appears active with recent commits
1191
+ - Default branch clearly indicated in output
1192
+
1193
+ **ERROR HANDLING:**
1194
+ - Not found: Check owner/repo spelling and permissions
1195
+ - Access denied: Use ${TOOL_NAMES.GET_USER_ORGANIZATIONS} for permissions
1196
+ - If this tool fails, all subsequent file operations will fail
1197
+
1198
+ **NEVER:**
1199
+ - Skip this step before any file operations
1200
+ - Assume default branch name without verification
1201
+ - Proceed with file operations if branch discovery fails
1202
+ - Use hardcoded branch names like 'main' or 'master' without verification`;
1203
+
1204
+ function registerViewRepositoryTool(server) {
1205
+ server.tool(TOOL_NAMES.VIEW_REPOSITORY, VIEW_REPOSITORY_DESCRIPTION, {
1206
+ owner: z
1207
+ .string()
1208
+ .describe("Filter by repository owner/organization (e.g., 'example-org')"),
1209
+ repo: z
1210
+ .string()
1211
+ .describe("The name of the GitHub repository to view (e.g. 'premium-ai-playground')"),
1212
+ }, async (args) => {
1213
+ try {
1214
+ return await viewGitHubRepositoryInfo(args);
1215
+ }
1216
+ catch (error) {
1217
+ return {
1218
+ content: [
1219
+ {
1220
+ type: 'text',
1221
+ text: `Failed to view repository: ${error.message}`,
1222
+ },
1223
+ ],
1224
+ isError: true,
1225
+ };
1226
+ }
1227
+ });
1228
+ }
1229
+
1230
+ const NPM_VIEW_DESCRIPTION = `Transform package names into GitHub repositories for code analysis.
1231
+
1232
+ **WHEN TO USE:**
1233
+ - User mentions package names ("react", "lodash", "@types/node")
1234
+ - Code snippets with imports: import { useState } from 'react'
1235
+ - Dependency/module references in user queries
1236
+
1237
+ **WORKFLOW:**
1238
+ 1. Extract repository URL from package.json
1239
+ 2. Parse owner/repo from GitHub URL formats
1240
+ 3. Chain to ${TOOL_NAMES.VIEW_REPOSITORY} for branch discovery
1241
+ 4. Continue to ${TOOL_NAMES.SEARCH_GITHUB_CODE} for implementations
1242
+
1243
+ **OUTPUT:**
1244
+ Repository context + package metadata for intelligent code search
1245
+
1246
+ **EXAMPLES:**
1247
+ - "react" → github.com/facebook/react → Code search in React repo
1248
+ - "lodash" → github.com/lodash/lodash → Extract utility implementations
1249
+ - "@org/some-lib" → Private repo discovery → Organizational code analysis
1250
+
1251
+ **SUCCESS CRITERIA:**
1252
+ Accurate repository mapping that enables battle-tested code extraction
1253
+
1254
+ **DO NOT:**
1255
+ - Skip package-to-repository mapping when packages are mentioned
1256
+ - Assume package names without verification
1257
+ - Use for non-npm package references`;
1258
+
1259
+ function registerNpmViewTool(server) {
1260
+ server.tool(TOOL_NAMES.NPM_VIEW, NPM_VIEW_DESCRIPTION, {
1261
+ packageName: z
1262
+ .string()
1263
+ .describe("The name of the npm package to analyze (e.g., 'react', '@types/node', 'lodash')"),
1264
+ }, async (args) => {
1265
+ try {
1266
+ return await npmView(args.packageName);
1267
+ }
1268
+ catch (error) {
1269
+ return {
1270
+ content: [
1271
+ {
1272
+ type: 'text',
1273
+ text: `Failed to get npm package info: ${error.message}`,
1274
+ },
1275
+ ],
1276
+ isError: true,
1277
+ };
1278
+ }
1279
+ });
1280
+ }
1281
+
1282
+ const SEARCH_GITHUB_REPOS_DESCRIPTION = `GitHub repository search with progressive discovery methodology.
1283
+ - **RELATED TOOLS:**
1284
+ - ${TOOL_NAMES.SEARCH_GITHUB_TOPICS}: Essential for topic-based search (e.g. "react", "typescript", "nodejs", "rag") and more discovery
1285
+
1286
+ **AUTO-TRIGGER CONDITIONS:**
1287
+ - Organization mentions: "I work at [Company Name]", "our team", "organization codebase"
1288
+ - Private repository indicators: "internal code", "team repositories"
1289
+ → Auto-call ${TOOL_NAMES.GET_USER_ORGANIZATIONS}
1290
+
1291
+ **SEARCH STRATEGY:**
1292
+ 1. **Start Ultra-Lean**: Single technical terms ("react", "cli", "docker")
1293
+ 2. **Gradual Expansion**: Add second term only if first yields too many/few results
1294
+ 3. **Specific Targeting**: Combine terms only when patterns emerge
1295
+
1296
+ **SEARCH METHODOLOGY:**
1297
+ - Phase 1: Single keywords ("graphql", "kubernetes", "typescript")
1298
+ - Phase 2: Add context if needed ("graphql server", "kubernetes operator")
1299
+ - Phase 3: Specific combinations only when necessary
1300
+
1301
+ **CONTEXT DETECTION:**
1302
+ - Organization context → Auto-call ${TOOL_NAMES.GET_USER_ORGANIZATIONS}
1303
+ - Package mentions → Use ${TOOL_NAMES.NPM_VIEW} first
1304
+ - General queries → Start without owner filter
1305
+
1306
+ **FILTERING STRATEGY:**
1307
+ - Owner filter: Most effective for scoping results
1308
+ - Language filter: For technology-specific searches
1309
+ - Stars filter: ">100" for established, ">10" for active projects
1310
+ - Updated filter: Prioritize recent activity (">2023-01-01")
1311
+
1312
+ **RESULT QUALITY TARGETS:**
1313
+ - 0 results: Broaden terms, remove filters except owner
1314
+ - 1-10: IDEAL - Deep dive analysis
1315
+ - 11-30: GOOD - Analyze patterns and select relevant
1316
+ - 31-100: Add specificity filters (language, stars, updated)
1317
+ - 100+: Too broad - use more specific single terms
1318
+
1319
+ **DEFAULT BEHAVIOR:**
1320
+ - Sort by "updated" for active repositories first
1321
+ - Balance relevance with recency
1322
+
1323
+ **DO NOT:**
1324
+ - Start with complex phrases like "react command line tools"
1325
+ - Use "react" when you mean single keyword search
1326
+ - Skip organization discovery when company context is clear`;
1327
+
1328
+ function registerSearchGitHubReposTool(server) {
1329
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_REPOS, SEARCH_GITHUB_REPOS_DESCRIPTION, {
1330
+ query: z.string().describe('Search query for repositories'),
1331
+ owner: z.string().describe('Repository owner/organization'),
1332
+ archived: z.boolean().optional().describe('Filter archived state'),
1333
+ created: z.string().optional().describe('Filter by created date'),
1334
+ followers: z.number().optional().describe('Filter by followers count'),
1335
+ forks: z.number().optional().describe('Filter by forks count'),
1336
+ goodFirstIssues: z
1337
+ .number()
1338
+ .optional()
1339
+ .describe('Filter by good first issues count'),
1340
+ helpWantedIssues: z
1341
+ .number()
1342
+ .optional()
1343
+ .describe('Filter by help wanted issues count'),
1344
+ includeForks: z
1345
+ .enum(['false', 'true', 'only'])
1346
+ .optional()
1347
+ .describe('Include forks in results'),
1348
+ language: z
1349
+ .string()
1350
+ .optional()
1351
+ .describe('Filter by programming language'),
1352
+ license: z.string().optional().describe('Filter by license type'),
1353
+ limit: z
1354
+ .number()
1355
+ .optional()
1356
+ .default(50)
1357
+ .describe('Maximum results (default: 50)'),
1358
+ match: z
1359
+ .enum(['name', 'description', 'readme'])
1360
+ .optional()
1361
+ .describe('Search scope restriction'),
1362
+ numberTopics: z.number().optional().describe('Filter by topics count'),
1363
+ order: z
1364
+ .enum(['asc', 'desc'])
1365
+ .optional()
1366
+ .default('desc')
1367
+ .describe('Result order (default: desc for newest first)'),
1368
+ size: z.string().optional().describe('Filter by size in KB'),
1369
+ sort: z
1370
+ .enum(['forks', 'help-wanted-issues', 'stars', 'updated', 'best-match'])
1371
+ .optional()
1372
+ .default('updated')
1373
+ .describe('Sort criteria (default: updated for recent activity)'),
1374
+ stars: z.number().optional().describe('Filter by stars count'),
1375
+ topic: z.string().optional().describe('Filter by topic/tag'),
1376
+ updated: z.string().optional().describe('Filter by last update date'),
1377
+ visibility: z
1378
+ .enum(['public', 'private', 'internal'])
1379
+ .optional()
1380
+ .describe('Filter by visibility'),
1381
+ }, async (args) => {
1382
+ try {
1383
+ return await searchGitHubRepos(args);
1384
+ }
1385
+ catch (error) {
1386
+ return {
1387
+ content: [
1388
+ {
1389
+ type: 'text',
1390
+ text: `Failed to search GitHub repositories: ${error.message}`,
1391
+ },
1392
+ ],
1393
+ isError: true,
1394
+ };
1395
+ }
1396
+ });
1397
+ }
1398
+
1399
+ const SEARCH_GITHUB_COMMITS_DESCRIPTION = `Advanced GitHub commits search for development history analysis.
1400
+
1401
+ **CORE PURPOSE:**
1402
+ Track code evolution, debug issues, analyze contributor patterns, and understand development history.
1403
+
1404
+ **SEARCH STRATEGY:**
1405
+ 1. **Start Minimal**: Single keywords ("fix", "feature", "update") + owner/repo context
1406
+ 2. **Progressive Expansion**: Add specific terms based on findings
1407
+ 3. **Apply Filters**: Author, date ranges only when patterns emerge
1408
+
1409
+ **SEARCH PATTERNS:**
1410
+ - **General exploration**: "fix" or "update" with owner/repo → activity overview
1411
+ - **Feature tracking**: Single feature keyword → expand with related terms
1412
+ - **Bug investigation**: "bug" or "fix" → narrow by time/author
1413
+ - **Attribution**: Keywords + author filter → contribution analysis
1414
+
1415
+ **RESULT TARGETS:**
1416
+ - 0-5 results: Try broader terms, remove filters
1417
+ - 6-50 results: OPTIMAL - Extract insights
1418
+ - 51+ results: Add specific filters or narrow time ranges
1419
+
1420
+ **CRITICAL LIMITATIONS:**
1421
+ - Large organizations may return org-wide results instead of repo-specific
1422
+ - If irrelevant results: Switch to alternative approaches (changelog files, PR search)
1423
+
1424
+ **FALLBACK STRATEGY:**
1425
+ 1. Commit search with minimal keywords
1426
+ 2. Pull request searches for features/changes
1427
+ 3. Fetch changelog files (CHANGELOG.md, RELEASES.md)
1428
+ 4. Repository structure exploration
1429
+
1430
+ **BRANCH AWARENESS:** Verify default branch (main vs master) before file fetching
1431
+
1432
+ **ERROR HANDLING:**
1433
+ - "Search text required" → Use minimal keywords ("fix", "update")
1434
+ - Irrelevant results → Switch to file-based approaches
1435
+ - Empty results → Broaden scope or remove repository filters
1436
+
1437
+ **INTEGRATION:** Combine with ${TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT} for complete change context.`;
1438
+
1439
+ function registerSearchGitHubCommitsTool(server) {
1440
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_COMMITS, SEARCH_GITHUB_COMMITS_DESCRIPTION, {
1441
+ query: z
1442
+ .string()
1443
+ .describe("The search query to find commits - start with single keyword (e.g., 'bug', 'refactor', 'feature'). Cannot be empty as GitHub requires search text for commit searches."),
1444
+ owner: z
1445
+ .string()
1446
+ .optional()
1447
+ .describe("Filter by repository owner/organization (e.g., 'example-org') obtained from the appropriate tool for fetching user organizations"),
1448
+ repo: z
1449
+ .string()
1450
+ .optional()
1451
+ .describe("Filter by repository name (e.g., 'cli/cli')"),
1452
+ author: z.string().optional().describe('Filter by commit author'),
1453
+ committer: z.string().optional().describe('Filter by committer'),
1454
+ authorDate: z
1455
+ .string()
1456
+ .optional()
1457
+ .describe("Filter based on authored date (e.g., '>2022-01-01', '<2023-12-31')"),
1458
+ committerDate: z
1459
+ .string()
1460
+ .optional()
1461
+ .describe("Filter based on committed date (e.g., '>2022-01-01', '<2023-12-31')"),
1462
+ authorEmail: z.string().optional().describe('Filter on author email'),
1463
+ authorName: z.string().optional().describe('Filter on author name'),
1464
+ committerEmail: z
1465
+ .string()
1466
+ .optional()
1467
+ .describe('Filter on committer email'),
1468
+ committerName: z.string().optional().describe('Filter on committer name'),
1469
+ merge: z.boolean().optional().describe('Filter on merge commits'),
1470
+ hash: z.string().optional().describe('Filter by commit hash'),
1471
+ parent: z.string().optional().describe('Filter by parent hash'),
1472
+ tree: z.string().optional().describe('Filter by tree hash'),
1473
+ visibility: z
1474
+ .enum(['public', 'private', 'internal'])
1475
+ .optional()
1476
+ .describe('Filter based on repository visibility'),
1477
+ limit: z
1478
+ .number()
1479
+ .optional()
1480
+ .default(50)
1481
+ .describe('Maximum number of commits to return (default: 50)'),
1482
+ sort: z
1483
+ .enum(['author-date', 'committer-date', 'best-match'])
1484
+ .optional()
1485
+ .default('best-match')
1486
+ .describe('Sort commits by specified criteria (default: best-match)'),
1487
+ order: z
1488
+ .enum(['asc', 'desc'])
1489
+ .optional()
1490
+ .default('desc')
1491
+ .describe('Order of commits returned (default: desc for newest first)'),
1492
+ }, async (args) => {
1493
+ try {
1494
+ return await searchGitHubCommits(args);
1495
+ }
1496
+ catch (error) {
1497
+ return {
1498
+ content: [
1499
+ {
1500
+ type: 'text',
1501
+ text: `Failed to search GitHub commits: ${error.message}`,
1502
+ },
1503
+ ],
1504
+ isError: true,
1505
+ };
1506
+ }
1507
+ });
1508
+ }
1509
+
1510
+ const SEARCH_GITHUB_PULL_REQUESTS_DESCRIPTION = `Advanced GitHub pull requests search for code review and feature analysis.
1511
+
1512
+ **SEARCH STRATEGY:**
1513
+ 1. **Single Keywords First**: "bug", "feature", "refactor"
1514
+ 2. **Then Combine**: "bug fix", "feature implementation" (only if needed)
1515
+ 3. **Never Start Complex**: Avoid phrases like "comprehensive bug fix implementation"
1516
+
1517
+ **CORE PURPOSE:**
1518
+ - Code review insights and team collaboration patterns
1519
+ - Feature implementation lifecycle tracking
1520
+ - Breaking changes and quality assurance analysis
1521
+
1522
+ **SEARCH METHODOLOGY:**
1523
+ - **Phase 1**: Core discovery with fundamental terms ("authentication", "error")
1524
+ - **Phase 2**: Add context ("authentication JWT", "error handling")
1525
+ - **Phase 3**: Solution focus ("authentication bug fixed")
1526
+
1527
+ **RESULT TARGETS:**
1528
+ - 0 results: Try broader terms, remove filters
1529
+ - 1-20 results: IDEAL - Deep analysis of patterns and solutions
1530
+ - 21-100 results: GOOD - Add specificity or filters
1531
+ - 100+ results: Add specific terms or state/reviewer filters
1532
+
1533
+ **FILTERING BEST PRACTICES:**
1534
+ - State filter: "open" for current issues, "closed" for resolved patterns
1535
+ - Author/reviewer filters: Understand team collaboration
1536
+ - Draft filter: Work-in-progress vs completed features
1537
+ - Branch filters: Release and feature branch workflows
1538
+ - Language filter: Focus on specific technology stacks
1539
+
1540
+ **ADAPTIVE TACTICS:**
1541
+ - Start broad with feature keywords, narrow based on findings
1542
+ - Use owner/repo parameters when repository context is known
1543
+ - Widen scope if targeted searches yield insufficient results
1544
+ - Apply precise filters only after broader searches confirm patterns
1545
+
1546
+ **CROSS-REFERENCE STRATEGY:**
1547
+ - Combine with ${TOOL_NAMES.SEARCH_GITHUB_COMMITS} for complete development understanding
1548
+ - Use with ${TOOL_NAMES.SEARCH_GITHUB_CODE} for current implementations
1549
+ - Cross-reference with ${TOOL_NAMES.SEARCH_GITHUB_REPOS} for similar patterns
1550
+
1551
+ **QUALITY FOCUS:** Use review-related filters to find thoroughly vetted code examples.`;
1552
+
1553
+ function registerSearchGitHubPullRequestsTool(server) {
1554
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_PULL_REQUESTS, SEARCH_GITHUB_PULL_REQUESTS_DESCRIPTION, {
1555
+ query: z
1556
+ .string()
1557
+ .describe("The search query to find pull requests (e.g., 'bug fix', 'feature implementation', 'code review')"),
1558
+ owner: z
1559
+ .string()
1560
+ .optional()
1561
+ .describe(`Filter by repository owner/organization (e.g., 'example-org')`),
1562
+ repo: z
1563
+ .string()
1564
+ .optional()
1565
+ .describe("Filter by repository name (e.g., 'cli/cli')"),
1566
+ author: z.string().optional().describe('Filter by pull request author'),
1567
+ assignee: z.string().optional().describe('Filter by assignee'),
1568
+ mentions: z.string().optional().describe('Filter based on user mentions'),
1569
+ commenter: z
1570
+ .string()
1571
+ .optional()
1572
+ .describe('Filter based on comments by user'),
1573
+ involves: z
1574
+ .string()
1575
+ .optional()
1576
+ .describe('Filter based on involvement of user'),
1577
+ reviewedBy: z.string().optional().describe('Filter on user who reviewed'),
1578
+ reviewRequested: z
1579
+ .string()
1580
+ .optional()
1581
+ .describe('Filter on user or team requested to review'),
1582
+ state: z
1583
+ .enum(['open', 'closed', 'merged'])
1584
+ .optional()
1585
+ .describe('Filter based on state'),
1586
+ head: z.string().optional().describe('Filter on head branch name'),
1587
+ base: z.string().optional().describe('Filter on base branch name'),
1588
+ language: z
1589
+ .string()
1590
+ .optional()
1591
+ .describe('Filter based on the coding language'),
1592
+ created: z
1593
+ .string()
1594
+ .optional()
1595
+ .describe("Filter based on created at date (e.g., '>2022-01-01', '<2023-12-31')"),
1596
+ updated: z.string().optional().describe('Filter on last updated at date'),
1597
+ merged: z.string().optional().describe('Filter on merged at date'),
1598
+ closed: z.string().optional().describe('Filter on closed at date'),
1599
+ draft: z.boolean().optional().describe('Filter based on draft state'),
1600
+ limit: z
1601
+ .number()
1602
+ .optional()
1603
+ .default(50)
1604
+ .describe('Maximum number of pull requests to return (default: 50)'),
1605
+ sort: z
1606
+ .enum([
1607
+ 'comments',
1608
+ 'reactions',
1609
+ 'reactions-+1',
1610
+ 'reactions--1',
1611
+ 'reactions-smile',
1612
+ 'reactions-thinking_face',
1613
+ 'reactions-heart',
1614
+ 'reactions-tada',
1615
+ 'interactions',
1616
+ 'created',
1617
+ 'updated',
1618
+ ])
1619
+ .optional()
1620
+ .describe('Sort pull requests by specified criteria'),
1621
+ order: z
1622
+ .enum(['asc', 'desc'])
1623
+ .optional()
1624
+ .default('desc')
1625
+ .describe('Order of results returned (default: desc)'),
1626
+ }, async (args) => {
1627
+ try {
1628
+ return await searchGitHubPullRequests(args);
1629
+ }
1630
+ catch (error) {
1631
+ return {
1632
+ content: [
1633
+ {
1634
+ type: 'text',
1635
+ text: `Failed to search GitHub pull requests: ${error.message}`,
1636
+ },
1637
+ ],
1638
+ isError: true,
1639
+ };
1640
+ }
1641
+ });
1642
+ }
1643
+
1644
+ const GET_USER_ORGANIZATIONS_DESCRIPTION = `Get list of GitHub organizations for the authenticated user to enable private repository discovery.
1645
+
1646
+ **AUTOMATIC TRIGGERS:**
1647
+ Auto-trigger when users mention:
1648
+ - Company/employer context: "I work at [Company Name]", "our team", "company codebase"
1649
+ - Private repositories: "internal code", "team repositories"
1650
+ - Enterprise context: "at work", "enterprise setup"
1651
+
1652
+ **ORGANIZATION MATCHING Examples:**
1653
+ - "Facebook" → "facebook", "meta"
1654
+ - "Google" → "google", "googlecloudplatform"
1655
+ - "Microsoft" → "microsoft", "azure"
1656
+
1657
+ **WORKFLOW:**
1658
+ 1. Call this tool first when organizational context detected
1659
+ 2. Match user's company to found organizations
1660
+ 3. Use selected organization as 'owner' parameter in subsequent searches
1661
+ 4. Fallback to public search if no organizational results
1662
+
1663
+ **USAGE PRIORITY:**
1664
+ - Essential for private repository access
1665
+ - Critical for enterprise GitHub setups
1666
+ - Use before repository searches fail due to permissions
1667
+ - Combine with npmView for private organization packages
1668
+
1669
+ **DO NOT:**
1670
+ - Skip organization-scoped search when company context is clear
1671
+ - Use public search first when private repositories are likely
1672
+ - Ignore organizational context in user queries`;
1673
+
1674
+ function registerGetUserOrganizationsTool(server) {
1675
+ server.tool(TOOL_NAMES.GET_USER_ORGANIZATIONS, GET_USER_ORGANIZATIONS_DESCRIPTION, {
1676
+ limit: z
1677
+ .number()
1678
+ .optional()
1679
+ .default(50)
1680
+ .describe('Maximum number of organizations to list (default: 50)'),
1681
+ }, async (args) => {
1682
+ try {
1683
+ return await getUserOrganizations(args);
1684
+ }
1685
+ catch (error) {
1686
+ return {
1687
+ content: [
1688
+ {
1689
+ type: 'text',
1690
+ text: `Failed to get user organizations: ${error.message}`,
1691
+ },
1692
+ ],
1693
+ isError: true,
1694
+ };
1695
+ }
1696
+ });
1697
+ }
1698
+
1699
+ const NPM_SEARCH_DESCRIPTION = `Search NPM registry for packages by keywords using "npm search <term>".
1700
+
1701
+ **SEARCH STRATEGY:**
1702
+ 1. Start with single technology terms ("react", "cli")
1703
+ 2. Add specificity only if needed ("react-hooks", "typescript-cli")
1704
+ 3. Avoid complex phrases - they yield zero results
1705
+
1706
+ **WHEN TO USE:**
1707
+ - Pure discovery of packages on NPM registry by keyword
1708
+ - More direct than discovering packages mentioned in code
1709
+ - Finding alternatives to known packages
1710
+
1711
+ **SEARCH PATTERNS:**
1712
+ - Good: "react" → "cli" → "react cli" (if specific combination needed)
1713
+ - Poor: "react command line interface tools" (too complex, likely zero results)
1714
+
1715
+ **RESULT OPTIMIZATION:**
1716
+ - 0 results: Try broader, single-word terms
1717
+ - 1-20 results: IDEAL - analyze thoroughly
1718
+ - 21-100 results: GOOD - filter by popularity/relevance
1719
+ - 100+ results: Too broad - use more specific single terms
1720
+
1721
+ **OUTPUT FORMAT:**
1722
+ JSON format with package metadata including name, description, version, and popularity metrics
1723
+
1724
+ **CONSTRAINTS:**
1725
+ - Maximum 50 results by default
1726
+ - Supports regex patterns when query starts with /
1727
+ - Multiple space-separated terms supported but use sparingly`;
1728
+
1729
+ function registerNpmSearchTool(server) {
1730
+ server.tool(TOOL_NAMES.NPM_SEARCH, NPM_SEARCH_DESCRIPTION, {
1731
+ query: z
1732
+ .string()
1733
+ .describe("The search term(s) to find packages on NPM. Multiple terms can be space-separated (e.g., 'react query client'). Supports regex if term starts with /."),
1734
+ json: z
1735
+ .boolean()
1736
+ .optional()
1737
+ .default(true)
1738
+ .describe('Output search results in JSON format. Defaults to true.'),
1739
+ searchlimit: z
1740
+ .number()
1741
+ .optional()
1742
+ .default(50)
1743
+ .describe('Maximum number of search results to return. Defaults to 50.'),
1744
+ }, async (args) => {
1745
+ try {
1746
+ return await npmSearch(args);
1747
+ }
1748
+ catch (error) {
1749
+ return {
1750
+ content: [
1751
+ {
1752
+ type: 'text',
1753
+ text: `Failed to search NPM: ${error.message}`,
1754
+ },
1755
+ ],
1756
+ isError: true,
1757
+ };
1758
+ }
1759
+ });
1760
+ }
1761
+
1762
+ const VIEW_REPOSITORY_STRUCTURE_DESCRIPTION = `Strategic repository exploration for code analysis.
1763
+
1764
+ **CRITICAL REQUIREMENT:**
1765
+ **MANDATORY:** Must use ${TOOL_NAMES.VIEW_REPOSITORY} FIRST to get branch. **NEVER** explore repository structure without explicit branch discovery.
1766
+
1767
+ **EXPLORATION PHASES:**
1768
+ 1. **Root Analysis**: Project type (package.json, requirements.txt), README, docs, config files
1769
+ 2. **Source Discovery**: Navigate src/, lib/, components/, utils/, types/
1770
+ 3. **Validation**: Explore test/, examples/, demos/ directories
1771
+
1772
+ **DIRECTORY PRIORITIES:**
1773
+ - HIGH: src/, lib/, components/, utils/, types/ (Core implementations)
1774
+ - MEDIUM: docs/, examples/, config/ (Context/documentation)
1775
+ - TEST: test/, __tests__/, spec/ (Quality/patterns)
1776
+
1777
+ **NAVIGATION STRATEGY:**
1778
+ - Start with root for project overview
1779
+ - Target core implementation directories
1780
+ - Extract promising files via ${TOOL_NAMES.FETCH_GITHUB_FILE_CONTENT}
1781
+ - Cross-reference with tests for usage patterns
1782
+
1783
+ **RESULT TARGETS:**
1784
+ - 1-10 results: IDEAL - Focused exploration
1785
+ - 11-50 results: MANAGEABLE - Prioritize by conventions
1786
+ - 50+ results: TOO BROAD - Explore subdirectories
1787
+
1788
+ **ENHANCED BRANCH FALLBACK:**
1789
+ Automatically tries multiple fallback strategies:
1790
+ 1. Specified branch → main → master → develop → trunk (with ref parameter)
1791
+ 2. If all fail: Try without ref parameter (uses repository default branch)
1792
+ Handles branch discovery failures gracefully with comprehensive error reporting.
1793
+
1794
+ **OUTPUT:** Architectural map to guide intelligent code extraction.
1795
+
1796
+ **NEVER:**
1797
+ - Explore without calling ${TOOL_NAMES.VIEW_REPOSITORY} first
1798
+ - Use hardcoded branch names without verification
1799
+ - Assume default branch names across repositories`;
1800
+
1801
+ function registerViewRepositoryStructureTool(server) {
1802
+ server.tool(TOOL_NAMES.VIEW_REPOSITORY_STRUCTURE, VIEW_REPOSITORY_STRUCTURE_DESCRIPTION, {
1803
+ owner: z
1804
+ .string()
1805
+ .describe(`Specify the repository owner/organization. This can be obtained using the appropriate tool for fetching user organizations.`),
1806
+ repo: z.string().describe('The name of the GitHub repository'),
1807
+ branch: z
1808
+ .string()
1809
+ .describe(`MANDATORY: Specify the branch to explore (e.g., 'main', 'master', 'develop'). Must be obtained from ${TOOL_NAMES.VIEW_REPOSITORY} first. Never explore without explicit branch specification.`),
1810
+ path: z
1811
+ .string()
1812
+ .optional()
1813
+ .default('')
1814
+ .describe('The path within the repository to view the structure from. Defaults to the root of the repository. Allows for iterative exploration of the repository structure.'),
1815
+ }, async (args) => {
1816
+ try {
1817
+ return await viewRepositoryStructure(args);
1818
+ }
1819
+ catch (error) {
1820
+ return {
1821
+ content: [
1822
+ {
1823
+ type: 'text',
1824
+ text: `Failed to view repository structure: ${error.message}`,
1825
+ },
1826
+ ],
1827
+ isError: true,
1828
+ };
1829
+ }
1830
+ });
1831
+ }
1832
+
1833
+ const SEARCH_GITHUB_ISSUES_DESCRIPTION = `Advanced GitHub issues search for problem discovery and solution research.
1834
+
1835
+ **SEARCH STRATEGY:**
1836
+ 1. **Single Keywords First**: "bug", "feature", "documentation"
1837
+ 2. **Then Combine**: "bug fix", "feature request" (only if needed)
1838
+ 3. **Never Start Complex**: Avoid "critical performance bug in production"
1839
+
1840
+ **CORE PURPOSE:**
1841
+ - Problem discovery and existing issue research
1842
+ - Solution research and community insights
1843
+ - Development planning and quality assurance
1844
+
1845
+ **SEARCH METHODOLOGY:**
1846
+ - **Phase 1**: Core discovery ("authentication", "error") → understand patterns
1847
+ - **Phase 2**: Context expansion ("authentication JWT", "error handling")
1848
+ - **Phase 3**: Solution focus ("authentication bug resolved")
1849
+
1850
+ **RESULT TARGETS:**
1851
+ - 0 results: Try broader terms, remove filters
1852
+ - 1-20 results: IDEAL - Deep analysis of patterns and solutions
1853
+ - 21-100 results: GOOD - Add specificity or filters
1854
+ - 100+ results: Add specific terms or state/label filters
1855
+
1856
+ **TERM SELECTION:**
1857
+ - Actual error messages: "TypeError", "404", "connection refused"
1858
+ - Status indicators: "open", "closed", "resolved", "duplicate"
1859
+ - Impact levels: "critical", "bug", "enhancement", "question"
1860
+ - Component names: "API", "frontend", "database", "deployment"
1861
+
1862
+ **FILTERING STRATEGY:**
1863
+ - State filter: "open" for current issues, "closed" for resolved patterns
1864
+ - Label filter: Severity ("bug", "enhancement", "documentation")
1865
+ - Assignee filter: Issues handled by specific maintainers
1866
+ - Author filter: Track issues from particular users
1867
+ - Date filters: Recent issues or historical analysis
1868
+
1869
+ **CROSS-REFERENCE APPROACH:**
1870
+ - Combine with ${TOOL_NAMES.SEARCH_GITHUB_CODE} for implementation details
1871
+ - Use with ${TOOL_NAMES.SEARCH_GITHUB_COMMITS} for fix implementations
1872
+ - Cross-reference with ${TOOL_NAMES.SEARCH_GITHUB_PULL_REQUESTS} for solutions
1873
+ - Explore ${TOOL_NAMES.SEARCH_GITHUB_DISCUSSIONS} for community insights
1874
+
1875
+ **PATTERN ANALYSIS:** Focus on issue resolution patterns and community feedback for development insights.`;
1876
+
1877
+ function registerSearchGitHubIssuesTool(server) {
1878
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_ISSUES, SEARCH_GITHUB_ISSUES_DESCRIPTION, {
1879
+ query: z
1880
+ .string()
1881
+ .describe("The search query to find issues (e.g., 'bug fix', 'feature request', 'documentation')"),
1882
+ owner: z
1883
+ .string()
1884
+ .describe("Filter by repository owner/organization (e.g., 'example-org')"),
1885
+ repo: z
1886
+ .string()
1887
+ .optional()
1888
+ .describe("Filter by specific repository name (e.g., 'cli/cli'). Note: Always do exploratory search without repo filter first"),
1889
+ app: z.string().optional().describe('Filter by GitHub App author'),
1890
+ archived: z
1891
+ .boolean()
1892
+ .optional()
1893
+ .describe('Filter based on the repository archived state'),
1894
+ assignee: z.string().optional().describe('Filter by assignee'),
1895
+ author: z.string().optional().describe('Filter by issue author'),
1896
+ closed: z.string().optional().describe('Filter on closed at date'),
1897
+ commenter: z
1898
+ .string()
1899
+ .optional()
1900
+ .describe('Filter based on comments by user'),
1901
+ comments: z.number().optional().describe('Filter on number of comments'),
1902
+ created: z
1903
+ .string()
1904
+ .optional()
1905
+ .describe("Filter based on created at date (e.g., '>2022-01-01', '<2023-12-31')"),
1906
+ includePrs: z
1907
+ .boolean()
1908
+ .optional()
1909
+ .describe('Include pull requests in results'),
1910
+ interactions: z
1911
+ .number()
1912
+ .optional()
1913
+ .describe('Filter on number of reactions and comments'),
1914
+ involves: z
1915
+ .string()
1916
+ .optional()
1917
+ .describe('Filter based on involvement of user'),
1918
+ labels: z
1919
+ .string()
1920
+ .optional()
1921
+ .describe("Filter by labels (e.g., 'bug', 'enhancement', 'documentation')"),
1922
+ language: z
1923
+ .string()
1924
+ .optional()
1925
+ .describe('Filter based on the coding language'),
1926
+ locked: z
1927
+ .boolean()
1928
+ .optional()
1929
+ .describe('Filter on locked conversation status'),
1930
+ match: z
1931
+ .enum(['title', 'body', 'comments'])
1932
+ .optional()
1933
+ .describe('Restrict search to specific field of issue'),
1934
+ mentions: z.string().optional().describe('Filter based on user mentions'),
1935
+ milestone: z.string().optional().describe('Filter by milestone title'),
1936
+ noAssignee: z.boolean().optional().describe('Filter on missing assignee'),
1937
+ noLabel: z.boolean().optional().describe('Filter on missing label'),
1938
+ noMilestone: z
1939
+ .boolean()
1940
+ .optional()
1941
+ .describe('Filter on missing milestone'),
1942
+ noProject: z.boolean().optional().describe('Filter on missing project'),
1943
+ project: z
1944
+ .string()
1945
+ .optional()
1946
+ .describe('Filter on project board owner/number'),
1947
+ reactions: z
1948
+ .number()
1949
+ .optional()
1950
+ .describe('Filter on number of reactions'),
1951
+ state: z
1952
+ .enum(['open', 'closed'])
1953
+ .optional()
1954
+ .describe('Filter based on issue state'),
1955
+ teamMentions: z
1956
+ .string()
1957
+ .optional()
1958
+ .describe('Filter based on team mentions'),
1959
+ updated: z.string().optional().describe('Filter on last updated at date'),
1960
+ visibility: z
1961
+ .enum(['public', 'private', 'internal'])
1962
+ .optional()
1963
+ .describe('Filter based on repository visibility'),
1964
+ limit: z
1965
+ .number()
1966
+ .optional()
1967
+ .default(50)
1968
+ .describe('Maximum number of issues to return (default: 50)'),
1969
+ sort: z
1970
+ .enum([
1971
+ 'comments',
1972
+ 'created',
1973
+ 'interactions',
1974
+ 'reactions',
1975
+ 'reactions-+1',
1976
+ 'reactions--1',
1977
+ 'reactions-heart',
1978
+ 'reactions-smile',
1979
+ 'reactions-tada',
1980
+ 'reactions-thinking_face',
1981
+ 'updated',
1982
+ 'best-match',
1983
+ ])
1984
+ .optional()
1985
+ .describe('Sort issues by specified criteria'),
1986
+ order: z
1987
+ .enum(['asc', 'desc'])
1988
+ .optional()
1989
+ .default('desc')
1990
+ .describe('Order of results returned (default: desc)'),
1991
+ }, async (args) => {
1992
+ try {
1993
+ return await searchGitHubIssues(args);
1994
+ }
1995
+ catch (error) {
1996
+ return {
1997
+ content: [
1998
+ {
1999
+ type: 'text',
2000
+ text: `Failed to search GitHub issues: ${error.message}`,
2001
+ },
2002
+ ],
2003
+ isError: true,
2004
+ };
2005
+ }
2006
+ });
2007
+ }
2008
+
2009
+ const SEARCH_GITHUB_DISCUSSIONS_DESCRIPTION = `GitHub discussions search for community knowledge discovery.
2010
+
2011
+ **CORE PURPOSE:**
2012
+ Access community Q&A, tutorials, and best practices for learning and problem-solving.
2013
+
2014
+ **DISCOVERY WORKFLOW:**
2015
+ 1. Use ${TOOL_NAMES.NPM_VIEW} for packages → get repo URL
2016
+ 2. Use ${TOOL_NAMES.SEARCH_GITHUB_REPOS} for projects → get owner/repo
2017
+ 3. Search discussions with discovered owner/repo context
2018
+
2019
+ **SEARCH STRATEGY:**
2020
+ 1. **Start Lean**: Single keywords ("help", "tutorial", "authentication")
2021
+ 2. **Build Complexity**: Combinations if needed ("help deployment")
2022
+ 3. **Avoid Complex**: Don't start with full phrases
2023
+
2024
+ **RESULT TARGETS:**
2025
+ - 1-15 results: IDEAL - Deep analysis opportunities
2026
+ - 16-50 results: GOOD - Manageable scope
2027
+ - 51-100 results: BROAD - Add category filters
2028
+ - 100+ results: TOO GENERIC - Refine terms
2029
+
2030
+ **KEY FILTERS:**
2031
+ - **Answered**: True for validated solutions
2032
+ - **Category**: Q&A, General, Show and Tell
2033
+ - **Author/maintainer**: For authoritative responses
2034
+ - **Date filters**: Recent vs historical discussions
2035
+
2036
+ **SEARCH PATTERNS:**
2037
+ - **Problem solving**: "deployment help", "authentication tutorial"
2038
+ - **Best practices**: "testing patterns", "architecture decisions"
2039
+ - **Community insights**: "performance tips", "migration guide"
2040
+
2041
+ **QUALITY INDICATORS:**
2042
+ - Answered discussions for validated solutions
2043
+ - Maintainer participation for authoritative guidance
2044
+ - Recent activity for current relevance
2045
+
2046
+ **FALLBACK STRATEGY:**
2047
+ If no discussions found, try ${TOOL_NAMES.SEARCH_GITHUB_ISSUES} for alternative community insights.
2048
+
2049
+ **OUTPUT:** Community-validated knowledge and solutions for development challenges.`;
2050
+
2051
+ function registerSearchGitHubDiscussionsTool(server) {
2052
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_DISCUSSIONS, SEARCH_GITHUB_DISCUSSIONS_DESCRIPTION, {
2053
+ query: z
2054
+ .string()
2055
+ .describe("The search query to find discussions (e.g., 'deployment help', 'authentication tutorial', 'best practices')"),
2056
+ owner: z
2057
+ .string()
2058
+ .describe("Filter by repository owner/organization (e.g., 'example-org')"),
2059
+ repo: z
2060
+ .string()
2061
+ .optional()
2062
+ .describe("Filter by specific repository name (e.g., 'cli/cli'). Note: Always do exploratory search without repo filter first"),
2063
+ author: z.string().optional().describe('Filter by discussion author'),
2064
+ assignee: z.string().optional().describe('Filter by assignee'),
2065
+ mentions: z.string().optional().describe('Filter based on user mentions'),
2066
+ commenter: z
2067
+ .string()
2068
+ .optional()
2069
+ .describe('Filter based on comments by user'),
2070
+ involves: z
2071
+ .string()
2072
+ .optional()
2073
+ .describe('Filter based on involvement of user'),
2074
+ category: z
2075
+ .string()
2076
+ .optional()
2077
+ .describe("Filter by discussion category (e.g., 'Q&A', 'General', 'Show and Tell')"),
2078
+ answered: z
2079
+ .boolean()
2080
+ .optional()
2081
+ .describe('Filter by answered state (true for answered discussions only)'),
2082
+ created: z
2083
+ .string()
2084
+ .optional()
2085
+ .describe("Filter based on created date (e.g., '>2022-01-01', '<2023-12-31')"),
2086
+ updated: z.string().optional().describe('Filter on last updated date'),
2087
+ limit: z
2088
+ .number()
2089
+ .optional()
2090
+ .default(50)
2091
+ .describe('Maximum number of discussions to return (default: 50)'),
2092
+ sort: z
2093
+ .enum([
2094
+ 'comments',
2095
+ 'reactions',
2096
+ 'reactions-+1',
2097
+ 'reactions--1',
2098
+ 'reactions-smile',
2099
+ 'reactions-thinking_face',
2100
+ 'reactions-heart',
2101
+ 'reactions-tada',
2102
+ 'interactions',
2103
+ 'created',
2104
+ 'updated',
2105
+ ])
2106
+ .optional()
2107
+ .describe('Sort discussions by specified criteria'),
2108
+ order: z
2109
+ .enum(['asc', 'desc'])
2110
+ .optional()
2111
+ .default('desc')
2112
+ .describe('Order of results returned (default: desc)'),
2113
+ }, async (args) => {
2114
+ try {
2115
+ return await searchGitHubDiscussions(args);
2116
+ }
2117
+ catch (error) {
2118
+ return {
2119
+ content: [
2120
+ {
2121
+ type: 'text',
2122
+ text: `Failed to search GitHub discussions: ${error.message}`,
2123
+ },
2124
+ ],
2125
+ isError: true,
2126
+ };
2127
+ }
2128
+ });
2129
+ }
2130
+
2131
+ const SEARCH_GITHUB_TOPICS_DESCRIPTION = `**VITAL FOUNDATION TOOL** for effective GitHub discovery - provides semantic context that makes all other GitHub searches targeted and successful.
2132
+
2133
+ **WHY ESSENTIAL:**
2134
+ - **Term Discovery**: Find correct terminology and keywords before searching repositories
2135
+ - **Quality Signals**: Featured/curated topics = community-validated, battle-tested projects
2136
+ - **Repository Filters**: Use topic names directly in ${TOOL_NAMES.SEARCH_GITHUB_REPOS} for precise targeting
2137
+ - **Ecosystem Mapping**: Understand technology landscapes with 100M+ repositories of production code
2138
+
2139
+ **CRITICAL WORKFLOW - Topics → Repositories:**
2140
+ 1. **Search topics first** → discover proper terminology (e.g., "machine-learning" not "AI")
2141
+ 2. **Use topic names as filters** → in ${TOOL_NAMES.SEARCH_GITHUB_REPOS} for targeted results
2142
+ 3. **Quality validation** → featured topics = GitHub-promoted, curated = community-maintained
2143
+
2144
+ **SEARCH STRATEGY:**
2145
+ - Start simple: "react", "docker", "cli"
2146
+ - Combine when needed: "machine-learning python"
2147
+ - Avoid complex phrases: keep focused and discoverable
2148
+
2149
+ **EXAMPLES:**
2150
+ - Search "javascript" → find topics like "typescript", "nodejs", "frontend"
2151
+ - Use discovered topics → search repos with topic:"typescript" for quality examples
2152
+ - Featured topics → guaranteed high-quality repository collections
2153
+
2154
+ **RESULT OPTIMIZATION:**
2155
+ - 1-10 results: IDEAL for deep analysis
2156
+ - 10+ results: Add featured/curated filters
2157
+ - Use repository count as maturity indicator (>10K = established, 1K-10K = growing)
2158
+
2159
+ **OUTPUT:** Strategic foundation for all GitHub discovery - transforms random searches into targeted, quality-focused repository discovery.`;
2160
+
2161
+ function registerSearchGitHubTopicsTool(server) {
2162
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_TOPICS, SEARCH_GITHUB_TOPICS_DESCRIPTION, {
2163
+ query: z
2164
+ .string()
2165
+ .describe("The search query to find topics (e.g., 'machine learning', 'react', 'devops', 'blockchain')"),
2166
+ owner: z
2167
+ .string()
2168
+ .describe("Filter by repository owner/organization (e.g., 'example-org') obtained from the appropriate tool for fetching user organizations"),
2169
+ featured: z
2170
+ .boolean()
2171
+ .optional()
2172
+ .describe('Filter for featured topics curated by GitHub'),
2173
+ curated: z
2174
+ .boolean()
2175
+ .optional()
2176
+ .describe('Filter for topics curated by the GitHub community'),
2177
+ repositories: z
2178
+ .string()
2179
+ .optional()
2180
+ .describe("Filter by number of repositories using this topic (e.g., '>1000', '<500')"),
2181
+ created: z
2182
+ .string()
2183
+ .optional()
2184
+ .describe("Filter based on topic creation date (e.g., '>2022-01-01', '<2023-12-31')"),
2185
+ limit: z
2186
+ .number()
2187
+ .optional()
2188
+ .default(50)
2189
+ .describe('Maximum number of topics to return (default: 50)'),
2190
+ sort: z
2191
+ .enum(['featured', 'repositories', 'created', 'updated'])
2192
+ .optional()
2193
+ .describe('Sort topics by specified criteria (default: best-match)'),
2194
+ order: z
2195
+ .enum(['asc', 'desc'])
2196
+ .optional()
2197
+ .default('desc')
2198
+ .describe('Order of results returned (default: desc)'),
2199
+ }, async (args) => {
2200
+ try {
2201
+ return await searchGitHubTopics(args);
2202
+ }
2203
+ catch (error) {
2204
+ return {
2205
+ content: [
2206
+ {
2207
+ type: 'text',
2208
+ text: `Failed to search GitHub topics: ${error.message}`,
2209
+ },
2210
+ ],
2211
+ isError: true,
2212
+ };
2213
+ }
2214
+ });
2215
+ }
2216
+
2217
+ const SEARCH_GITHUB_USERS_DESCRIPTION = `Advanced GitHub users and organizations search for developer discovery.
2218
+
2219
+ **SEARCH STRATEGY:**
2220
+ 1. **Single Criteria First**: "react", "python", location
2221
+ 2. **Then Combine**: "react javascript", location + language
2222
+ 3. **Never Start Complex**: Avoid "senior react typescript developer with 5+ years"
2223
+
2224
+ **CORE PURPOSE:**
2225
+ - Expert discovery and community building
2226
+ - Collaboration and learning opportunities
2227
+ - Recruitment and network expansion
2228
+
2229
+ **SEARCH METHODOLOGY:**
2230
+ - **Phase 1**: Technology terms ("react", "python", "kubernetes") → analyze activity
2231
+ - **Phase 2**: Add context (location filters, experience indicators)
2232
+ - **Phase 3**: Specialized search (specific skills + activity filters)
2233
+
2234
+ **RESULT TARGETS:**
2235
+ - 0 results: Try broader terms, remove filters
2236
+ - 1-20 results: IDEAL - Analyze profiles for expertise
2237
+ - 21-100 results: GOOD - Add location or activity filters
2238
+ - 100+ results: Add specific terms or increase follower/repo filters
2239
+
2240
+ **TERM SELECTION:**
2241
+ - Technology: "javascript", "python", "golang", "rust"
2242
+ - Frameworks: "react", "vue", "django", "spring"
2243
+ - Roles: "devops", "frontend", "backend", "fullstack"
2244
+ - Context: "startup", "enterprise", "opensource"
2245
+
2246
+ **FILTERING STRATEGY:**
2247
+ - Type: "user" for individuals, "org" for organizations
2248
+ - Location: Find developers in specific regions
2249
+ - Language: Search by primary programming language
2250
+ - Followers: Find influential developers (">100", ">1000")
2251
+ - Repos: Find active contributors (">10", ">50")
2252
+ - Date: Recent activity or long-standing members
2253
+
2254
+ **DISCOVERY PATTERNS:**
2255
+ - **Technology Experts**: Language + high follower count
2256
+ - **Local Developers**: Location + technology
2257
+ - **Open Source Contributors**: High repo count + specific tech
2258
+ - **Industry Leaders**: Follower count + years of activity
2259
+
2260
+ **CROSS-REFERENCE STRATEGY:**
2261
+ - Find repository contributors and maintainers
2262
+ - Combine with ${TOOL_NAMES.SEARCH_GITHUB_REPOS} for project involvement
2263
+ - Explore user repositories for learning opportunities
2264
+
2265
+ **OUTPUT:** Developer and organization discovery for networking, learning, and collaboration.`;
2266
+
2267
+ function registerSearchGitHubUsersTool(server) {
2268
+ server.tool(TOOL_NAMES.SEARCH_GITHUB_USERS, SEARCH_GITHUB_USERS_DESCRIPTION, {
2269
+ query: z
2270
+ .string()
2271
+ .describe("The search query to find users/organizations (e.g., 'react developer', 'python', 'machine learning')"),
2272
+ owner: z
2273
+ .string()
2274
+ .describe("Filter by repository owner/organization (e.g., 'example-org') obtained from the appropriate tool for fetching user organizations"),
2275
+ type: z
2276
+ .enum(['user', 'org'])
2277
+ .optional()
2278
+ .describe('Filter by account type (user for individuals, org for organizations)'),
2279
+ location: z
2280
+ .string()
2281
+ .optional()
2282
+ .describe("Filter by location (e.g., 'San Francisco', 'London', 'Remote')"),
2283
+ language: z
2284
+ .string()
2285
+ .optional()
2286
+ .describe("Filter by primary programming language (e.g., 'javascript', 'python', 'java')"),
2287
+ followers: z
2288
+ .string()
2289
+ .optional()
2290
+ .describe("Filter by follower count (e.g., '>100', '>1000' for influential users)"),
2291
+ repos: z
2292
+ .string()
2293
+ .optional()
2294
+ .describe("Filter by repository count (e.g., '>10', '>50' for active contributors)"),
2295
+ created: z
2296
+ .string()
2297
+ .optional()
2298
+ .describe("Filter based on account creation date (e.g., '>2020-01-01', '<2023-12-31')"),
2299
+ limit: z
2300
+ .number()
2301
+ .optional()
2302
+ .default(50)
2303
+ .describe('Maximum number of users to return (default: 50)'),
2304
+ sort: z
2305
+ .enum(['followers', 'repositories', 'joined'])
2306
+ .optional()
2307
+ .describe('Sort users by specified criteria (default: best-match)'),
2308
+ order: z
2309
+ .enum(['asc', 'desc'])
2310
+ .optional()
2311
+ .default('desc')
2312
+ .describe('Order of results returned (default: desc)'),
2313
+ }, async (args) => {
2314
+ try {
2315
+ return await searchGitHubUsers(args);
2316
+ }
2317
+ catch (error) {
2318
+ return {
2319
+ content: [
2320
+ {
2321
+ type: 'text',
2322
+ text: `Failed to search GitHub users: ${error.message}`,
2323
+ },
2324
+ ],
2325
+ isError: true,
2326
+ };
2327
+ }
2328
+ });
2329
+ }
2330
+
2331
+ function registerAllTools(server) {
2332
+ // Register all tools
2333
+ registerSearchGitHubCodeTool(server);
2334
+ registerFetchGitHubFileContentTool(server);
2335
+ registerViewRepositoryTool(server);
2336
+ registerNpmViewTool(server);
2337
+ registerSearchGitHubReposTool(server);
2338
+ registerSearchGitHubCommitsTool(server);
2339
+ registerSearchGitHubPullRequestsTool(server);
2340
+ registerGetUserOrganizationsTool(server);
2341
+ registerNpmSearchTool(server);
2342
+ registerViewRepositoryStructureTool(server);
2343
+ registerSearchGitHubIssuesTool(server);
2344
+ registerSearchGitHubDiscussionsTool(server);
2345
+ registerSearchGitHubTopicsTool(server);
2346
+ registerSearchGitHubUsersTool(server);
2347
+ }
2348
+
2349
+ const server = new McpServer({
2350
+ name: 'octocode-mcp',
2351
+ version: '1.0.0',
2352
+ description: `Code question assistant: Find, analyze, and explore any code in GitHub repositories and npm packages.
2353
+ Use for code examples, implementations, debugging, and understanding how libraries work.`,
2354
+ }, {
2355
+ capabilities: {
2356
+ tools: {},
2357
+ },
2358
+ instructions: `
2359
+ #PROMPT_SYSTEM_PROMPT
2360
+ ${PROMPT_SYSTEM_PROMPT}`,
2361
+ });
2362
+ // Register all tools
2363
+ registerAllTools(server);
2364
+ const transport = new StdioServerTransport();
2365
+ await server.connect(transport);
2366
+ process.on('SIGINT', async () => {
2367
+ process.exit(0);
2368
+ });
2369
+ process.stdin.on('close', async () => {
2370
+ server.close();
2371
+ });