@sweny-ai/core 0.1.76 → 0.1.78
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/browser.d.ts +11 -5
- package/dist/browser.js +11 -11
- package/dist/claude.d.ts +20 -0
- package/dist/claude.js +139 -9
- package/dist/cli/config.d.ts +22 -0
- package/dist/cli/config.js +56 -9
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +56 -57
- package/dist/cli/marketplace.js +35 -9
- package/dist/cli/publish.d.ts +10 -0
- package/dist/cli/publish.js +22 -14
- package/dist/executor.js +104 -43
- package/dist/loader.d.ts +40 -0
- package/dist/loader.js +73 -0
- package/dist/mcp-catalog.d.ts +47 -0
- package/dist/mcp-catalog.js +304 -0
- package/dist/mcp.d.ts +6 -9
- package/dist/mcp.js +24 -314
- package/dist/requires.d.ts +7 -0
- package/dist/requires.js +34 -0
- package/dist/retry.d.ts +23 -0
- package/dist/retry.js +72 -0
- package/dist/schema.d.ts +667 -80
- package/dist/schema.js +144 -5
- package/dist/skills/custom-loader.d.ts +40 -0
- package/dist/skills/custom-loader.js +107 -32
- package/dist/skills/index.d.ts +13 -1
- package/dist/skills/index.js +12 -3
- package/dist/studio.js +4 -1
- package/dist/templates.d.ts +29 -8
- package/dist/templates.js +30 -20
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +7 -0
- package/dist/types.d.ts +76 -0
- package/dist/verify.d.ts +1 -0
- package/dist/verify.js +43 -5
- package/package.json +8 -4
- package/dist/__tests__/cascade.test.d.ts +0 -11
- package/dist/__tests__/cascade.test.js +0 -449
- package/dist/__tests__/claude.test.d.ts +0 -1
- package/dist/__tests__/claude.test.js +0 -427
- package/dist/__tests__/custom-loader.test.d.ts +0 -1
- package/dist/__tests__/custom-loader.test.js +0 -116
- package/dist/__tests__/executor.test.d.ts +0 -1
- package/dist/__tests__/executor.test.js +0 -736
- package/dist/__tests__/integration/datadog.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/datadog.integration.test.js +0 -23
- package/dist/__tests__/integration/e2e-workflow.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/e2e-workflow.integration.test.js +0 -75
- package/dist/__tests__/integration/github.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/github.integration.test.js +0 -37
- package/dist/__tests__/integration/harness.d.ts +0 -24
- package/dist/__tests__/integration/harness.js +0 -34
- package/dist/__tests__/integration/linear.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/linear.integration.test.js +0 -15
- package/dist/__tests__/integration/sentry.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/sentry.integration.test.js +0 -20
- package/dist/__tests__/integration/slack.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/slack.integration.test.js +0 -22
- package/dist/__tests__/integration/sources.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/sources.integration.test.js +0 -123
- package/dist/__tests__/publish.test.d.ts +0 -1
- package/dist/__tests__/publish.test.js +0 -180
- package/dist/__tests__/schema.test.d.ts +0 -1
- package/dist/__tests__/schema.test.js +0 -526
- package/dist/__tests__/skill-config-integration.test.d.ts +0 -1
- package/dist/__tests__/skill-config-integration.test.js +0 -204
- package/dist/__tests__/skills-index.test.d.ts +0 -1
- package/dist/__tests__/skills-index.test.js +0 -119
- package/dist/__tests__/skills.test.d.ts +0 -1
- package/dist/__tests__/skills.test.js +0 -565
- package/dist/__tests__/spec-conformance.test.d.ts +0 -18
- package/dist/__tests__/spec-conformance.test.js +0 -1074
- package/dist/__tests__/studio.test.d.ts +0 -1
- package/dist/__tests__/studio.test.js +0 -403
- package/dist/__tests__/templates.test.d.ts +0 -1
- package/dist/__tests__/templates.test.js +0 -49
- package/dist/__tests__/testing.test.d.ts +0 -1
- package/dist/__tests__/testing.test.js +0 -224
- package/dist/__tests__/verify.test.d.ts +0 -1
- package/dist/__tests__/verify.test.js +0 -517
- package/dist/__tests__/version-consistency.test.d.ts +0 -1
- package/dist/__tests__/version-consistency.test.js +0 -312
- package/dist/__tests__/workflow-builder.test.d.ts +0 -1
- package/dist/__tests__/workflow-builder.test.js +0 -110
- package/dist/__tests__/workflow-yaml.test.d.ts +0 -1
- package/dist/__tests__/workflow-yaml.test.js +0 -201
- package/dist/cli/__tests__/diagram.test.d.ts +0 -1
- package/dist/cli/__tests__/diagram.test.js +0 -225
- package/dist/cli/__tests__/report-cloud.test.d.ts +0 -1
- package/dist/cli/__tests__/report-cloud.test.js +0 -165
- package/dist/cli/__tests__/upgrade.test.d.ts +0 -1
- package/dist/cli/__tests__/upgrade.test.js +0 -317
- package/dist/cli/__tests__/version-check.test.d.ts +0 -1
- package/dist/cli/__tests__/version-check.test.js +0 -209
- package/dist/cli/config.test.d.ts +0 -1
- package/dist/cli/config.test.js +0 -200
- package/dist/cli/credentials.test.d.ts +0 -1
- package/dist/cli/credentials.test.js +0 -172
- package/dist/cli/e2e.test.d.ts +0 -1
- package/dist/cli/e2e.test.js +0 -690
- package/dist/cli/marketplace.test.d.ts +0 -1
- package/dist/cli/marketplace.test.js +0 -355
- package/dist/cli/new.test.d.ts +0 -1
- package/dist/cli/new.test.js +0 -1043
- package/dist/cli/output.test.d.ts +0 -1
- package/dist/cli/output.test.js +0 -180
- package/dist/cli/publish.test.d.ts +0 -1
- package/dist/cli/publish.test.js +0 -610
- package/dist/cli/renderer.test.d.ts +0 -1
- package/dist/cli/renderer.test.js +0 -302
- package/dist/executor.test.d.ts +0 -1
- package/dist/executor.test.js +0 -603
- package/dist/mcp.test.d.ts +0 -1
- package/dist/mcp.test.js +0 -735
- package/dist/mermaid.test.d.ts +0 -1
- package/dist/mermaid.test.js +0 -256
- package/dist/sources.test.d.ts +0 -1
- package/dist/sources.test.js +0 -265
- package/dist/sources.validation.test.d.ts +0 -12
- package/dist/sources.validation.test.js +0 -380
- package/dist/workflow-builder.test.d.ts +0 -1
- package/dist/workflow-builder.test.js +0 -117
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Provider Catalog — single source of truth for provider/MCP wiring.
|
|
3
|
+
*
|
|
4
|
+
* Before this catalog existed, `buildSkillMcpServers` (skill-driven) and
|
|
5
|
+
* `buildAutoMcpServers` (flag-driven, legacy triage/implement) each encoded
|
|
6
|
+
* the same transport/auth/env for every provider. Drift was inevitable.
|
|
7
|
+
*
|
|
8
|
+
* Each entry declares:
|
|
9
|
+
* - which trigger paths (skill id, provider flag, workspace tool) wire it
|
|
10
|
+
* - how to build the McpServerConfig from credentials
|
|
11
|
+
* - whether the server uses stdio or http transport
|
|
12
|
+
* - if stdio: why the `npx -y` policy exception is acceptable (Fix #18)
|
|
13
|
+
*
|
|
14
|
+
* Adding a provider is a one-place edit. A module-load assertion and a
|
|
15
|
+
* test enforce that every stdio entry declares its exception reason.
|
|
16
|
+
*/
|
|
17
|
+
// ── Catalog entries ─────────────────────────────────────────────────
|
|
18
|
+
const github = {
|
|
19
|
+
id: "github",
|
|
20
|
+
triggers: {
|
|
21
|
+
skill: ["github"],
|
|
22
|
+
sourceControl: ["github"],
|
|
23
|
+
issueTracker: ["github-issues"],
|
|
24
|
+
},
|
|
25
|
+
transport: "stdio",
|
|
26
|
+
npxExceptionReason: "Official @modelcontextprotocol/server-github; no public HTTP MCP endpoint.",
|
|
27
|
+
wire: (creds) => {
|
|
28
|
+
if (!creds.GITHUB_TOKEN)
|
|
29
|
+
return undefined;
|
|
30
|
+
return {
|
|
31
|
+
type: "stdio",
|
|
32
|
+
command: "npx",
|
|
33
|
+
args: ["-y", "@modelcontextprotocol/server-github@latest"],
|
|
34
|
+
env: { GITHUB_PERSONAL_ACCESS_TOKEN: creds.GITHUB_TOKEN },
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const gitlab = {
|
|
39
|
+
id: "gitlab",
|
|
40
|
+
triggers: {
|
|
41
|
+
skill: ["gitlab"],
|
|
42
|
+
sourceControl: ["gitlab"],
|
|
43
|
+
},
|
|
44
|
+
transport: "stdio",
|
|
45
|
+
npxExceptionReason: "Official @modelcontextprotocol/server-gitlab; no public HTTP MCP endpoint.",
|
|
46
|
+
wire: (creds) => {
|
|
47
|
+
if (!creds.GITLAB_TOKEN)
|
|
48
|
+
return undefined;
|
|
49
|
+
const env = { GITLAB_PERSONAL_ACCESS_TOKEN: creds.GITLAB_TOKEN };
|
|
50
|
+
const baseUrl = creds.GITLAB_URL || "https://gitlab.com";
|
|
51
|
+
if (baseUrl !== "https://gitlab.com")
|
|
52
|
+
env.GITLAB_API_URL = `${baseUrl}/api/v4`;
|
|
53
|
+
return {
|
|
54
|
+
type: "stdio",
|
|
55
|
+
command: "npx",
|
|
56
|
+
args: ["-y", "@modelcontextprotocol/server-gitlab@latest"],
|
|
57
|
+
env,
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const linear = {
|
|
62
|
+
id: "linear",
|
|
63
|
+
triggers: {
|
|
64
|
+
skill: ["linear"],
|
|
65
|
+
issueTracker: ["linear"],
|
|
66
|
+
},
|
|
67
|
+
transport: "http",
|
|
68
|
+
npxExceptionReason: null,
|
|
69
|
+
wire: (creds) => {
|
|
70
|
+
if (!creds.LINEAR_API_KEY)
|
|
71
|
+
return undefined;
|
|
72
|
+
return {
|
|
73
|
+
type: "http",
|
|
74
|
+
url: "https://mcp.linear.app/mcp",
|
|
75
|
+
headers: { Authorization: `Bearer ${creds.LINEAR_API_KEY}` },
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const jira = {
|
|
80
|
+
id: "jira",
|
|
81
|
+
triggers: {
|
|
82
|
+
skill: ["jira"],
|
|
83
|
+
issueTracker: ["jira"],
|
|
84
|
+
},
|
|
85
|
+
transport: "stdio",
|
|
86
|
+
npxExceptionReason: "Atlassian has no first-party MCP server; @sooperset/mcp-atlassian is the de-facto community standard. Revisit if Atlassian ships one.",
|
|
87
|
+
wire: (creds) => {
|
|
88
|
+
if (!creds.JIRA_URL || !creds.JIRA_EMAIL || !creds.JIRA_API_TOKEN)
|
|
89
|
+
return undefined;
|
|
90
|
+
return {
|
|
91
|
+
type: "stdio",
|
|
92
|
+
command: "npx",
|
|
93
|
+
args: ["-y", "@sooperset/mcp-atlassian@latest"],
|
|
94
|
+
env: {
|
|
95
|
+
JIRA_URL: creds.JIRA_URL,
|
|
96
|
+
JIRA_EMAIL: creds.JIRA_EMAIL,
|
|
97
|
+
JIRA_API_TOKEN: creds.JIRA_API_TOKEN,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
const datadog = {
|
|
103
|
+
id: "datadog",
|
|
104
|
+
triggers: {
|
|
105
|
+
skill: ["datadog"],
|
|
106
|
+
observability: ["datadog"],
|
|
107
|
+
},
|
|
108
|
+
transport: "http",
|
|
109
|
+
npxExceptionReason: null,
|
|
110
|
+
wire: (creds) => {
|
|
111
|
+
if (!creds.DD_API_KEY || !creds.DD_APP_KEY)
|
|
112
|
+
return undefined;
|
|
113
|
+
return {
|
|
114
|
+
type: "http",
|
|
115
|
+
url: "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
|
|
116
|
+
headers: { DD_API_KEY: creds.DD_API_KEY, DD_APPLICATION_KEY: creds.DD_APP_KEY },
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const sentry = {
|
|
121
|
+
id: "sentry",
|
|
122
|
+
triggers: {
|
|
123
|
+
skill: ["sentry"],
|
|
124
|
+
observability: ["sentry"],
|
|
125
|
+
},
|
|
126
|
+
transport: "stdio",
|
|
127
|
+
npxExceptionReason: "Official @sentry/mcp-server; no public HTTP MCP endpoint.",
|
|
128
|
+
wire: (creds) => {
|
|
129
|
+
if (!creds.SENTRY_AUTH_TOKEN)
|
|
130
|
+
return undefined;
|
|
131
|
+
const env = { SENTRY_ACCESS_TOKEN: creds.SENTRY_AUTH_TOKEN };
|
|
132
|
+
const sentryUrl = creds.SENTRY_URL;
|
|
133
|
+
if (sentryUrl && sentryUrl !== "https://sentry.io") {
|
|
134
|
+
try {
|
|
135
|
+
env.SENTRY_HOST = new URL(sentryUrl).hostname;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// malformed URL — leave SENTRY_HOST unset, server defaults to sentry.io
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
type: "stdio",
|
|
143
|
+
command: "npx",
|
|
144
|
+
args: ["-y", "@sentry/mcp-server@latest"],
|
|
145
|
+
env,
|
|
146
|
+
};
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const newrelic = {
|
|
150
|
+
id: "newrelic",
|
|
151
|
+
triggers: {
|
|
152
|
+
skill: ["newrelic"],
|
|
153
|
+
observability: ["newrelic"],
|
|
154
|
+
},
|
|
155
|
+
transport: "http",
|
|
156
|
+
npxExceptionReason: null,
|
|
157
|
+
wire: (creds) => {
|
|
158
|
+
if (!creds.NEW_RELIC_API_KEY)
|
|
159
|
+
return undefined;
|
|
160
|
+
const region = creds.NEW_RELIC_REGION;
|
|
161
|
+
const url = region === "eu" ? "https://mcp.eu.newrelic.com/mcp/" : "https://mcp.newrelic.com/mcp/";
|
|
162
|
+
return {
|
|
163
|
+
type: "http",
|
|
164
|
+
url,
|
|
165
|
+
headers: { "Api-Key": creds.NEW_RELIC_API_KEY },
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const betterstack = {
|
|
170
|
+
id: "betterstack",
|
|
171
|
+
triggers: {
|
|
172
|
+
skill: ["betterstack"],
|
|
173
|
+
observability: ["betterstack"],
|
|
174
|
+
},
|
|
175
|
+
transport: "http",
|
|
176
|
+
npxExceptionReason: null,
|
|
177
|
+
wire: (creds) => {
|
|
178
|
+
const token = creds.BETTERSTACK_API_TOKEN || creds.BETTERSTACK_TELEMETRY_TOKEN || creds.BETTERSTACK_UPTIME_TOKEN;
|
|
179
|
+
if (!token)
|
|
180
|
+
return undefined;
|
|
181
|
+
return {
|
|
182
|
+
type: "http",
|
|
183
|
+
url: "https://mcp.betterstack.com",
|
|
184
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
const slack = {
|
|
189
|
+
id: "slack",
|
|
190
|
+
triggers: {
|
|
191
|
+
skill: ["slack"],
|
|
192
|
+
workspaceTool: ["slack"],
|
|
193
|
+
},
|
|
194
|
+
transport: "stdio",
|
|
195
|
+
npxExceptionReason: "Official @modelcontextprotocol/server-slack; no public HTTP MCP endpoint.",
|
|
196
|
+
wire: (creds) => {
|
|
197
|
+
if (!creds.SLACK_BOT_TOKEN)
|
|
198
|
+
return undefined;
|
|
199
|
+
const env = { SLACK_BOT_TOKEN: creds.SLACK_BOT_TOKEN };
|
|
200
|
+
if (creds.SLACK_TEAM_ID)
|
|
201
|
+
env.SLACK_TEAM_ID = creds.SLACK_TEAM_ID;
|
|
202
|
+
return {
|
|
203
|
+
type: "stdio",
|
|
204
|
+
command: "npx",
|
|
205
|
+
args: ["-y", "@modelcontextprotocol/server-slack@latest"],
|
|
206
|
+
env,
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
const notion = {
|
|
211
|
+
id: "notion",
|
|
212
|
+
triggers: {
|
|
213
|
+
skill: ["notion"],
|
|
214
|
+
workspaceTool: ["notion"],
|
|
215
|
+
},
|
|
216
|
+
transport: "stdio",
|
|
217
|
+
npxExceptionReason: "Official @notionhq/notion-mcp-server; no public HTTP MCP endpoint.",
|
|
218
|
+
wire: (creds) => {
|
|
219
|
+
const token = creds.NOTION_TOKEN || creds.NOTION_API_KEY;
|
|
220
|
+
if (!token)
|
|
221
|
+
return undefined;
|
|
222
|
+
return {
|
|
223
|
+
type: "stdio",
|
|
224
|
+
command: "npx",
|
|
225
|
+
args: ["-y", "@notionhq/notion-mcp-server@latest"],
|
|
226
|
+
env: { NOTION_TOKEN: token },
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
const pagerduty = {
|
|
231
|
+
id: "pagerduty",
|
|
232
|
+
triggers: {
|
|
233
|
+
skill: ["pagerduty"],
|
|
234
|
+
workspaceTool: ["pagerduty"],
|
|
235
|
+
},
|
|
236
|
+
transport: "http",
|
|
237
|
+
npxExceptionReason: null,
|
|
238
|
+
wire: (creds) => {
|
|
239
|
+
if (!creds.PAGERDUTY_API_TOKEN)
|
|
240
|
+
return undefined;
|
|
241
|
+
return {
|
|
242
|
+
type: "http",
|
|
243
|
+
url: "https://mcp.pagerduty.com/mcp",
|
|
244
|
+
headers: { Authorization: `Token token=${creds.PAGERDUTY_API_TOKEN}` },
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
const monday = {
|
|
249
|
+
id: "monday",
|
|
250
|
+
triggers: {
|
|
251
|
+
skill: ["monday"],
|
|
252
|
+
workspaceTool: ["monday"],
|
|
253
|
+
},
|
|
254
|
+
transport: "stdio",
|
|
255
|
+
npxExceptionReason: "Official @mondaydotcomorg/monday-api-mcp; no public HTTP MCP endpoint.",
|
|
256
|
+
wire: (creds) => {
|
|
257
|
+
if (!creds.MONDAY_TOKEN)
|
|
258
|
+
return undefined;
|
|
259
|
+
return {
|
|
260
|
+
type: "stdio",
|
|
261
|
+
command: "npx",
|
|
262
|
+
args: ["-y", "@mondaydotcomorg/monday-api-mcp@latest"],
|
|
263
|
+
env: { MONDAY_TOKEN: creds.MONDAY_TOKEN },
|
|
264
|
+
};
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
// asana was removed in Fix #15 — absent from SUPPORTED_WORKSPACE_TOOLS for
|
|
268
|
+
// some time, and the asana-mcp package is community-maintained without a
|
|
269
|
+
// clear first-party alternative. Add back in a dedicated catalog entry if
|
|
270
|
+
// there's demand and a policy-compliant server to wire.
|
|
271
|
+
// ── Assembled catalog ────────────────────────────────────────────────
|
|
272
|
+
export const MCP_CATALOG = [
|
|
273
|
+
github,
|
|
274
|
+
gitlab,
|
|
275
|
+
linear,
|
|
276
|
+
jira,
|
|
277
|
+
datadog,
|
|
278
|
+
sentry,
|
|
279
|
+
newrelic,
|
|
280
|
+
betterstack,
|
|
281
|
+
slack,
|
|
282
|
+
notion,
|
|
283
|
+
pagerduty,
|
|
284
|
+
monday,
|
|
285
|
+
];
|
|
286
|
+
// ── Policy enforcement ──────────────────────────────────────────────
|
|
287
|
+
/**
|
|
288
|
+
* Assert the `npx -y` policy (Fix #18). Thrown at module load and also
|
|
289
|
+
* asserted by the test suite, so a stdio entry missing `npxExceptionReason`
|
|
290
|
+
* never reaches shipping.
|
|
291
|
+
*/
|
|
292
|
+
function assertNpxPolicyCompliant(entries) {
|
|
293
|
+
for (const entry of entries) {
|
|
294
|
+
if (entry.transport === "stdio" && entry.npxExceptionReason === null) {
|
|
295
|
+
throw new Error(`MCP catalog entry "${entry.id}" uses stdio transport but declares no npxExceptionReason. ` +
|
|
296
|
+
`Stdio entries must document why the npx -y exception is acceptable. See ARCHITECTURE.md.`);
|
|
297
|
+
}
|
|
298
|
+
if (entry.transport === "http" && entry.npxExceptionReason !== null) {
|
|
299
|
+
throw new Error(`MCP catalog entry "${entry.id}" uses http transport but declares an npxExceptionReason. ` +
|
|
300
|
+
`Only stdio entries need an exception reason; set it to null for http entries.`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
assertNpxPolicyCompliant(MCP_CATALOG);
|
package/dist/mcp.d.ts
CHANGED
|
@@ -12,16 +12,13 @@ export interface SkillMcpOptions {
|
|
|
12
12
|
/**
|
|
13
13
|
* Build MCP server configs for the skills a workflow references.
|
|
14
14
|
*
|
|
15
|
-
* For each
|
|
16
|
-
*
|
|
15
|
+
* For each entry in MCP_CATALOG whose skill triggers intersect
|
|
16
|
+
* `referencedSkills`, wire its MCP if credentials are present. Skills with
|
|
17
|
+
* no MCP variant (e.g. `notification`, `supabase`) are silently skipped —
|
|
18
|
+
* their in-process tools are wired separately by the executor. Unknown
|
|
19
|
+
* skill IDs pass through; the engine's hard-fail validation handles them.
|
|
17
20
|
*
|
|
18
|
-
*
|
|
19
|
-
* skipped — their in-process tools are wired separately by the executor.
|
|
20
|
-
*
|
|
21
|
-
* Unknown skill IDs (not built-in, not in this MCP catalog) are silently
|
|
22
|
-
* skipped here; the engine's hard-fail validation handles them upstream.
|
|
23
|
-
*
|
|
24
|
-
* User-supplied servers always win on key conflict.
|
|
21
|
+
* Inline skill-declared servers and user-supplied servers layer on top.
|
|
25
22
|
*/
|
|
26
23
|
export declare function buildSkillMcpServers(opts: SkillMcpOptions): Record<string, McpServerConfig>;
|
|
27
24
|
/**
|
package/dist/mcp.js
CHANGED
|
@@ -1,159 +1,26 @@
|
|
|
1
|
+
import { MCP_CATALOG } from "./mcp-catalog.js";
|
|
1
2
|
/**
|
|
2
3
|
* Build MCP server configs for the skills a workflow references.
|
|
3
4
|
*
|
|
4
|
-
* For each
|
|
5
|
-
*
|
|
5
|
+
* For each entry in MCP_CATALOG whose skill triggers intersect
|
|
6
|
+
* `referencedSkills`, wire its MCP if credentials are present. Skills with
|
|
7
|
+
* no MCP variant (e.g. `notification`, `supabase`) are silently skipped —
|
|
8
|
+
* their in-process tools are wired separately by the executor. Unknown
|
|
9
|
+
* skill IDs pass through; the engine's hard-fail validation handles them.
|
|
6
10
|
*
|
|
7
|
-
*
|
|
8
|
-
* skipped — their in-process tools are wired separately by the executor.
|
|
9
|
-
*
|
|
10
|
-
* Unknown skill IDs (not built-in, not in this MCP catalog) are silently
|
|
11
|
-
* skipped here; the engine's hard-fail validation handles them upstream.
|
|
12
|
-
*
|
|
13
|
-
* User-supplied servers always win on key conflict.
|
|
11
|
+
* Inline skill-declared servers and user-supplied servers layer on top.
|
|
14
12
|
*/
|
|
15
13
|
export function buildSkillMcpServers(opts) {
|
|
16
14
|
const auto = {};
|
|
17
15
|
const refs = opts.referencedSkills;
|
|
18
16
|
const creds = opts.credentials;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
// GitLab MCP.
|
|
29
|
-
if (refs.has("gitlab") && creds.GITLAB_TOKEN) {
|
|
30
|
-
const env = { GITLAB_PERSONAL_ACCESS_TOKEN: creds.GITLAB_TOKEN };
|
|
31
|
-
const baseUrl = creds.GITLAB_URL || "https://gitlab.com";
|
|
32
|
-
if (baseUrl !== "https://gitlab.com")
|
|
33
|
-
env.GITLAB_API_URL = `${baseUrl}/api/v4`;
|
|
34
|
-
auto["gitlab"] = {
|
|
35
|
-
type: "stdio",
|
|
36
|
-
command: "npx",
|
|
37
|
-
args: ["-y", "@modelcontextprotocol/server-gitlab@latest"],
|
|
38
|
-
env,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// Linear MCP — official remote HTTP endpoint.
|
|
42
|
-
if (refs.has("linear") && creds.LINEAR_API_KEY) {
|
|
43
|
-
auto["linear"] = {
|
|
44
|
-
type: "http",
|
|
45
|
-
url: "https://mcp.linear.app/mcp",
|
|
46
|
-
headers: { Authorization: `Bearer ${creds.LINEAR_API_KEY}` },
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
// Jira / Confluence — needs all 3 creds.
|
|
50
|
-
if (refs.has("jira") && creds.JIRA_URL && creds.JIRA_EMAIL && creds.JIRA_API_TOKEN) {
|
|
51
|
-
auto["jira"] = {
|
|
52
|
-
type: "stdio",
|
|
53
|
-
command: "npx",
|
|
54
|
-
args: ["-y", "@sooperset/mcp-atlassian@latest"],
|
|
55
|
-
env: {
|
|
56
|
-
JIRA_URL: creds.JIRA_URL,
|
|
57
|
-
JIRA_EMAIL: creds.JIRA_EMAIL,
|
|
58
|
-
JIRA_API_TOKEN: creds.JIRA_API_TOKEN,
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
// Datadog MCP.
|
|
63
|
-
if (refs.has("datadog") && creds.DD_API_KEY && creds.DD_APP_KEY) {
|
|
64
|
-
auto["datadog"] = {
|
|
65
|
-
type: "http",
|
|
66
|
-
url: "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
|
|
67
|
-
headers: { DD_API_KEY: creds.DD_API_KEY, DD_APPLICATION_KEY: creds.DD_APP_KEY },
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
// Sentry MCP — server reads SENTRY_ACCESS_TOKEN, not SENTRY_AUTH_TOKEN.
|
|
71
|
-
if (refs.has("sentry") && creds.SENTRY_AUTH_TOKEN) {
|
|
72
|
-
const env = { SENTRY_ACCESS_TOKEN: creds.SENTRY_AUTH_TOKEN };
|
|
73
|
-
const sentryUrl = creds.SENTRY_URL;
|
|
74
|
-
if (sentryUrl && sentryUrl !== "https://sentry.io") {
|
|
75
|
-
try {
|
|
76
|
-
env.SENTRY_HOST = new URL(sentryUrl).hostname;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
// malformed URL — leave SENTRY_HOST unset
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
auto["sentry"] = {
|
|
83
|
-
type: "stdio",
|
|
84
|
-
command: "npx",
|
|
85
|
-
args: ["-y", "@sentry/mcp-server@latest"],
|
|
86
|
-
env,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
// New Relic MCP — region-aware HTTP endpoint, header is "Api-Key".
|
|
90
|
-
if (refs.has("newrelic") && creds.NEW_RELIC_API_KEY) {
|
|
91
|
-
const region = creds.NEW_RELIC_REGION;
|
|
92
|
-
const url = region === "eu" ? "https://mcp.eu.newrelic.com/mcp/" : "https://mcp.newrelic.com/mcp/";
|
|
93
|
-
auto["newrelic"] = {
|
|
94
|
-
type: "http",
|
|
95
|
-
url,
|
|
96
|
-
headers: { "Api-Key": creds.NEW_RELIC_API_KEY },
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
// BetterStack MCP — accept any of the legacy/telemetry/uptime tokens.
|
|
100
|
-
const bsToken = creds.BETTERSTACK_API_TOKEN || creds.BETTERSTACK_TELEMETRY_TOKEN || creds.BETTERSTACK_UPTIME_TOKEN;
|
|
101
|
-
if (refs.has("betterstack") && bsToken) {
|
|
102
|
-
auto["betterstack"] = {
|
|
103
|
-
type: "http",
|
|
104
|
-
url: "https://mcp.betterstack.com",
|
|
105
|
-
headers: { Authorization: `Bearer ${bsToken}` },
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
// Slack MCP — wired when workflow uses `slack` skill and bot token is set.
|
|
109
|
-
if (refs.has("slack") && creds.SLACK_BOT_TOKEN) {
|
|
110
|
-
const env = { SLACK_BOT_TOKEN: creds.SLACK_BOT_TOKEN };
|
|
111
|
-
if (creds.SLACK_TEAM_ID)
|
|
112
|
-
env.SLACK_TEAM_ID = creds.SLACK_TEAM_ID;
|
|
113
|
-
auto["slack"] = {
|
|
114
|
-
type: "stdio",
|
|
115
|
-
command: "npx",
|
|
116
|
-
args: ["-y", "@modelcontextprotocol/server-slack@latest"],
|
|
117
|
-
env,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
// Notion MCP — accept either NOTION_TOKEN or NOTION_API_KEY.
|
|
121
|
-
if (refs.has("notion")) {
|
|
122
|
-
const token = creds.NOTION_TOKEN || creds.NOTION_API_KEY;
|
|
123
|
-
if (token) {
|
|
124
|
-
auto["notion"] = {
|
|
125
|
-
type: "stdio",
|
|
126
|
-
command: "npx",
|
|
127
|
-
args: ["-y", "@notionhq/notion-mcp-server@latest"],
|
|
128
|
-
env: { NOTION_TOKEN: token },
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// PagerDuty MCP — auth scheme is `Token token=<key>`.
|
|
133
|
-
if (refs.has("pagerduty") && creds.PAGERDUTY_API_TOKEN) {
|
|
134
|
-
auto["pagerduty"] = {
|
|
135
|
-
type: "http",
|
|
136
|
-
url: "https://mcp.pagerduty.com/mcp",
|
|
137
|
-
headers: { Authorization: `Token token=${creds.PAGERDUTY_API_TOKEN}` },
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
// Monday.com MCP.
|
|
141
|
-
if (refs.has("monday") && creds.MONDAY_TOKEN) {
|
|
142
|
-
auto["monday"] = {
|
|
143
|
-
type: "stdio",
|
|
144
|
-
command: "npx",
|
|
145
|
-
args: ["-y", "@mondaydotcomorg/monday-api-mcp@latest"],
|
|
146
|
-
env: { MONDAY_TOKEN: creds.MONDAY_TOKEN },
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
// Asana MCP.
|
|
150
|
-
if (refs.has("asana") && creds.ASANA_ACCESS_TOKEN) {
|
|
151
|
-
auto["asana"] = {
|
|
152
|
-
type: "stdio",
|
|
153
|
-
command: "npx",
|
|
154
|
-
args: ["-y", "asana-mcp@latest"],
|
|
155
|
-
env: { ASANA_ACCESS_TOKEN: creds.ASANA_ACCESS_TOKEN },
|
|
156
|
-
};
|
|
17
|
+
for (const entry of MCP_CATALOG) {
|
|
18
|
+
const skillIds = entry.triggers.skill ?? [];
|
|
19
|
+
if (!skillIds.some((id) => refs.has(id)))
|
|
20
|
+
continue;
|
|
21
|
+
const wired = entry.wire(creds);
|
|
22
|
+
if (wired)
|
|
23
|
+
auto[entry.id] = wired;
|
|
157
24
|
}
|
|
158
25
|
// Skill-declared MCP servers — only include for referenced skills.
|
|
159
26
|
if (opts.skillMcpServers) {
|
|
@@ -178,175 +45,18 @@ export function buildSkillMcpServers(opts) {
|
|
|
178
45
|
export function buildAutoMcpServers(config) {
|
|
179
46
|
const auto = {};
|
|
180
47
|
const creds = config.credentials;
|
|
181
|
-
// ── Category A: Provider-config triggered ──────────────────────
|
|
182
|
-
// GitHub MCP — inject when using GitHub source control OR GitHub Issues tracker.
|
|
183
|
-
// @modelcontextprotocol/server-github requires GITHUB_PERSONAL_ACCESS_TOKEN.
|
|
184
|
-
const githubToken = creds.GITHUB_TOKEN;
|
|
185
|
-
if ((config.sourceControlProvider === "github" || config.issueTrackerProvider === "github-issues") && githubToken) {
|
|
186
|
-
auto["github"] = {
|
|
187
|
-
type: "stdio",
|
|
188
|
-
command: "npx",
|
|
189
|
-
args: ["-y", "@modelcontextprotocol/server-github@latest"],
|
|
190
|
-
env: { GITHUB_PERSONAL_ACCESS_TOKEN: githubToken },
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
// GitLab MCP — inject when source control provider is gitlab.
|
|
194
|
-
const gitlabToken = creds.GITLAB_TOKEN;
|
|
195
|
-
if (config.sourceControlProvider === "gitlab" && gitlabToken) {
|
|
196
|
-
const gitlabEnv = { GITLAB_PERSONAL_ACCESS_TOKEN: gitlabToken };
|
|
197
|
-
const baseUrl = creds.GITLAB_URL || "https://gitlab.com";
|
|
198
|
-
if (baseUrl !== "https://gitlab.com") {
|
|
199
|
-
gitlabEnv.GITLAB_API_URL = `${baseUrl}/api/v4`;
|
|
200
|
-
}
|
|
201
|
-
auto["gitlab"] = {
|
|
202
|
-
type: "stdio",
|
|
203
|
-
command: "npx",
|
|
204
|
-
args: ["-y", "@modelcontextprotocol/server-gitlab@latest"],
|
|
205
|
-
env: gitlabEnv,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
// Linear MCP — official HTTP remote MCP endpoint.
|
|
209
|
-
const linearApiKey = creds.LINEAR_API_KEY;
|
|
210
|
-
if (config.issueTrackerProvider === "linear" && linearApiKey) {
|
|
211
|
-
auto["linear"] = {
|
|
212
|
-
type: "http",
|
|
213
|
-
url: "https://mcp.linear.app/mcp",
|
|
214
|
-
headers: { Authorization: `Bearer ${linearApiKey}` },
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
// Jira / Confluence (Atlassian) MCP — needs all 3 credentials.
|
|
218
|
-
const jiraUrl = creds.JIRA_URL;
|
|
219
|
-
const jiraEmail = creds.JIRA_EMAIL;
|
|
220
|
-
const jiraApiToken = creds.JIRA_API_TOKEN;
|
|
221
|
-
if (config.issueTrackerProvider === "jira" && jiraUrl && jiraEmail && jiraApiToken) {
|
|
222
|
-
auto["jira"] = {
|
|
223
|
-
type: "stdio",
|
|
224
|
-
command: "npx",
|
|
225
|
-
args: ["-y", "@sooperset/mcp-atlassian@latest"],
|
|
226
|
-
env: {
|
|
227
|
-
JIRA_URL: jiraUrl,
|
|
228
|
-
JIRA_EMAIL: jiraEmail,
|
|
229
|
-
JIRA_API_TOKEN: jiraApiToken,
|
|
230
|
-
},
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
// ── Observability MCP servers ──────────────────────────────────
|
|
234
|
-
// Inject MCP for every configured observability provider whose credentials
|
|
235
|
-
// are present. Multiple providers are supported (e.g. "loki,sentry").
|
|
236
48
|
const obsProviders = new Set(config.observabilityProviders ?? []);
|
|
237
|
-
// Datadog MCP — HTTP transport.
|
|
238
|
-
const ddApiKey = creds.DD_API_KEY;
|
|
239
|
-
const ddAppKey = creds.DD_APP_KEY;
|
|
240
|
-
if (obsProviders.has("datadog") && ddApiKey && ddAppKey) {
|
|
241
|
-
auto["datadog"] = {
|
|
242
|
-
type: "http",
|
|
243
|
-
url: "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
|
|
244
|
-
headers: { DD_API_KEY: ddApiKey, DD_APPLICATION_KEY: ddAppKey },
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
// Sentry MCP — @sentry/mcp-server reads SENTRY_ACCESS_TOKEN (not SENTRY_AUTH_TOKEN).
|
|
248
|
-
const sentryAuthToken = creds.SENTRY_AUTH_TOKEN;
|
|
249
|
-
if (obsProviders.has("sentry") && sentryAuthToken) {
|
|
250
|
-
const sentryEnv = { SENTRY_ACCESS_TOKEN: sentryAuthToken };
|
|
251
|
-
const sentryUrl = creds.SENTRY_URL;
|
|
252
|
-
if (sentryUrl && sentryUrl !== "https://sentry.io") {
|
|
253
|
-
try {
|
|
254
|
-
sentryEnv.SENTRY_HOST = new URL(sentryUrl).hostname;
|
|
255
|
-
}
|
|
256
|
-
catch {
|
|
257
|
-
// malformed URL — leave SENTRY_HOST unset, server defaults to sentry.io
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
auto["sentry"] = {
|
|
261
|
-
type: "stdio",
|
|
262
|
-
command: "npx",
|
|
263
|
-
args: ["-y", "@sentry/mcp-server@latest"],
|
|
264
|
-
env: sentryEnv,
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
// New Relic MCP — HTTP transport; region-aware endpoint.
|
|
268
|
-
const nrApiKey = creds.NEW_RELIC_API_KEY;
|
|
269
|
-
if (obsProviders.has("newrelic") && nrApiKey) {
|
|
270
|
-
const nrRegion = creds.NEW_RELIC_REGION;
|
|
271
|
-
const nrEndpoint = nrRegion === "eu" ? "https://mcp.eu.newrelic.com/mcp/" : "https://mcp.newrelic.com/mcp/";
|
|
272
|
-
auto["newrelic"] = {
|
|
273
|
-
type: "http",
|
|
274
|
-
url: nrEndpoint,
|
|
275
|
-
headers: { "Api-Key": nrApiKey },
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
// Better Stack MCP — HTTP remote MCP; Bearer token auth.
|
|
279
|
-
const bsApiToken = creds.BETTERSTACK_API_TOKEN || creds.BETTERSTACK_TELEMETRY_TOKEN || creds.BETTERSTACK_UPTIME_TOKEN;
|
|
280
|
-
if (obsProviders.has("betterstack") && bsApiToken) {
|
|
281
|
-
auto["betterstack"] = {
|
|
282
|
-
type: "http",
|
|
283
|
-
url: "https://mcp.betterstack.com",
|
|
284
|
-
headers: { Authorization: `Bearer ${bsApiToken}` },
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
// ── Category B: Workspace tools (explicit opt-in) ──────────────
|
|
288
49
|
const tools = new Set(config.workspaceTools ?? []);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
args: ["-y", "@modelcontextprotocol/server-slack@latest"],
|
|
300
|
-
env: slackEnv,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// Notion MCP — requires opt-in; accepts NOTION_TOKEN or NOTION_API_KEY.
|
|
305
|
-
if (tools.has("notion")) {
|
|
306
|
-
const notionToken = creds.NOTION_TOKEN || creds.NOTION_API_KEY;
|
|
307
|
-
if (notionToken) {
|
|
308
|
-
auto["notion"] = {
|
|
309
|
-
type: "stdio",
|
|
310
|
-
command: "npx",
|
|
311
|
-
args: ["-y", "@notionhq/notion-mcp-server@latest"],
|
|
312
|
-
env: { NOTION_TOKEN: notionToken },
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
// PagerDuty MCP — HTTP remote endpoint; auth uses "Token token=<key>".
|
|
317
|
-
if (tools.has("pagerduty")) {
|
|
318
|
-
const pagerdutyToken = creds.PAGERDUTY_API_TOKEN;
|
|
319
|
-
if (pagerdutyToken) {
|
|
320
|
-
auto["pagerduty"] = {
|
|
321
|
-
type: "http",
|
|
322
|
-
url: "https://mcp.pagerduty.com/mcp",
|
|
323
|
-
headers: { Authorization: `Token token=${pagerdutyToken}` },
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
// Monday.com MCP — requires opt-in AND MONDAY_TOKEN.
|
|
328
|
-
if (tools.has("monday")) {
|
|
329
|
-
const mondayToken = creds.MONDAY_TOKEN;
|
|
330
|
-
if (mondayToken) {
|
|
331
|
-
auto["monday"] = {
|
|
332
|
-
type: "stdio",
|
|
333
|
-
command: "npx",
|
|
334
|
-
args: ["-y", "@mondaydotcomorg/monday-api-mcp@latest"],
|
|
335
|
-
env: { MONDAY_TOKEN: mondayToken },
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
// Asana MCP — requires opt-in AND ASANA_ACCESS_TOKEN.
|
|
340
|
-
if (tools.has("asana")) {
|
|
341
|
-
const asanaToken = creds.ASANA_ACCESS_TOKEN;
|
|
342
|
-
if (asanaToken) {
|
|
343
|
-
auto["asana"] = {
|
|
344
|
-
type: "stdio",
|
|
345
|
-
command: "npx",
|
|
346
|
-
args: ["-y", "asana-mcp@latest"],
|
|
347
|
-
env: { ASANA_ACCESS_TOKEN: asanaToken },
|
|
348
|
-
};
|
|
349
|
-
}
|
|
50
|
+
for (const entry of MCP_CATALOG) {
|
|
51
|
+
const matches = (entry.triggers.sourceControl?.includes(config.sourceControlProvider ?? "") ?? false) ||
|
|
52
|
+
(entry.triggers.issueTracker?.includes(config.issueTrackerProvider ?? "") ?? false) ||
|
|
53
|
+
(entry.triggers.observability?.some((o) => obsProviders.has(o)) ?? false) ||
|
|
54
|
+
(entry.triggers.workspaceTool?.some((t) => tools.has(t)) ?? false);
|
|
55
|
+
if (!matches)
|
|
56
|
+
continue;
|
|
57
|
+
const wired = entry.wire(creds);
|
|
58
|
+
if (wired)
|
|
59
|
+
auto[entry.id] = wired;
|
|
350
60
|
}
|
|
351
61
|
// User-supplied servers always win on key conflict.
|
|
352
62
|
return { ...auto, ...(config.userMcpServers ?? {}) };
|