@oss-scout/mcp 0.10.2 → 0.11.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/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export { registerResources } from "./resources.js";
12
12
  /** Server identity, kept in one place for the bin and any embedding host. */
13
13
  export declare const SERVER_INFO: {
14
14
  readonly name: "oss-scout-mcp";
15
- readonly version: "0.10.2";
15
+ readonly version: "0.11.0";
16
16
  };
17
17
  /**
18
18
  * Build a fully-wired MCP server (tools + resources) around a scout.
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { registerResources } from "./resources.js";
15
15
  /** Server identity, kept in one place for the bin and any embedding host. */
16
16
  export const SERVER_INFO = {
17
17
  name: "oss-scout-mcp",
18
- version: "0.10.2", // x-release-please-version
18
+ version: "0.11.0", // x-release-please-version
19
19
  };
20
20
  /**
21
21
  * Build a fully-wired MCP server (tools + resources) around a scout.
@@ -36075,6 +36075,7 @@ var IssueScopeSchema = external_exports3.enum([
36075
36075
  ]);
36076
36076
  var SearchStrategySchema = external_exports3.enum([
36077
36077
  "merged",
36078
+ "orgs",
36078
36079
  "starred",
36079
36080
  "broad",
36080
36081
  "maintained",
@@ -36082,6 +36083,7 @@ var SearchStrategySchema = external_exports3.enum([
36082
36083
  ]);
36083
36084
  var CONCRETE_STRATEGIES = [
36084
36085
  "merged",
36086
+ "orgs",
36085
36087
  "starred",
36086
36088
  "broad",
36087
36089
  "maintained"
@@ -36215,6 +36217,9 @@ var ScoutPreferencesSchema = external_exports3.looseObject({
36215
36217
  scope: external_exports3.array(IssueScopeSchema).optional(),
36216
36218
  excludeRepos: external_exports3.array(external_exports3.string()).default([]),
36217
36219
  excludeOrgs: external_exports3.array(external_exports3.string()).default([]),
36220
+ // Orgs whose repos the "orgs" search phase targets with org: qualifiers.
36221
+ // Empty (the default) disables the phase even when the strategy is enabled.
36222
+ preferredOrgs: external_exports3.array(external_exports3.string()).default([]),
36218
36223
  aiPolicyBlocklist: external_exports3.array(external_exports3.string()).default(["matplotlib/matplotlib"]),
36219
36224
  projectCategories: external_exports3.array(ProjectCategorySchema).default([]),
36220
36225
  minStars: external_exports3.number().default(50),
@@ -38420,7 +38425,7 @@ function buildLanguageVariants(languages, isAnyLanguage, hasLabels) {
38420
38425
  return [languages.map((l) => `language:${l}`).join(" ")];
38421
38426
  return languages.map((l) => `language:${l}`);
38422
38427
  }
38423
- async function searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage, labels, buildBaseQuery, perPage, tracker = getSearchBudgetTracker(), startOffset = 0) {
38428
+ async function searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage, labels, buildBaseQuery, perPage, tracker = getSearchBudgetTracker(), startOffset = 0, reservedOps = 0) {
38424
38429
  const variants = buildLanguageVariants(languages, isAnyLanguage, labels.length > 0);
38425
38430
  const k = variants.length > 0 ? startOffset % variants.length : 0;
38426
38431
  const langVariants = [...variants.slice(k), ...variants.slice(0, k)];
@@ -38429,7 +38434,7 @@ async function searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage,
38429
38434
  for (let i = 0; i < langVariants.length; i++) {
38430
38435
  if (i > 0)
38431
38436
  await sleep(GRAPHQL_INTER_QUERY_DELAY_MS);
38432
- const items = await searchWithChunkedLabels(octokit, labels, 0, (labelQ) => `${buildBaseQuery(langVariants[i])} ${labelQ}`.replace(/ +/g, " ").trim(), perPage, tracker);
38437
+ const items = await searchWithChunkedLabels(octokit, labels, reservedOps, (labelQ) => `${buildBaseQuery(langVariants[i])} ${labelQ}`.replace(/ +/g, " ").trim(), perPage, tracker);
38433
38438
  for (const item of items) {
38434
38439
  if (!seenUrls.has(item.html_url)) {
38435
38440
  seenUrls.add(item.html_url);
@@ -38607,6 +38612,35 @@ async function runPhase0(octokit, vetter, repos, maxResults, filterIssues) {
38607
38612
  rateLimitHit
38608
38613
  };
38609
38614
  }
38615
+ var MAX_QUERY_ORGS = 8;
38616
+ async function runPhaseOrgs(octokit, vetter, orgs, languages, isAnyLanguage, labels, maxResults, minStars, phase0RepoSet, starredRepoSet, filterIssues, tracker) {
38617
+ info(MODULE12, `Orgs phase: searching ${orgs.length} preferred org(s)...`);
38618
+ const queryOrgs = orgs.slice(0, MAX_QUERY_ORGS);
38619
+ if (orgs.length > MAX_QUERY_ORGS) {
38620
+ warn(MODULE12, `Orgs phase: capping query at ${MAX_QUERY_ORGS} org(s); dropping ${orgs.slice(MAX_QUERY_ORGS).join(", ")}`);
38621
+ }
38622
+ const orgQuery = queryOrgs.map((o) => `org:${o}`).join(" ");
38623
+ try {
38624
+ const allItems = await searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage, labels, (langQ) => `is:issue is:open ${langQ} no:assignee ${orgQuery}`.replace(/ +/g, " ").trim(), maxResults * 3, tracker, 0, queryOrgs.length);
38625
+ const { candidates, allVetFailed, rateLimitHit } = await filterVetAndScore(vetter, allItems, filterIssues, [phase0RepoSet, starredRepoSet], maxResults, minStars, "Orgs phase");
38626
+ info(MODULE12, `Found ${candidates.length} candidates from preferred orgs`);
38627
+ return {
38628
+ candidates,
38629
+ error: allVetFailed ? "all vetting failed" : null,
38630
+ rateLimitHit
38631
+ };
38632
+ } catch (error48) {
38633
+ if (getHttpStatusCode(error48) === 401)
38634
+ throw error48;
38635
+ const errMsg = errorMessage(error48);
38636
+ warn(MODULE12, `Error in preferred-orgs search: ${errMsg}`);
38637
+ return {
38638
+ candidates: [],
38639
+ error: errMsg,
38640
+ rateLimitHit: isRateLimitError(error48)
38641
+ };
38642
+ }
38643
+ }
38610
38644
  async function runPhase1(octokit, vetter, repos, labels, maxResults, filterIssues) {
38611
38645
  info(MODULE12, `Phase 1: Searching issues in ${repos.length} starred repos...`);
38612
38646
  const phase1Labels = labels.slice(0, 3);
@@ -38896,7 +38930,9 @@ var IssueDiscovery = class {
38896
38930
  break;
38897
38931
  }
38898
38932
  const phase0RepoSet = new Set(phase0Repos);
38899
- const otherStrategiesCanRun = starredRepos.length > 0 && enabledStrategies.has("starred") || enabledStrategies.has("broad") || enabledStrategies.has("maintained");
38933
+ const preferredOrgs = config2.preferredOrgs ?? [];
38934
+ const orgsPhaseEnabled = preferredOrgs.length > 0 && enabledStrategies.has("orgs");
38935
+ const otherStrategiesCanRun = orgsPhaseEnabled || starredRepos.length > 0 && enabledStrategies.has("starred") || enabledStrategies.has("broad") || enabledStrategies.has("maintained");
38900
38936
  if (phase0Repos.length > 0 && enabledStrategies.has("merged")) {
38901
38937
  const phase0Cap = otherStrategiesCanRun ? Math.max(1, Math.ceil(maxResults * PHASE0_MAX_SHARE)) : maxResults;
38902
38938
  const remaining = Math.min(maxResults - allCandidates.length, phase0Cap);
@@ -38906,6 +38942,13 @@ var IssueDiscovery = class {
38906
38942
  }
38907
38943
  strategiesUsed.push("merged");
38908
38944
  }
38945
+ if (allCandidates.length < maxResults && orgsPhaseEnabled) {
38946
+ await applyInterPhaseDelay();
38947
+ const remaining = maxResults - allCandidates.length;
38948
+ const result = await runPhaseOrgs(this.octokit, this.vetter, preferredOrgs, languages, isAnyLanguage, labels, remaining, minStars, phase0RepoSet, starredRepoSet, filterIssues, tracker);
38949
+ recordPhaseResult("orgs", result);
38950
+ strategiesUsed.push("orgs");
38951
+ }
38909
38952
  if (allCandidates.length < maxResults && starredRepos.length > 0 && searchBudget >= CRITICAL_BUDGET_THRESHOLD && enabledStrategies.has("starred")) {
38910
38953
  await applyInterPhaseDelay();
38911
38954
  const reposToSearch = starredRepos.filter((r) => !phase0RepoSet.has(r));
@@ -38925,7 +38968,8 @@ var IssueDiscovery = class {
38925
38968
  if (viableBeforeBroad >= maxResults && enabledStrategies.has("broad")) {
38926
38969
  info(MODULE12, `Skipping broad search: ${viableBeforeBroad} viable candidate(s) already meet maxResults (${maxResults})`);
38927
38970
  } else if (enabledStrategies.has("broad")) {
38928
- const newRepoCandidateCount = allCandidates.filter((c) => c.recommendation !== "skip" && !phase0RepoSet.has(c.issue.repo) && !starredRepoSet.has(c.issue.repo)).length;
38971
+ const preferredOrgSet = new Set(preferredOrgs.map((o) => o.toLowerCase()));
38972
+ const newRepoCandidateCount = allCandidates.filter((c) => c.recommendation !== "skip" && !phase0RepoSet.has(c.issue.repo) && !starredRepoSet.has(c.issue.repo) && !preferredOrgSet.has(c.issue.repo.split("/")[0]?.toLowerCase() ?? "")).length;
38929
38973
  if (skipThreshold > 0 && newRepoCandidateCount >= skipThreshold) {
38930
38974
  info(MODULE12, `Skipping broad search: already found ${newRepoCandidateCount} viable candidate(s) from new repos (threshold: ${skipThreshold})`);
38931
38975
  } else {
@@ -38957,6 +39001,7 @@ var IssueDiscovery = class {
38957
39001
  if (allCandidates.length === 0) {
38958
39002
  const errorDetails = [
38959
39003
  phaseErrors["0"] ? `Phase 0 (merged-PR repos): ${phaseErrors["0"]}` : null,
39004
+ phaseErrors["orgs"] ? `Orgs phase (preferred orgs): ${phaseErrors["orgs"]}` : null,
38960
39005
  phaseErrors["1"] ? `Phase 1 (starred repos): ${phaseErrors["1"]}` : null,
38961
39006
  phaseErrors["2"] ? `Phase 2 (general): ${phaseErrors["2"]}` : null,
38962
39007
  phaseErrors["3"] ? `Phase 3 (maintained repos): ${phaseErrors["3"]}` : null
@@ -40647,6 +40692,7 @@ var FIELD_CONFIGS = {
40647
40692
  scope: { type: "enum-array", validValues: IssueScopeSchema.options },
40648
40693
  excludeRepos: { type: "array" },
40649
40694
  excludeOrgs: { type: "array" },
40695
+ preferredOrgs: { type: "array" },
40650
40696
  aiPolicyBlocklist: { type: "array" },
40651
40697
  projectCategories: {
40652
40698
  type: "enum-array",
@@ -40810,7 +40856,7 @@ function registerTools(server, scout) {
40810
40856
  {
40811
40857
  maxResults: external_exports3.number().int().min(1).max(100).optional().describe("Maximum number of results to return (1-100, default 10)"),
40812
40858
  strategies: external_exports3.string().optional().describe(
40813
- "Comma-separated search strategies: merged, starred, broad, maintained, all"
40859
+ "Comma-separated search strategies: merged, orgs, starred, broad, maintained, all"
40814
40860
  ),
40815
40861
  preferLanguages: external_exports3.array(external_exports3.string()).optional().describe(
40816
40862
  "Soft-boost ranking for candidates whose repo language matches one of these (case-insensitive). Personalization tier between recommendation and viabilityScore (#1244). Not a filter; only reorders."
@@ -41157,7 +41203,7 @@ function registerResources(server, scout) {
41157
41203
  // src/index.ts
41158
41204
  var SERVER_INFO = {
41159
41205
  name: "oss-scout-mcp",
41160
- version: "0.10.2"
41206
+ version: "0.11.0"
41161
41207
  // x-release-please-version
41162
41208
  };
41163
41209
  function createServer(scout) {
package/dist/tools.js CHANGED
@@ -44,7 +44,7 @@ export function registerTools(server, scout) {
44
44
  strategies: z
45
45
  .string()
46
46
  .optional()
47
- .describe("Comma-separated search strategies: merged, starred, broad, maintained, all"),
47
+ .describe("Comma-separated search strategies: merged, orgs, starred, broad, maintained, all"),
48
48
  preferLanguages: z
49
49
  .array(z.string())
50
50
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-scout/mcp",
3
- "version": "0.10.2",
3
+ "version": "0.11.0",
4
4
  "description": "MCP server for oss-scout — exposes issue discovery and vetting as MCP tools",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "dependencies": {
19
19
  "@modelcontextprotocol/sdk": "^1.27.1",
20
20
  "zod": "^4.3.6",
21
- "@oss-scout/core": "^1.5.2"
21
+ "@oss-scout/core": "^1.6.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^25.5.0",