@oss-scout/mcp 0.6.0 → 0.7.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/mcp-server.bundle.cjs +73 -7
- package/dist/tools.js +11 -1
- package/package.json +2 -2
|
@@ -37542,6 +37542,32 @@ async function searchWithChunkedLabels(octokit, labels, reservedOps, buildQuery,
|
|
|
37542
37542
|
}
|
|
37543
37543
|
return allItems;
|
|
37544
37544
|
}
|
|
37545
|
+
function buildLanguageVariants(languages, isAnyLanguage, hasLabels) {
|
|
37546
|
+
if (isAnyLanguage || languages.length === 0)
|
|
37547
|
+
return [""];
|
|
37548
|
+
if (languages.length === 1)
|
|
37549
|
+
return [`language:${languages[0]}`];
|
|
37550
|
+
if (!hasLabels)
|
|
37551
|
+
return [languages.map((l) => `language:${l}`).join(" ")];
|
|
37552
|
+
return languages.map((l) => `language:${l}`);
|
|
37553
|
+
}
|
|
37554
|
+
async function searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage, labels, buildBaseQuery, perPage) {
|
|
37555
|
+
const langVariants = buildLanguageVariants(languages, isAnyLanguage, labels.length > 0);
|
|
37556
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
37557
|
+
const allItems = [];
|
|
37558
|
+
for (let i = 0; i < langVariants.length; i++) {
|
|
37559
|
+
if (i > 0)
|
|
37560
|
+
await sleep(INTER_QUERY_DELAY_MS);
|
|
37561
|
+
const items = await searchWithChunkedLabels(octokit, labels, 0, (labelQ) => `${buildBaseQuery(langVariants[i])} ${labelQ}`.replace(/ +/g, " ").trim(), perPage);
|
|
37562
|
+
for (const item of items) {
|
|
37563
|
+
if (!seenUrls.has(item.html_url)) {
|
|
37564
|
+
seenUrls.add(item.html_url);
|
|
37565
|
+
allItems.push(item);
|
|
37566
|
+
}
|
|
37567
|
+
}
|
|
37568
|
+
}
|
|
37569
|
+
return allItems;
|
|
37570
|
+
}
|
|
37545
37571
|
async function filterVetAndScore(vetter, items, filterIssues, excludedRepoSets, remainingNeeded, minStars, phaseLabel) {
|
|
37546
37572
|
const spamRepos = detectLabelFarmingRepos(items);
|
|
37547
37573
|
if (spamRepos.size > 0) {
|
|
@@ -37574,6 +37600,33 @@ async function filterVetAndScore(vetter, items, filterIssues, excludedRepoSets,
|
|
|
37574
37600
|
return { candidates: starFiltered, allVetFailed, rateLimitHit };
|
|
37575
37601
|
}
|
|
37576
37602
|
|
|
37603
|
+
// ../core/dist/core/personalization.js
|
|
37604
|
+
var REPO_BOOST = 20;
|
|
37605
|
+
var LANGUAGE_BOOST = 10;
|
|
37606
|
+
function annotateBoost(candidates, preferLanguages, preferRepos) {
|
|
37607
|
+
const langSet = new Set((preferLanguages ?? []).map((l) => l.trim().toLowerCase()).filter(Boolean));
|
|
37608
|
+
const repoSet = new Set((preferRepos ?? []).map((r) => r.trim()).filter(Boolean));
|
|
37609
|
+
if (langSet.size === 0 && repoSet.size === 0)
|
|
37610
|
+
return;
|
|
37611
|
+
for (const c of candidates) {
|
|
37612
|
+
let score = 0;
|
|
37613
|
+
const reasons = [];
|
|
37614
|
+
if (repoSet.size > 0 && repoSet.has(c.issue.repo)) {
|
|
37615
|
+
score += REPO_BOOST;
|
|
37616
|
+
reasons.push(`repo affinity: ${c.issue.repo}`);
|
|
37617
|
+
}
|
|
37618
|
+
const lang = c.projectHealth.language;
|
|
37619
|
+
if (langSet.size > 0 && lang && langSet.has(lang.toLowerCase())) {
|
|
37620
|
+
score += LANGUAGE_BOOST;
|
|
37621
|
+
reasons.push(`language match: ${lang}`);
|
|
37622
|
+
}
|
|
37623
|
+
if (score > 0) {
|
|
37624
|
+
c.boostScore = score;
|
|
37625
|
+
c.boostReasons = reasons;
|
|
37626
|
+
}
|
|
37627
|
+
}
|
|
37628
|
+
}
|
|
37629
|
+
|
|
37577
37630
|
// ../core/dist/core/issue-discovery.js
|
|
37578
37631
|
var MODULE10 = "issue-discovery";
|
|
37579
37632
|
var LOW_BUDGET_THRESHOLD = 20;
|
|
@@ -37629,7 +37682,7 @@ async function runPhase1(octokit, vetter, repos, labels, maxResults, filterIssue
|
|
|
37629
37682
|
rateLimitHit
|
|
37630
37683
|
};
|
|
37631
37684
|
}
|
|
37632
|
-
async function runPhase2(octokit, vetter, scopes, labels, configLabels,
|
|
37685
|
+
async function runPhase2(octokit, vetter, scopes, labels, configLabels, languages, isAnyLanguage, maxResults, minStars, phase0RepoSet, starredRepoSet, existingCandidates, filterIssues) {
|
|
37633
37686
|
info(MODULE10, "Phase 2: General issue search...");
|
|
37634
37687
|
const seenRepos = new Set(existingCandidates.map((c) => c.issue.repo));
|
|
37635
37688
|
const tierLabelGroups = [];
|
|
@@ -37656,7 +37709,7 @@ async function runPhase2(octokit, vetter, scopes, labels, configLabels, baseQual
|
|
|
37656
37709
|
let rateLimitHit = false;
|
|
37657
37710
|
for (const { tier, tierLabels } of tierLabelGroups) {
|
|
37658
37711
|
try {
|
|
37659
|
-
const allItems = await
|
|
37712
|
+
const allItems = await searchAcrossLanguagesAndLabels(octokit, languages, isAnyLanguage, tierLabels, (langQ) => `is:issue is:open ${langQ} no:assignee`.replace(/ +/g, " ").trim(), budgetPerTier * 3);
|
|
37660
37713
|
info(MODULE10, `Phase 2 [${tier}]: processing ${allItems.length} items...`);
|
|
37661
37714
|
const { candidates: tierCandidates, allVetFailed, rateLimitHit: vetRateLimitHit } = await filterVetAndScore(vetter, allItems, filterIssues, [phase0RepoSet, starredRepoSet, seenRepos], budgetPerTier, minStars, `Phase 2 [${tier}]`);
|
|
37662
37715
|
tierResults.push(tierCandidates);
|
|
@@ -37850,7 +37903,6 @@ var IssueDiscovery = class {
|
|
|
37850
37903
|
const lowScoringRepos = new Set(this.deriveLowScoringRepos(config2.minRepoScoreThreshold));
|
|
37851
37904
|
const isAnyLanguage = languages.some((l) => l.toLowerCase() === "any");
|
|
37852
37905
|
const langQuery = isAnyLanguage ? "" : languages.map((l) => `language:${l}`).join(" ");
|
|
37853
|
-
const baseQualifiers = `is:issue is:open ${langQuery} no:assignee`.replace(/ +/g, " ").trim();
|
|
37854
37906
|
const aiBlocklisted = new Set(config2.aiPolicyBlocklist);
|
|
37855
37907
|
if (aiBlocklisted.size > 0) {
|
|
37856
37908
|
debug(MODULE10, `[AI_POLICY_FILTER] Filtering issues from ${aiBlocklisted.size} blocklisted repo(s): ${[...aiBlocklisted].join(", ")}`);
|
|
@@ -37922,7 +37974,7 @@ var IssueDiscovery = class {
|
|
|
37922
37974
|
info(MODULE10, `Skipping broad phase delay: no results from previous phases, proceeding immediately`);
|
|
37923
37975
|
}
|
|
37924
37976
|
const remaining = maxResults - allCandidates.length;
|
|
37925
|
-
const result = await runPhase2(this.octokit, this.vetter, scopes, labels, config2.labels,
|
|
37977
|
+
const result = await runPhase2(this.octokit, this.vetter, scopes, labels, config2.labels, languages, isAnyLanguage, remaining, minStars, phase0RepoSet, starredRepoSet, allCandidates, filterIssues);
|
|
37926
37978
|
allCandidates.push(...result.candidates);
|
|
37927
37979
|
phaseErrors["2"] = result.error;
|
|
37928
37980
|
if (result.rateLimitHit)
|
|
@@ -37967,6 +38019,7 @@ var IssueDiscovery = class {
|
|
|
37967
38019
|
if (rateLimitHitDuringSearch || phasesSkippedForBudget) {
|
|
37968
38020
|
this.rateLimitWarning = `Search results may be incomplete: GitHub API rate limits were hit during search.${budgetNote} Found ${allCandidates.length} candidate${allCandidates.length === 1 ? "" : "s"} but some search phases were limited. Try again after the rate limit resets for complete results.`;
|
|
37969
38021
|
}
|
|
38022
|
+
annotateBoost(allCandidates, options.preferLanguages, options.preferRepos);
|
|
37970
38023
|
allCandidates.sort((a, b) => {
|
|
37971
38024
|
const priorityOrder = {
|
|
37972
38025
|
merged_pr: 0,
|
|
@@ -37980,6 +38033,9 @@ var IssueDiscovery = class {
|
|
|
37980
38033
|
const recDiff = recommendationOrder[a.recommendation] - recommendationOrder[b.recommendation];
|
|
37981
38034
|
if (recDiff !== 0)
|
|
37982
38035
|
return recDiff;
|
|
38036
|
+
const boostDiff = (b.boostScore ?? 0) - (a.boostScore ?? 0);
|
|
38037
|
+
if (boostDiff !== 0)
|
|
38038
|
+
return boostDiff;
|
|
37983
38039
|
return b.viabilityScore - a.viabilityScore;
|
|
37984
38040
|
});
|
|
37985
38041
|
const capped = applyPerRepoCap(allCandidates, 2);
|
|
@@ -38812,7 +38868,9 @@ var OssScout = class {
|
|
|
38812
38868
|
const { candidates, strategiesUsed } = await discovery.searchIssues({
|
|
38813
38869
|
maxResults: options?.maxResults,
|
|
38814
38870
|
strategies: options?.strategies,
|
|
38815
|
-
skippedUrls
|
|
38871
|
+
skippedUrls,
|
|
38872
|
+
preferLanguages: options?.preferLanguages,
|
|
38873
|
+
preferRepos: options?.preferRepos
|
|
38816
38874
|
});
|
|
38817
38875
|
this.state.lastSearchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38818
38876
|
this.dirty = true;
|
|
@@ -39271,15 +39329,23 @@ function registerTools(server, scout) {
|
|
|
39271
39329
|
maxResults: external_exports3.number().optional().describe("Maximum number of results to return (default 10)"),
|
|
39272
39330
|
strategies: external_exports3.string().optional().describe(
|
|
39273
39331
|
"Comma-separated search strategies: merged, starred, broad, maintained, all"
|
|
39332
|
+
),
|
|
39333
|
+
preferLanguages: external_exports3.array(external_exports3.string()).optional().describe(
|
|
39334
|
+
"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."
|
|
39335
|
+
),
|
|
39336
|
+
preferRepos: external_exports3.array(external_exports3.string()).optional().describe(
|
|
39337
|
+
"Soft-boost ranking for candidates in one of these `owner/repo` slugs. Stronger weight than language match (#1244). Not a filter; only reorders."
|
|
39274
39338
|
)
|
|
39275
39339
|
},
|
|
39276
|
-
async ({ maxResults, strategies }) => {
|
|
39340
|
+
async ({ maxResults, strategies, preferLanguages, preferRepos }) => {
|
|
39277
39341
|
try {
|
|
39278
39342
|
const parsedStrategies = strategies ? strategies.split(",").map((s) => SearchStrategySchema.parse(s.trim())) : void 0;
|
|
39279
39343
|
const result = await withTimeout(
|
|
39280
39344
|
scout.search({
|
|
39281
39345
|
maxResults: maxResults ?? 10,
|
|
39282
|
-
strategies: parsedStrategies
|
|
39346
|
+
strategies: parsedStrategies,
|
|
39347
|
+
preferLanguages,
|
|
39348
|
+
preferRepos
|
|
39283
39349
|
})
|
|
39284
39350
|
);
|
|
39285
39351
|
scout.saveResults(result.candidates);
|
package/dist/tools.js
CHANGED
|
@@ -18,7 +18,15 @@ export function registerTools(server, scout) {
|
|
|
18
18
|
.string()
|
|
19
19
|
.optional()
|
|
20
20
|
.describe("Comma-separated search strategies: merged, starred, broad, maintained, all"),
|
|
21
|
-
|
|
21
|
+
preferLanguages: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("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."),
|
|
25
|
+
preferRepos: z
|
|
26
|
+
.array(z.string())
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Soft-boost ranking for candidates in one of these `owner/repo` slugs. Stronger weight than language match (#1244). Not a filter; only reorders."),
|
|
29
|
+
}, async ({ maxResults, strategies, preferLanguages, preferRepos }) => {
|
|
22
30
|
try {
|
|
23
31
|
const parsedStrategies = strategies
|
|
24
32
|
? strategies
|
|
@@ -28,6 +36,8 @@ export function registerTools(server, scout) {
|
|
|
28
36
|
const result = await withTimeout(scout.search({
|
|
29
37
|
maxResults: maxResults ?? 10,
|
|
30
38
|
strategies: parsedStrategies,
|
|
39
|
+
preferLanguages,
|
|
40
|
+
preferRepos,
|
|
31
41
|
}));
|
|
32
42
|
scout.saveResults(result.candidates);
|
|
33
43
|
await scout.checkpoint();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oss-scout/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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": "^0.
|
|
21
|
+
"@oss-scout/core": "^0.10.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^25.5.0",
|