octocode-mcp 2.3.11 → 2.3.12
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 +223 -180
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -944,23 +944,10 @@ function createToolSuggestion(currentTool, suggestedTools) {
|
|
|
944
944
|
}
|
|
945
945
|
|
|
946
946
|
const API_STATUS_CHECK_TOOL_NAME = 'apiStatusCheck';
|
|
947
|
-
const DESCRIPTION$9 = `
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
-
|
|
951
|
-
- Troubleshoot access issues before extensive searches
|
|
952
|
-
- Verify API connectivity and permissions
|
|
953
|
-
|
|
954
|
-
ORGANIZATION DISCOVERY:
|
|
955
|
-
- List available GitHub organizations for scoped searches
|
|
956
|
-
- Identify accessible private repositories
|
|
957
|
-
- Guide repository search strategy based on permissions
|
|
958
|
-
|
|
959
|
-
WORKFLOW OPTIMIZATION:
|
|
960
|
-
- Run first when dealing with private/organizational repositories
|
|
961
|
-
- Prevents access errors in subsequent tool usage
|
|
962
|
-
- Informs search scope and strategy decisions
|
|
963
|
-
- Essential for comprehensive organizational research`;
|
|
947
|
+
const DESCRIPTION$9 = `initial tool to verify user connections
|
|
948
|
+
|
|
949
|
+
- Github: check gh login status and list available organizations.
|
|
950
|
+
- Npm: check npm login status and list npm registry.`;
|
|
964
951
|
// Helper function to parse execution results with proper typing
|
|
965
952
|
function parseExecResult(result) {
|
|
966
953
|
if (!result.isError && result.content?.[0]?.text) {
|
|
@@ -1119,69 +1106,64 @@ const DESCRIPTION$8 = `Search code across GitHub repositories using GitHub's cod
|
|
|
1119
1106
|
|
|
1120
1107
|
SEARCH STRATEGY FOR BEST RESULTS:
|
|
1121
1108
|
|
|
1122
|
-
|
|
1123
|
-
-
|
|
1124
|
-
-
|
|
1125
|
-
- RESTRICTIVE: 3+ terms - very specific but may miss relevant results
|
|
1126
|
-
- Example: "useState" (best coverage) vs "react hook useState" (specific but restrictive)
|
|
1127
|
-
|
|
1128
|
-
MULTI-SEARCH STRATEGY:
|
|
1129
|
-
- Use SEPARATE searches for different aspects instead of complex single queries
|
|
1130
|
-
- Example: Search "authentication" separately, then "login" separately
|
|
1131
|
-
- Separate searches provide broader coverage than restrictive AND logic
|
|
1109
|
+
EXACT vs TERMS (Choose ONE):
|
|
1110
|
+
- exactQuery: Use for exact phrase matching
|
|
1111
|
+
- queryTerms: Use minimal words for broader coverage
|
|
1132
1112
|
|
|
1133
|
-
|
|
1134
|
-
-
|
|
1135
|
-
-
|
|
1136
|
-
-
|
|
1137
|
-
- Mixed queries: "exact phrase" additional_term (phrase + term)
|
|
1113
|
+
TERM OPTIMIZATION:
|
|
1114
|
+
- BEST: Single terms for maximum coverage
|
|
1115
|
+
- GOOD: 2-3 minimal terms
|
|
1116
|
+
- AVOID: Long phrases in queryTerms
|
|
1138
1117
|
|
|
1139
|
-
|
|
1140
|
-
-
|
|
1141
|
-
-
|
|
1142
|
-
- Mixed queries: "exact phrase" single_term another_term
|
|
1118
|
+
MULTI-SEARCH STRATEGY:
|
|
1119
|
+
- Use separate searches for different aspects
|
|
1120
|
+
- Separate searches provide broader coverage than complex queries
|
|
1143
1121
|
|
|
1144
1122
|
Filter Usage:
|
|
1145
|
-
-
|
|
1146
|
-
- Combine filters
|
|
1147
|
-
- Never use filters on exploratory searches - use to refine
|
|
1123
|
+
- Use filters to narrow scope: language, owner, repo, filename
|
|
1124
|
+
- Combine filters strategically: language + owner for organization-wide searches
|
|
1125
|
+
- Never use filters on exploratory searches - use to refine results`;
|
|
1148
1126
|
function registerGitHubSearchCodeTool(server) {
|
|
1149
1127
|
server.registerTool(GITHUB_SEARCH_CODE_TOOL_NAME, {
|
|
1150
1128
|
description: DESCRIPTION$8,
|
|
1151
1129
|
inputSchema: {
|
|
1152
|
-
|
|
1130
|
+
exactQuery: z
|
|
1153
1131
|
.string()
|
|
1154
|
-
.
|
|
1155
|
-
.describe('
|
|
1132
|
+
.optional()
|
|
1133
|
+
.describe('Exact phrase/word to search for'),
|
|
1134
|
+
queryTerms: z
|
|
1135
|
+
.array(z.string())
|
|
1136
|
+
.optional()
|
|
1137
|
+
.describe('Array of search terms (AND logic in files). Use minimal words for broader coverage'),
|
|
1156
1138
|
language: z
|
|
1157
1139
|
.string()
|
|
1158
1140
|
.optional()
|
|
1159
|
-
.describe('Programming language filter.
|
|
1141
|
+
.describe('Programming language filter. Narrows search to specific language files.'),
|
|
1160
1142
|
owner: z
|
|
1161
1143
|
.union([z.string(), z.array(z.string())])
|
|
1162
1144
|
.optional()
|
|
1163
|
-
.describe('Repository owner/organization name(s)
|
|
1145
|
+
.describe('Repository owner/organization name(s). Organization-wide search.'),
|
|
1164
1146
|
repo: z
|
|
1165
1147
|
.union([z.string(), z.array(z.string())])
|
|
1166
1148
|
.optional()
|
|
1167
|
-
.describe('
|
|
1149
|
+
.describe('Repository filter. Use with owner or full format.'),
|
|
1168
1150
|
filename: z
|
|
1169
1151
|
.string()
|
|
1170
1152
|
.optional()
|
|
1171
|
-
.describe('Target specific filename or pattern.
|
|
1153
|
+
.describe('Target specific filename or pattern.'),
|
|
1172
1154
|
extension: z
|
|
1173
1155
|
.string()
|
|
1174
1156
|
.optional()
|
|
1175
|
-
.describe('File extension filter.
|
|
1157
|
+
.describe('File extension filter. Alternative to language parameter.'),
|
|
1176
1158
|
match: z
|
|
1177
1159
|
.enum(['file', 'path'])
|
|
1178
1160
|
.optional()
|
|
1179
|
-
.describe('Search scope:
|
|
1161
|
+
.describe('Search scope: file for file content (default), path for filenames/paths.'),
|
|
1180
1162
|
size: z
|
|
1181
1163
|
.string()
|
|
1182
|
-
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid size format. Use: ">
|
|
1164
|
+
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid size format. Use: ">N", ">=N", "<N", "<=N", "N..M", or exact number')
|
|
1183
1165
|
.optional()
|
|
1184
|
-
.describe('File size filter in KB.
|
|
1166
|
+
.describe('File size filter in KB. Format: ">N" (larger), "<N" (smaller), "N..M" (range).'),
|
|
1185
1167
|
limit: z
|
|
1186
1168
|
.number()
|
|
1187
1169
|
.int()
|
|
@@ -1189,7 +1171,7 @@ function registerGitHubSearchCodeTool(server) {
|
|
|
1189
1171
|
.max(100)
|
|
1190
1172
|
.optional()
|
|
1191
1173
|
.default(30)
|
|
1192
|
-
.describe('Maximum number of results to return (1-100).
|
|
1174
|
+
.describe('Maximum number of results to return (1-100).'),
|
|
1193
1175
|
},
|
|
1194
1176
|
annotations: {
|
|
1195
1177
|
title: 'GitHub Code Search - Smart & Efficient',
|
|
@@ -1199,6 +1181,19 @@ function registerGitHubSearchCodeTool(server) {
|
|
|
1199
1181
|
openWorldHint: true,
|
|
1200
1182
|
},
|
|
1201
1183
|
}, async (args) => {
|
|
1184
|
+
// Validate that exactly one search parameter is provided (not both)
|
|
1185
|
+
const hasExactQuery = !!args.exactQuery;
|
|
1186
|
+
const hasQueryTerms = args.queryTerms && args.queryTerms.length > 0;
|
|
1187
|
+
if (!hasExactQuery && !hasQueryTerms) {
|
|
1188
|
+
return createResult({
|
|
1189
|
+
error: 'One search parameter required: exactQuery OR queryTerms',
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
if (hasExactQuery && hasQueryTerms) {
|
|
1193
|
+
return createResult({
|
|
1194
|
+
error: 'Use either exactQuery OR queryTerms, not both. Choose one search approach.',
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1202
1197
|
try {
|
|
1203
1198
|
const result = await searchGitHubCode(args);
|
|
1204
1199
|
if (result.isError) {
|
|
@@ -1354,26 +1349,31 @@ function extractSingleRepository$1(items) {
|
|
|
1354
1349
|
}
|
|
1355
1350
|
/**
|
|
1356
1351
|
* Build command line arguments for GitHub CLI following the exact CLI format.
|
|
1357
|
-
* Uses proper flags (--flag=value)
|
|
1352
|
+
* Uses proper flags (--flag=value) for filters and direct query terms.
|
|
1358
1353
|
*/
|
|
1359
1354
|
function buildGitHubCliArgs(params) {
|
|
1360
1355
|
const args = ['code'];
|
|
1361
|
-
//
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1356
|
+
// Build search query (either exactQuery OR queryTerms, never both)
|
|
1357
|
+
if (params.exactQuery) {
|
|
1358
|
+
// Add exact query with quotes for literal matching
|
|
1359
|
+
args.push(`"${params.exactQuery}"`);
|
|
1360
|
+
}
|
|
1361
|
+
else if (params.queryTerms && params.queryTerms.length > 0) {
|
|
1362
|
+
// Add query terms as separate arguments (for AND logic)
|
|
1363
|
+
// Auto-quote terms with special characters for literal matching
|
|
1364
|
+
const processedTerms = params.queryTerms.map(term => {
|
|
1365
|
+
// Check if term contains special search characters that need quoting
|
|
1366
|
+
const hasSpecialChars = /[()[\]{}*?^$|.\\+]/.test(term);
|
|
1367
|
+
return hasSpecialChars ? `"${term}"` : term;
|
|
1368
|
+
});
|
|
1369
|
+
args.push(...processedTerms);
|
|
1370
|
+
}
|
|
1371
1371
|
// Add explicit parameters as CLI flags (following GitHub CLI format)
|
|
1372
|
-
if (params.language
|
|
1372
|
+
if (params.language) {
|
|
1373
1373
|
args.push(`--language=${params.language}`);
|
|
1374
1374
|
}
|
|
1375
1375
|
// Handle owner and repo parameters properly
|
|
1376
|
-
if (params.repo
|
|
1376
|
+
if (params.repo) {
|
|
1377
1377
|
const repos = Array.isArray(params.repo) ? params.repo : [params.repo];
|
|
1378
1378
|
repos.forEach(repo => {
|
|
1379
1379
|
// If both owner and repo are provided, combine them for --repo flag
|
|
@@ -1389,30 +1389,27 @@ function buildGitHubCliArgs(params) {
|
|
|
1389
1389
|
}
|
|
1390
1390
|
});
|
|
1391
1391
|
}
|
|
1392
|
-
else if (params.owner
|
|
1393
|
-
!params.query.includes('org:') &&
|
|
1394
|
-
!params.query.includes('user:')) {
|
|
1392
|
+
else if (params.owner) {
|
|
1395
1393
|
// Only owner provided, no repo - use --owner flag for organization-wide search
|
|
1396
1394
|
const owners = Array.isArray(params.owner) ? params.owner : [params.owner];
|
|
1397
1395
|
owners.forEach(owner => args.push(`--owner=${owner}`));
|
|
1398
1396
|
}
|
|
1399
|
-
if (params.filename
|
|
1397
|
+
if (params.filename) {
|
|
1400
1398
|
args.push(`--filename=${params.filename}`);
|
|
1401
1399
|
}
|
|
1402
|
-
if (params.extension
|
|
1400
|
+
if (params.extension) {
|
|
1403
1401
|
args.push(`--extension=${params.extension}`);
|
|
1404
1402
|
}
|
|
1405
|
-
if (params.size
|
|
1403
|
+
if (params.size) {
|
|
1406
1404
|
args.push(`--size=${params.size}`);
|
|
1407
1405
|
}
|
|
1408
1406
|
// Handle match parameter - use --match flag
|
|
1409
1407
|
if (params.match) {
|
|
1410
1408
|
args.push(`--match=${params.match}`);
|
|
1411
1409
|
}
|
|
1412
|
-
// Add limit flag
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
}
|
|
1410
|
+
// Add limit flag (use default 30 if not specified)
|
|
1411
|
+
const limit = params.limit || 30;
|
|
1412
|
+
args.push(`--limit=${limit}`);
|
|
1416
1413
|
// Add JSON output format
|
|
1417
1414
|
args.push('--json=repository,path,textMatches,sha,url');
|
|
1418
1415
|
return args;
|
|
@@ -1433,55 +1430,6 @@ async function searchGitHubCode(params) {
|
|
|
1433
1430
|
}
|
|
1434
1431
|
});
|
|
1435
1432
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Parse search query to preserve quoted phrases and extract qualifiers.
|
|
1438
|
-
* Handles:
|
|
1439
|
-
* - Quoted phrases: "error handling" -> kept as single unit
|
|
1440
|
-
* - Multiple terms: react lifecycle -> both terms for AND search
|
|
1441
|
-
* - Mixed: "error handling" debug -> phrase + term
|
|
1442
|
-
* - Qualifiers: language:javascript -> extracted separately
|
|
1443
|
-
* - Quote escaping issues: automatically fixes common mistakes
|
|
1444
|
-
*/
|
|
1445
|
-
function parseSearchQuery(query) {
|
|
1446
|
-
const qualifiers = [];
|
|
1447
|
-
const searchTerms = [];
|
|
1448
|
-
// Clean up common quote escaping issues
|
|
1449
|
-
let cleanedQuery = query;
|
|
1450
|
-
// Fix escaped quotes that shouldn't be escaped
|
|
1451
|
-
if (cleanedQuery.includes('\\"') && !cleanedQuery.includes(' ')) {
|
|
1452
|
-
cleanedQuery = cleanedQuery.replace(/\\"/g, '');
|
|
1453
|
-
}
|
|
1454
|
-
// Fix single-word queries wrapped in quotes unnecessarily
|
|
1455
|
-
if (cleanedQuery.startsWith('"') &&
|
|
1456
|
-
cleanedQuery.endsWith('"') &&
|
|
1457
|
-
!cleanedQuery.slice(1, -1).includes(' ')) {
|
|
1458
|
-
cleanedQuery = cleanedQuery.slice(1, -1);
|
|
1459
|
-
}
|
|
1460
|
-
// Regular expression to match quoted strings or individual words/qualifiers
|
|
1461
|
-
const tokenRegex = /"([^"]+)"|([^\s]+)/g;
|
|
1462
|
-
let match;
|
|
1463
|
-
while ((match = tokenRegex.exec(cleanedQuery)) !== null) {
|
|
1464
|
-
const token = match[1] || match[2]; // match[1] is quoted content, match[2] is unquoted
|
|
1465
|
-
// Check if it's a qualifier (contains : but not inside quotes)
|
|
1466
|
-
if (!match[1] && token.includes(':') && /^[a-zA-Z]+:/.test(token)) {
|
|
1467
|
-
qualifiers.push(token);
|
|
1468
|
-
}
|
|
1469
|
-
else {
|
|
1470
|
-
// It's a search term (either quoted or unquoted)
|
|
1471
|
-
if (match[1]) {
|
|
1472
|
-
// Preserve quotes for exact phrase search
|
|
1473
|
-
searchTerms.push(`"${token}"`);
|
|
1474
|
-
}
|
|
1475
|
-
else {
|
|
1476
|
-
searchTerms.push(token);
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
return {
|
|
1481
|
-
searchQuery: searchTerms.join(' '),
|
|
1482
|
-
extractedQualifiers: qualifiers,
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
1433
|
|
|
1486
1434
|
/***********************************************************************
|
|
1487
1435
|
|
|
@@ -112365,14 +112313,13 @@ const GITHUB_SEARCH_REPOSITORIES_TOOL_NAME = 'githubSearchRepositories';
|
|
|
112365
112313
|
const DESCRIPTION$6 = `Search GitHub repositories using gh search repos CLI.
|
|
112366
112314
|
|
|
112367
112315
|
BEST PRACTICES:
|
|
112368
|
-
- Use
|
|
112369
|
-
- Use
|
|
112370
|
-
-
|
|
112371
|
-
- Use language to
|
|
112316
|
+
- Use topic for discovering repositories by technology/purpose
|
|
112317
|
+
- Use query for searching by repository name
|
|
112318
|
+
- Use owner to explore specific organizations
|
|
112319
|
+
- Use language to filter by programming language
|
|
112372
112320
|
- Use quality filters (stars, forks) for refinement
|
|
112373
|
-
- Use limit to control the number of repositories to return
|
|
112374
112321
|
|
|
112375
|
-
|
|
112322
|
+
Separate searches for different topics and use minimal filters to get the most relevant results`;
|
|
112376
112323
|
/**
|
|
112377
112324
|
* Extract owner/repo information from various query formats
|
|
112378
112325
|
*/
|
|
@@ -112410,38 +112357,38 @@ function registerSearchGitHubReposTool(server) {
|
|
|
112410
112357
|
query: z
|
|
112411
112358
|
.string()
|
|
112412
112359
|
.optional()
|
|
112413
|
-
.describe('Search
|
|
112360
|
+
.describe('Search by repository name. Use minimal words for repository names or specific projects. For topic discovery, use topic parameter instead.'),
|
|
112414
112361
|
// CORE FILTERS (GitHub CLI flags)
|
|
112415
112362
|
owner: z
|
|
112416
112363
|
.union([z.string(), z.array(z.string())])
|
|
112417
112364
|
.optional()
|
|
112418
|
-
.describe('Repository owner/organization name(s)
|
|
112365
|
+
.describe('Repository owner/organization name(s). Search within specific organizations or users.'),
|
|
112419
112366
|
language: z
|
|
112420
112367
|
.string()
|
|
112421
112368
|
.optional()
|
|
112422
|
-
.describe('Programming language filter. Filters repositories by primary language.
|
|
112369
|
+
.describe('Programming language filter. Filters repositories by primary language.'),
|
|
112423
112370
|
stars: z
|
|
112424
112371
|
.union([
|
|
112425
112372
|
z.number().int().min(0),
|
|
112426
112373
|
z
|
|
112427
112374
|
.string()
|
|
112428
|
-
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid format. Use: ">
|
|
112375
|
+
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid format. Use: ">N", ">=N", "<N", "<=N", "N..M", or exact number'),
|
|
112429
112376
|
])
|
|
112430
112377
|
.optional()
|
|
112431
|
-
.describe('Star count filter. Format: ">
|
|
112378
|
+
.describe('Star count filter. Format: ">N" (more than), "<N" (less than), "N..M" (range).'),
|
|
112432
112379
|
topic: z
|
|
112433
112380
|
.union([z.string(), z.array(z.string())])
|
|
112434
112381
|
.optional()
|
|
112435
|
-
.describe('
|
|
112382
|
+
.describe('Discover repositories by topic. Use for exploring unknown domains and finding projects by technology or purpose.'),
|
|
112436
112383
|
forks: z
|
|
112437
112384
|
.union([
|
|
112438
112385
|
z.number().int().min(0),
|
|
112439
112386
|
z
|
|
112440
112387
|
.string()
|
|
112441
|
-
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid format. Use: ">
|
|
112388
|
+
.regex(/^(>=?\d+|<=?\d+|\d+\.\.\d+|\d+)$/, 'Invalid format. Use: ">N", ">=N", "<N", "<=N", "N..M", or exact number'),
|
|
112442
112389
|
])
|
|
112443
112390
|
.optional()
|
|
112444
|
-
.describe('Fork count filter. Format: ">
|
|
112391
|
+
.describe('Fork count filter. Format: ">N" (more than), "<N" (less than), "N..M" (range).'),
|
|
112445
112392
|
// Match CLI parameter name exactly
|
|
112446
112393
|
'number-topics': z
|
|
112447
112394
|
.union([
|
|
@@ -112456,7 +112403,7 @@ function registerSearchGitHubReposTool(server) {
|
|
|
112456
112403
|
license: z
|
|
112457
112404
|
.union([z.string(), z.array(z.string())])
|
|
112458
112405
|
.optional()
|
|
112459
|
-
.describe('License filter.
|
|
112406
|
+
.describe('License filter. Filter repositories by license type.'),
|
|
112460
112407
|
archived: z
|
|
112461
112408
|
.boolean()
|
|
112462
112409
|
.optional()
|
|
@@ -112520,7 +112467,7 @@ function registerSearchGitHubReposTool(server) {
|
|
|
112520
112467
|
z.array(z.enum(['name', 'description', 'readme'])),
|
|
112521
112468
|
])
|
|
112522
112469
|
.optional()
|
|
112523
|
-
.describe('Search scope.
|
|
112470
|
+
.describe('Search scope. Where to search: name, description, or readme content.'),
|
|
112524
112471
|
// SORTING & LIMITS - Match CLI defaults exactly
|
|
112525
112472
|
sort: z
|
|
112526
112473
|
.enum([
|
|
@@ -113485,22 +113432,25 @@ function buildGitHubPullRequestsListCommand(params) {
|
|
|
113485
113432
|
}
|
|
113486
113433
|
|
|
113487
113434
|
const NPM_PACKAGE_SEARCH_TOOL_NAME = 'npmPackageSearch';
|
|
113488
|
-
const DESCRIPTION$3 = `Search NPM packages
|
|
113489
|
-
|
|
113490
|
-
|
|
113491
|
-
-
|
|
113492
|
-
-
|
|
113493
|
-
-
|
|
113494
|
-
|
|
113495
|
-
|
|
113496
|
-
|
|
113497
|
-
|
|
113498
|
-
-
|
|
113499
|
-
|
|
113500
|
-
|
|
113501
|
-
-
|
|
113502
|
-
|
|
113503
|
-
|
|
113435
|
+
const DESCRIPTION$3 = `Search NPM packages using 'npm search' command. Discover packages by functionality keywords and explore alternatives.
|
|
113436
|
+
|
|
113437
|
+
CAPABILITIES:
|
|
113438
|
+
- Package discovery: npm search <term> --json --searchlimit=<n>
|
|
113439
|
+
- Multiple search terms: searches each term separately and combines results
|
|
113440
|
+
- Functional keyword search: "testing", "validation", "http client"
|
|
113441
|
+
- Repository URL extraction for GitHub integration
|
|
113442
|
+
- Deduplication and result optimization
|
|
113443
|
+
|
|
113444
|
+
SEARCH STRATEGY:
|
|
113445
|
+
- Use broad functional terms for best discovery
|
|
113446
|
+
- Single keywords work better than complex phrases
|
|
113447
|
+
- Multiple searches reveal ecosystem alternatives
|
|
113448
|
+
- Results include package names, versions, descriptions, and repository links
|
|
113449
|
+
|
|
113450
|
+
USAGE EXAMPLES:
|
|
113451
|
+
- Single search: queries="testing"
|
|
113452
|
+
- Multiple searches: queries=["react", "hooks", "typescript"]
|
|
113453
|
+
- Limit results: searchLimit=10`;
|
|
113504
113454
|
const MAX_DESCRIPTION_LENGTH = 100;
|
|
113505
113455
|
const MAX_KEYWORDS = 10;
|
|
113506
113456
|
function registerNpmSearchTool(server) {
|
|
@@ -114365,25 +114315,20 @@ function buildGitHubIssuesAPICommand(params) {
|
|
|
114365
114315
|
}
|
|
114366
114316
|
|
|
114367
114317
|
const NPM_VIEW_PACKAGE_TOOL_NAME = 'npmViewPackage';
|
|
114368
|
-
const DESCRIPTION = `
|
|
114369
|
-
|
|
114370
|
-
|
|
114371
|
-
-
|
|
114372
|
-
-
|
|
114373
|
-
-
|
|
114374
|
-
-
|
|
114375
|
-
|
|
114376
|
-
|
|
114377
|
-
|
|
114378
|
-
-
|
|
114379
|
-
-
|
|
114380
|
-
-
|
|
114381
|
-
|
|
114382
|
-
USE CASES:
|
|
114383
|
-
- Repository discovery from package names
|
|
114384
|
-
- Version analysis and security assessment
|
|
114385
|
-
- Export structure for integration planning
|
|
114386
|
-
- Dependency research and ecosystem exploration`;
|
|
114318
|
+
const DESCRIPTION = `View NPM package information using 'npm view' command. Supports field-specific queries and GitHub repository discovery.
|
|
114319
|
+
|
|
114320
|
+
CAPABILITIES:
|
|
114321
|
+
- Full package info: npm view <package> --json (optimized format)
|
|
114322
|
+
- Single field: npm view <package> <field> (e.g., version, description, license)
|
|
114323
|
+
- Multiple fields: filtered JSON response for specific fields
|
|
114324
|
+
- Repository URLs for GitHub integration and source code analysis
|
|
114325
|
+
- Version history, dependencies, and package metadata
|
|
114326
|
+
|
|
114327
|
+
USAGE EXAMPLES:
|
|
114328
|
+
- Get version: field="version"
|
|
114329
|
+
- Get repository: field="repository" or match="repository"
|
|
114330
|
+
- Get multiple: match=["version", "description", "license"]
|
|
114331
|
+
- Get all info: no parameters (returns optimized package data)`;
|
|
114387
114332
|
function registerNpmViewPackageTool(server) {
|
|
114388
114333
|
server.registerTool(NPM_VIEW_PACKAGE_TOOL_NAME, {
|
|
114389
114334
|
description: DESCRIPTION,
|
|
@@ -114392,6 +114337,51 @@ function registerNpmViewPackageTool(server) {
|
|
|
114392
114337
|
.string()
|
|
114393
114338
|
.min(1)
|
|
114394
114339
|
.describe('NPM package name (e.g., "react", "express", "@types/node"). Include @ prefix for scoped packages.'),
|
|
114340
|
+
field: z
|
|
114341
|
+
.string()
|
|
114342
|
+
.optional()
|
|
114343
|
+
.describe('Optional field to get specific information (e.g., "version", "description", "license"). If not provided, returns full package info.'),
|
|
114344
|
+
match: z
|
|
114345
|
+
.union([
|
|
114346
|
+
z.enum([
|
|
114347
|
+
'version',
|
|
114348
|
+
'description',
|
|
114349
|
+
'license',
|
|
114350
|
+
'author',
|
|
114351
|
+
'homepage',
|
|
114352
|
+
'repository',
|
|
114353
|
+
'dependencies',
|
|
114354
|
+
'devDependencies',
|
|
114355
|
+
'keywords',
|
|
114356
|
+
'main',
|
|
114357
|
+
'scripts',
|
|
114358
|
+
'engines',
|
|
114359
|
+
'files',
|
|
114360
|
+
'publishConfig',
|
|
114361
|
+
'dist-tags',
|
|
114362
|
+
'time',
|
|
114363
|
+
]),
|
|
114364
|
+
z.array(z.enum([
|
|
114365
|
+
'version',
|
|
114366
|
+
'description',
|
|
114367
|
+
'license',
|
|
114368
|
+
'author',
|
|
114369
|
+
'homepage',
|
|
114370
|
+
'repository',
|
|
114371
|
+
'dependencies',
|
|
114372
|
+
'devDependencies',
|
|
114373
|
+
'keywords',
|
|
114374
|
+
'main',
|
|
114375
|
+
'scripts',
|
|
114376
|
+
'engines',
|
|
114377
|
+
'files',
|
|
114378
|
+
'publishConfig',
|
|
114379
|
+
'dist-tags',
|
|
114380
|
+
'time',
|
|
114381
|
+
])),
|
|
114382
|
+
])
|
|
114383
|
+
.optional()
|
|
114384
|
+
.describe('Specific field(s) to retrieve. Can be single field or array of fields. Examples: "version", ["version", "description"], ["dependencies", "devDependencies"]. When used, returns only the specified fields. use repository to get the repository url in github'),
|
|
114395
114385
|
},
|
|
114396
114386
|
annotations: {
|
|
114397
114387
|
title: 'NPM Package Analyzer',
|
|
@@ -114402,13 +114392,48 @@ function registerNpmViewPackageTool(server) {
|
|
|
114402
114392
|
},
|
|
114403
114393
|
}, async (args) => {
|
|
114404
114394
|
try {
|
|
114405
|
-
const result = await viewNpmPackage(args.packageName);
|
|
114395
|
+
const result = await viewNpmPackage(args.packageName, args.field, args.match);
|
|
114406
114396
|
if (result.isError) {
|
|
114407
114397
|
return result;
|
|
114408
114398
|
}
|
|
114399
|
+
// If field is specified, npm returns plain text, not JSON
|
|
114400
|
+
if (args.field) {
|
|
114401
|
+
const plainTextResult = result.content[0].text;
|
|
114402
|
+
// Parse the plain text result from npm command
|
|
114403
|
+
const execResult = JSON.parse(plainTextResult);
|
|
114404
|
+
const fieldValue = execResult.result;
|
|
114405
|
+
return createResult({
|
|
114406
|
+
data: {
|
|
114407
|
+
field: args.field,
|
|
114408
|
+
value: fieldValue,
|
|
114409
|
+
package: args.packageName,
|
|
114410
|
+
},
|
|
114411
|
+
});
|
|
114412
|
+
}
|
|
114413
|
+
// If match is specified, filter the JSON response to only include matched fields
|
|
114414
|
+
if (args.match) {
|
|
114415
|
+
const execResult = JSON.parse(result.content[0].text);
|
|
114416
|
+
const packageData = execResult.result;
|
|
114417
|
+
const matchFields = Array.isArray(args.match)
|
|
114418
|
+
? args.match
|
|
114419
|
+
: [args.match];
|
|
114420
|
+
const filteredData = {};
|
|
114421
|
+
matchFields.forEach(field => {
|
|
114422
|
+
if (packageData[field] !== undefined) {
|
|
114423
|
+
filteredData[field] = packageData[field];
|
|
114424
|
+
}
|
|
114425
|
+
});
|
|
114426
|
+
return createResult({
|
|
114427
|
+
data: {
|
|
114428
|
+
package: args.packageName,
|
|
114429
|
+
fields: matchFields,
|
|
114430
|
+
values: filteredData,
|
|
114431
|
+
},
|
|
114432
|
+
});
|
|
114433
|
+
}
|
|
114434
|
+
// Otherwise return full optimized format (JSON response)
|
|
114409
114435
|
const execResult = JSON.parse(result.content[0].text);
|
|
114410
114436
|
const packageData = execResult.result;
|
|
114411
|
-
// Transform to optimized format
|
|
114412
114437
|
const optimizedResult = transformToOptimizedFormat(packageData);
|
|
114413
114438
|
return createResult({ data: optimizedResult });
|
|
114414
114439
|
}
|
|
@@ -114418,6 +114443,11 @@ function registerNpmViewPackageTool(server) {
|
|
|
114418
114443
|
if (errorMessage.includes('not found') ||
|
|
114419
114444
|
errorMessage.includes('404')) {
|
|
114420
114445
|
const packageName = args.packageName;
|
|
114446
|
+
const fieldInfo = args.field ? ` (field: ${args.field})` : '';
|
|
114447
|
+
const matchInfo = args.match
|
|
114448
|
+
? ` (match: ${Array.isArray(args.match) ? args.match.join(', ') : args.match})`
|
|
114449
|
+
: '';
|
|
114450
|
+
const paramInfo = fieldInfo || matchInfo;
|
|
114421
114451
|
const suggestions = [];
|
|
114422
114452
|
// Check for common naming patterns
|
|
114423
114453
|
if (packageName.includes('_')) {
|
|
@@ -114432,12 +114462,22 @@ function registerNpmViewPackageTool(server) {
|
|
|
114432
114462
|
if (packageName.startsWith('@')) {
|
|
114433
114463
|
suggestions.push(`• Try without scope: "${packageName.split('/')[1]}"`);
|
|
114434
114464
|
}
|
|
114465
|
+
// Add field/match-specific suggestions
|
|
114466
|
+
if (args.field) {
|
|
114467
|
+
suggestions.push(`• Try without field parameter to get full package info`);
|
|
114468
|
+
suggestions.push(`• Common fields: version, description, license, dependencies`);
|
|
114469
|
+
}
|
|
114470
|
+
if (args.match) {
|
|
114471
|
+
suggestions.push(`• Try without match parameter to get full package info`);
|
|
114472
|
+
suggestions.push(`• Try single field instead of multiple: field: "version"`);
|
|
114473
|
+
suggestions.push(`• Common fields: version, description, license, dependencies`);
|
|
114474
|
+
}
|
|
114435
114475
|
// Add discovery alternatives
|
|
114436
114476
|
suggestions.push('• Use npm_package_search for discovery');
|
|
114437
114477
|
suggestions.push('• Use github_search_repos to find source repository');
|
|
114438
114478
|
suggestions.push('• Check exact spelling on npmjs.com');
|
|
114439
114479
|
return createResult({
|
|
114440
|
-
error: `Package "${packageName}" not found on NPM registry.
|
|
114480
|
+
error: `Package "${packageName}"${paramInfo} not found on NPM registry.
|
|
114441
114481
|
|
|
114442
114482
|
Try these alternatives:
|
|
114443
114483
|
${suggestions.join('\n')}
|
|
@@ -114582,11 +114622,14 @@ function simplifyExports(exports) {
|
|
|
114582
114622
|
}
|
|
114583
114623
|
return { main: 'index.js' };
|
|
114584
114624
|
}
|
|
114585
|
-
async function viewNpmPackage(packageName) {
|
|
114586
|
-
const cacheKey = generateCacheKey('npm-view', { packageName });
|
|
114625
|
+
async function viewNpmPackage(packageName, field, match) {
|
|
114626
|
+
const cacheKey = generateCacheKey('npm-view', { packageName, field, match });
|
|
114587
114627
|
return withCache(cacheKey, async () => {
|
|
114588
114628
|
try {
|
|
114589
|
-
|
|
114629
|
+
// Build arguments based on parameters
|
|
114630
|
+
// Priority: field > match > full JSON
|
|
114631
|
+
const args = field ? [packageName, field] : [packageName, '--json']; // For match or full info, we need JSON
|
|
114632
|
+
const result = await executeNpmCommand('view', args, {
|
|
114590
114633
|
cache: false,
|
|
114591
114634
|
});
|
|
114592
114635
|
return result;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "octocode-mcp",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.12",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for advanced GitHub repository analysis, code discovery, and npm package exploration. Provides AI assistants with powerful tools to search, analyze, and understand codebases across GitHub and npm ecosystems.",
|
|
5
5
|
"author": "Guy Bary <guybary@gmail.com>",
|
|
6
6
|
"homepage": "https://octocode.ai",
|