Skip to content

Commit 465ca62

Browse files
authored
Merge pull request #8656 from continuedev/dallin/error-untemplated-mcp-secrets
fix: warnings and errors for unresolved MCP secrets
2 parents 33914f3 + 0b011ea commit 465ca62

File tree

3 files changed

+43
-17
lines changed

3 files changed

+43
-17
lines changed

core/config/yaml/loadYaml.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
ModelRole,
1010
PackageIdentifier,
1111
RegistryClient,
12-
TEMPLATE_VAR_REGEX,
1312
unrollAssistant,
1413
validateConfigYaml,
1514
} from "@continuedev/config-yaml";
@@ -237,22 +236,6 @@ export async function configYamlToContinueConfig(options: {
237236
sourceFile: doc.sourceFile,
238237
}));
239238

240-
config.mcpServers?.forEach((mcpServer) => {
241-
if ("args" in mcpServer) {
242-
const mcpArgVariables =
243-
mcpServer.args?.filter((arg) => TEMPLATE_VAR_REGEX.test(arg)) ?? [];
244-
245-
if (mcpArgVariables.length === 0) {
246-
return;
247-
}
248-
249-
localErrors.push({
250-
fatal: false,
251-
message: `MCP server "${mcpServer.name}" has unsubstituted variables in args: ${mcpArgVariables.join(", ")}. Please refer to https://docs.continue.dev/hub/secrets/secret-types for managing hub secrets.`,
252-
});
253-
}
254-
});
255-
256239
// Prompt files -
257240
try {
258241
const promptFiles = await getAllPromptFiles(ide, undefined, true);

core/context/mcp/MCPConnection.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
22
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
33
import { fileURLToPath } from "url";
44

5+
import {
6+
decodeSecretLocation,
7+
getTemplateVariables,
8+
} from "@continuedev/config-yaml";
59
import {
610
SSEClientTransport,
711
SseError,
@@ -163,6 +167,24 @@ class MCPConnection {
163167
}
164168
}
165169

170+
const vars = getTemplateVariables(JSON.stringify(this.options));
171+
const unrendered = vars.map((v) => {
172+
const stripped = v.replace("secrets.", "");
173+
try {
174+
return decodeSecretLocation(stripped).secretName;
175+
} catch {
176+
return stripped;
177+
}
178+
});
179+
180+
if (unrendered.length > 0) {
181+
this.errors.push(
182+
`${this.options.name} MCP Server has unresolved secrets: ${unrendered.join(", ")}.
183+
For personal use you can set the secret in the hub at https://hub.continue.dev/settings/secrets.
184+
Org-level secrets can only be used for MCP by Background Agents (https://docs.continue.dev/hub/agents/overview) when \"Include in Env\" is enabled.`,
185+
);
186+
}
187+
166188
this.connectionPromise = Promise.race([
167189
// If aborted by a refresh or other, cancel and don't do anything
168190
new Promise((resolve) => {

extensions/cli/src/services/MCPService.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import {
2+
decodeSecretLocation,
3+
getTemplateVariables,
4+
} from "@continuedev/config-yaml";
15
import { type AssistantConfig } from "@continuedev/sdk";
26
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
37
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -311,7 +315,24 @@ export class MCPService
311315
this.connections.set(serverName, connection);
312316
this.updateState();
313317

318+
const vars = getTemplateVariables(JSON.stringify(serverConfig));
319+
const secretVars = vars.filter((v) => v.startsWith("secrets."));
320+
const unrendered = secretVars.map((v) => {
321+
return decodeSecretLocation(v.replace("secrets.", "")).secretName;
322+
});
323+
314324
try {
325+
if (unrendered.length > 0) {
326+
const message = `${serverConfig.name} MCP Server has unresolved secrets: ${unrendered.join(", ")}
327+
For personal use you can set the secret in the hub at https://hub.continue.dev/settings/secrets or pass it to the CLI environment.
328+
Org-level secrets can only be used for MCP by Background Agents (https://docs.continue.dev/hub/agents/overview) when \"Include in Env\" is enabled for the secret.`;
329+
if (this.isHeadless) {
330+
throw new Error(message);
331+
} else {
332+
connection.warnings.push(message);
333+
}
334+
}
335+
315336
const client = await this.getConnectedClient(serverConfig, connection);
316337

317338
connection.client = client;

0 commit comments

Comments
 (0)