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.
Files changed (2) hide show
  1. package/build/index.js +223 -180
  2. 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 = `Verify API connections and discover available organizations. FIRST STEP for private repository research.
948
-
949
- AUTHENTICATION VERIFICATION:
950
- - Check GitHub and NPM CLI authentication status
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
- TERM OPTIMIZATION (IMPORTANT):
1123
- - BEST: Single terms for maximum coverage and relevance
1124
- - GOOD: 2 terms when you need both to be present
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
- Search Logic:
1134
- - Multiple terms = ALL must be present (AND logic) - very restrictive
1135
- - Single terms = maximum results and coverage
1136
- - Quoted phrases = exact phrase matching
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
- Quote Usage:
1140
- - Single terms: NO quotes (useState, authentication)
1141
- - Multi-word phrases: WITH quotes ("error handling", "user authentication")
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
- - All filters use GitHub CLI flags (--language, --owner, --repo, etc.)
1146
- - Combine filters to narrow scope: language + owner, repo + filename
1147
- - Never use filters on exploratory searches - use to refine when too many results`;
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
- query: z
1130
+ exactQuery: z
1153
1131
  .string()
1154
- .min(1)
1155
- .describe('Search query with AND logic between terms. OPTIMIZATION: Single terms give best coverage, 2 terms when both needed, 3+ terms very restrictive. Multiple words require ALL to be present. Use quotes for exact phrases. Examples: "useState" (best coverage), "error handling" (exact phrase), "react hook useState" (specific but restrictive).'),
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. Uses --language CLI flag. Narrows search to specific language files. Use for language-specific searches.'),
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) to search within (e.g., "facebook", ["google", "microsoft"]). Uses --owner CLI flag for organization-wide search. Can be combined with repo parameter for specific repository search. Do NOT use owner/repo format - just the organization/username.'),
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('Filter on specific repository(ies). Uses --repo CLI flag. Two usage patterns: (1) Use with owner parameter - provide just repo name (e.g., owner="facebook", repo="react" → --repo=facebook/react), or (2) Use alone - provide full "owner/repo" format (e.g., "facebook/react" → --repo=facebook/react).'),
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. Uses --filename CLI flag. Use for file-specific searches.'),
1153
+ .describe('Target specific filename or pattern.'),
1172
1154
  extension: z
1173
1155
  .string()
1174
1156
  .optional()
1175
- .describe('File extension filter. Uses --extension CLI flag. Alternative to language parameter.'),
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: "file" for file content (default), "path" for filenames/paths. Uses --match CLI flag. Single value only - multiple scopes not supported by GitHub CLI.'),
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: ">10", ">=5", "<100", "<=50", "10..100", or exact number "50"')
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. Uses --size CLI flag. Format: ">N" (larger than), "<N" (smaller than), "N..M" (range), "N" (exact).'),
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). Default: 30. Higher values may increase response time.'),
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) instead of qualifiers where appropriate.
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
- // Parse query to preserve quoted phrases and extract qualifiers
1362
- const { searchQuery, extractedQualifiers } = parseSearchQuery(params.query);
1363
- // Add the main search query if present
1364
- if (searchQuery) {
1365
- args.push(searchQuery);
1366
- }
1367
- // Add extracted qualifiers from the query (these should remain as qualifiers)
1368
- extractedQualifiers.forEach(qualifier => {
1369
- args.push(qualifier);
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 && !params.query.includes('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 && !params.query.includes('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 && !params.query.includes('filename:')) {
1397
+ if (params.filename) {
1400
1398
  args.push(`--filename=${params.filename}`);
1401
1399
  }
1402
- if (params.extension && !params.query.includes('extension:')) {
1400
+ if (params.extension) {
1403
1401
  args.push(`--extension=${params.extension}`);
1404
1402
  }
1405
- if (params.size && !params.query.includes('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
- if (params.limit) {
1414
- args.push(`--limit=${params.limit}`);
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 topics for unknown domains to explore repositories by TOPIC
112369
- - Use owner to explore repositories by ORGANIZATION
112370
- - Search by name and sort by best match / starts to search specific repositories
112371
- - Use language to explore repositories by LANGUAGE
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
- Seperate queries for different topics and repositories search and use minimal filters to get the most relevant results`;
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 query with AND logic between terms. Multiple words require ALL to be present. Use quotes for exact phrases. Examples: "cli shell", "vim plugin". For negation, use embedded qualifiers like "topic:react -topic:vue". Advanced: supports GitHub search qualifiers (stars:>100, language:python, etc.)'),
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) (e.g., "facebook", ["google", "microsoft"]). Search within specific organizations. Do NOT use owner/repo format - just the organization/username.'),
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. Essential for language-specific searches.'),
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: ">1000", ">=500", "<100", "<=50", "10..100", or exact number "50"'),
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: ">1000" (more than), ">=500" (more than or equal), "<100" (less than), "<=50" (less than or equal), "100..1000" (range), "500" (exact).'),
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('🎯 BEST FOR EXPLORATION: Repository topics filter. Use for discovering projects in unknown domains. Format: single topic "react" or array ["unix", "terminal"]. Topics use kebab-case format.'),
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: ">100", ">=50", "<10", "<=5", "10..100", or exact number "5"'),
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: ">100" (more than), ">=50" (more than or equal), "<10" (less than), "<=5" (less than or equal), "10..100" (range), "5" (exact).'),
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. Examples: "mit", "apache-2.0", ["mit", "bsd-3-clause"]'),
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. "name" (repository names only), "description" (descriptions only), "readme" (README content). Can be single value or array.'),
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 by functionality keywords. PRIMARY ENTRY POINT for package-related queries.
113489
-
113490
- PACKAGE-FIRST STRATEGY:
113491
- - Start here when users mention: libraries, dependencies, installations, alternatives
113492
- - Use broad functional terms for discovery (not exact package names)
113493
- - Bridge to GitHub tools via repository URLs from results
113494
-
113495
- SEARCH APPROACH:
113496
- - Single functional terms work best for discovery
113497
- - Multiple searches for different aspects/use-cases
113498
- - Reveals ecosystem alternatives and quality indicators
113499
-
113500
- INTEGRATION WORKFLOW:
113501
- - Package Discovery Repository Analysis Implementation Patterns
113502
- - npmPackageSearch → npmViewPackage → GitHub repository tools
113503
- - Compare alternatives by searching different functional terms`;
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 = `Analyze NPM packages for repository discovery and dependency insights. BRIDGE to GitHub ecosystem.
114369
-
114370
- PACKAGE ANALYSIS CAPABILITIES:
114371
- - Repository URL discovery for GitHub exploration
114372
- - Version history and release patterns
114373
- - Export analysis for implementation understanding
114374
- - Dependency metadata for ecosystem mapping
114375
-
114376
- GITHUB INTEGRATION:
114377
- - Provides repository links for GitHub repository tools
114378
- - Connects package metadata to source code analysis
114379
- - Enables package-to-implementation research workflows
114380
- - Essential for dependency and alternative evaluation
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
- const result = await executeNpmCommand('view', [packageName, '--json'], {
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.11",
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",