@oss-scout/mcp 0.1.0 → 0.2.1
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.js +8 -8
- package/dist/mcp-server.bundle.cjs +564 -259
- package/dist/resources.d.ts +2 -2
- package/dist/resources.js +21 -15
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +110 -36
- package/package.json +1 -1
package/dist/resources.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { OssScout } from
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { OssScout } from "@oss-scout/core";
|
|
3
3
|
export declare function registerResources(server: McpServer, scout: OssScout): void;
|
package/dist/resources.js
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
export function registerResources(server, scout) {
|
|
2
|
-
server.resource(
|
|
3
|
-
contents: [
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
server.resource("config", "scout://config", { description: "Current oss-scout preferences" }, async () => ({
|
|
3
|
+
contents: [
|
|
4
|
+
{
|
|
5
|
+
uri: "scout://config",
|
|
6
|
+
mimeType: "application/json",
|
|
6
7
|
text: JSON.stringify(scout.getPreferences(), null, 2),
|
|
7
|
-
}
|
|
8
|
+
},
|
|
9
|
+
],
|
|
8
10
|
}));
|
|
9
|
-
server.resource(
|
|
10
|
-
contents: [
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
server.resource("results", "scout://results", { description: "Saved search results from previous runs" }, async () => ({
|
|
12
|
+
contents: [
|
|
13
|
+
{
|
|
14
|
+
uri: "scout://results",
|
|
15
|
+
mimeType: "application/json",
|
|
13
16
|
text: JSON.stringify(scout.getSavedResults(), null, 2),
|
|
14
|
-
}
|
|
17
|
+
},
|
|
18
|
+
],
|
|
15
19
|
}));
|
|
16
|
-
server.resource(
|
|
20
|
+
server.resource("scores", "scout://scores", { description: "Repository score data based on contribution history" }, async () => {
|
|
17
21
|
const state = scout.getState();
|
|
18
22
|
return {
|
|
19
|
-
contents: [
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
contents: [
|
|
24
|
+
{
|
|
25
|
+
uri: "scout://scores",
|
|
26
|
+
mimeType: "application/json",
|
|
22
27
|
text: JSON.stringify(state.repoScores, null, 2),
|
|
23
|
-
}
|
|
28
|
+
},
|
|
29
|
+
],
|
|
24
30
|
};
|
|
25
31
|
});
|
|
26
32
|
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { McpServer } from
|
|
2
|
-
import type { OssScout } from
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { OssScout } from "@oss-scout/core";
|
|
3
3
|
export declare function registerTools(server: McpServer, scout: OssScout): void;
|
package/dist/tools.js
CHANGED
|
@@ -1,43 +1,99 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { SearchStrategySchema, ScoutPreferencesSchema } from
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SearchStrategySchema, ScoutPreferencesSchema } from "@oss-scout/core";
|
|
3
3
|
export function registerTools(server, scout) {
|
|
4
|
-
server.tool(
|
|
5
|
-
maxResults: z
|
|
6
|
-
|
|
4
|
+
server.tool("search", "Search for open source issues matching your preferences", {
|
|
5
|
+
maxResults: z
|
|
6
|
+
.number()
|
|
7
|
+
.optional()
|
|
8
|
+
.describe("Maximum number of results to return (default 10)"),
|
|
9
|
+
strategies: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Comma-separated search strategies: merged, orgs, starred, broad, maintained, all"),
|
|
7
13
|
}, async ({ maxResults, strategies }) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
try {
|
|
15
|
+
const parsedStrategies = strategies
|
|
16
|
+
? strategies
|
|
17
|
+
.split(",")
|
|
18
|
+
.map((s) => SearchStrategySchema.parse(s.trim()))
|
|
19
|
+
: undefined;
|
|
20
|
+
const result = await scout.search({
|
|
21
|
+
maxResults: maxResults ?? 10,
|
|
22
|
+
strategies: parsedStrategies,
|
|
23
|
+
});
|
|
24
|
+
scout.saveResults(result.candidates);
|
|
25
|
+
await scout.checkpoint();
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
34
|
+
isError: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
16
37
|
});
|
|
17
|
-
server.tool(
|
|
18
|
-
issueUrl: z
|
|
38
|
+
server.tool("vet", "Vet a specific GitHub issue for contribution viability", {
|
|
39
|
+
issueUrl: z
|
|
40
|
+
.string()
|
|
41
|
+
.describe("Full GitHub issue URL (e.g. https://github.com/owner/repo/issues/123)"),
|
|
19
42
|
}, async ({ issueUrl }) => {
|
|
20
|
-
|
|
21
|
-
|
|
43
|
+
try {
|
|
44
|
+
const candidate = await scout.vetIssue(issueUrl);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: JSON.stringify(candidate, null, 2) }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
53
|
+
isError: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
22
56
|
});
|
|
23
|
-
server.tool(
|
|
57
|
+
server.tool("config", "Show current oss-scout configuration preferences", async () => {
|
|
24
58
|
const preferences = scout.getPreferences();
|
|
25
|
-
return {
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: JSON.stringify(preferences, null, 2) }],
|
|
61
|
+
};
|
|
26
62
|
});
|
|
27
63
|
const VALID_KEYS = Object.keys(ScoutPreferencesSchema.shape);
|
|
28
64
|
const ARRAY_KEYS = new Set([
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
"languages",
|
|
66
|
+
"labels",
|
|
67
|
+
"preferredOrgs",
|
|
68
|
+
"projectCategories",
|
|
69
|
+
"excludeRepos",
|
|
70
|
+
"excludeOrgs",
|
|
71
|
+
"aiPolicyBlocklist",
|
|
72
|
+
"scope",
|
|
73
|
+
"defaultStrategy",
|
|
74
|
+
]);
|
|
75
|
+
const NUMBER_KEYS = new Set([
|
|
76
|
+
"minStars",
|
|
77
|
+
"maxIssueAgeDays",
|
|
78
|
+
"minRepoScoreThreshold",
|
|
31
79
|
]);
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
80
|
+
const BOOLEAN_KEYS = new Set(["includeDocIssues"]);
|
|
81
|
+
server.tool("config-set", "Update an oss-scout configuration preference", {
|
|
82
|
+
key: z
|
|
83
|
+
.string()
|
|
84
|
+
.describe("Preference key to update (e.g. languages, minStars, excludeRepos)"),
|
|
85
|
+
value: z
|
|
86
|
+
.string()
|
|
87
|
+
.describe("New value — comma-separated for arrays, plain string for scalars"),
|
|
37
88
|
}, async ({ key, value }) => {
|
|
38
89
|
if (!VALID_KEYS.includes(key)) {
|
|
39
90
|
return {
|
|
40
|
-
content: [
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: `Unknown config key: "${key}". Valid keys: ${VALID_KEYS.join(", ")}`,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
41
97
|
isError: true,
|
|
42
98
|
};
|
|
43
99
|
}
|
|
@@ -47,18 +103,26 @@ export function registerTools(server, scout) {
|
|
|
47
103
|
try {
|
|
48
104
|
parsed = JSON.parse(value);
|
|
49
105
|
if (!Array.isArray(parsed)) {
|
|
50
|
-
parsed = value
|
|
106
|
+
parsed = value
|
|
107
|
+
.split(",")
|
|
108
|
+
.map((s) => s.trim())
|
|
109
|
+
.filter(Boolean);
|
|
51
110
|
}
|
|
52
111
|
}
|
|
53
112
|
catch {
|
|
54
|
-
parsed = value
|
|
113
|
+
parsed = value
|
|
114
|
+
.split(",")
|
|
115
|
+
.map((s) => s.trim())
|
|
116
|
+
.filter(Boolean);
|
|
55
117
|
}
|
|
56
118
|
}
|
|
57
119
|
else if (NUMBER_KEYS.has(key)) {
|
|
58
120
|
const num = Number(value);
|
|
59
121
|
if (isNaN(num)) {
|
|
60
122
|
return {
|
|
61
|
-
content: [
|
|
123
|
+
content: [
|
|
124
|
+
{ type: "text", text: `Invalid number for "${key}": "${value}"` },
|
|
125
|
+
],
|
|
62
126
|
isError: true,
|
|
63
127
|
};
|
|
64
128
|
}
|
|
@@ -66,13 +130,18 @@ export function registerTools(server, scout) {
|
|
|
66
130
|
}
|
|
67
131
|
else if (BOOLEAN_KEYS.has(key)) {
|
|
68
132
|
const lower = value.toLowerCase();
|
|
69
|
-
if (lower ===
|
|
133
|
+
if (lower === "true" || lower === "yes")
|
|
70
134
|
parsed = true;
|
|
71
|
-
else if (lower ===
|
|
135
|
+
else if (lower === "false" || lower === "no")
|
|
72
136
|
parsed = false;
|
|
73
137
|
else {
|
|
74
138
|
return {
|
|
75
|
-
content: [
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: "text",
|
|
142
|
+
text: `Invalid boolean for "${key}": "${value}". Use true/false or yes/no.`,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
76
145
|
isError: true,
|
|
77
146
|
};
|
|
78
147
|
}
|
|
@@ -86,14 +155,19 @@ export function registerTools(server, scout) {
|
|
|
86
155
|
// Validate the full preferences object with Zod
|
|
87
156
|
const result = ScoutPreferencesSchema.safeParse(candidate);
|
|
88
157
|
if (!result.success) {
|
|
89
|
-
const issues = result.error.issues
|
|
158
|
+
const issues = result.error.issues
|
|
159
|
+
.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
160
|
+
.join("; ");
|
|
90
161
|
return {
|
|
91
|
-
content: [{ type:
|
|
162
|
+
content: [{ type: "text", text: `Validation error: ${issues}` }],
|
|
92
163
|
isError: true,
|
|
93
164
|
};
|
|
94
165
|
}
|
|
95
166
|
scout.updatePreferences({ [key]: parsed });
|
|
167
|
+
await scout.checkpoint();
|
|
96
168
|
const updated = scout.getPreferences();
|
|
97
|
-
return {
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
|
|
171
|
+
};
|
|
98
172
|
});
|
|
99
173
|
}
|