Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions core/config/yaml/loadYaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
ModelRole,
PackageIdentifier,
RegistryClient,
TEMPLATE_VAR_REGEX,
unrollAssistant,
validateConfigYaml,
} from "@continuedev/config-yaml";
Expand Down Expand Up @@ -237,22 +236,6 @@ export async function configYamlToContinueConfig(options: {
sourceFile: doc.sourceFile,
}));

config.mcpServers?.forEach((mcpServer) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed this since it only applied to args. Moved to mcp loading

if ("args" in mcpServer) {
const mcpArgVariables =
mcpServer.args?.filter((arg) => TEMPLATE_VAR_REGEX.test(arg)) ?? [];

if (mcpArgVariables.length === 0) {
return;
}

localErrors.push({
fatal: false,
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.`,
});
}
});

// Prompt files -
try {
const promptFiles = await getAllPromptFiles(ide, undefined, true);
Expand Down
17 changes: 17 additions & 0 deletions core/context/mcp/MCPConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import { fileURLToPath } from "url";

import {
decodeSecretLocation,
getTemplateVariables,
} from "@continuedev/config-yaml";
import {
SSEClientTransport,
SseError,
Expand Down Expand Up @@ -163,6 +167,19 @@ class MCPConnection {
}
}

const vars = getTemplateVariables(JSON.stringify(this.options));
const unrendered = vars.map((v) => {
return decodeSecretLocation(v.replace("secrets.", "")).secretName;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodeSecretLocation expects a colon-delimited secret location (e.g. "user:slug/secret"), but this passes plain secret keys like "OPENAI_API_KEY". When unresolved secrets are present, decodeSecretLocation throws and connectClient crashes instead of collecting the warning.

Prompt for AI agents
Address the following comment on core/context/mcp/MCPConnection.ts at line 172:

<comment>decodeSecretLocation expects a colon-delimited secret location (e.g. &quot;user:slug/secret&quot;), but this passes plain secret keys like &quot;OPENAI_API_KEY&quot;. When unresolved secrets are present, decodeSecretLocation throws and connectClient crashes instead of collecting the warning.</comment>

<file context>
@@ -163,6 +167,19 @@ class MCPConnection {
 
+    const vars = getTemplateVariables(JSON.stringify(this.options));
+    const unrendered = vars.map((v) =&gt; {
+      return decodeSecretLocation(v.replace(&quot;secrets.&quot;, &quot;&quot;)).secretName;
+    });
+
</file context>
Suggested change
return decodeSecretLocation(v.replace("secrets.", "")).secretName;
return v.replace("secrets.", "");
Fix with Cubic

});

if (unrendered.length > 0) {
this.errors.push(
`${this.options.name} MCP Server has unresolved secrets: ${unrendered.join(", ")}.
For personal use you can set the secret in the hub at https://hub.continue.dev/settings/secrets.
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.`,
);
}

this.connectionPromise = Promise.race([
// If aborted by a refresh or other, cancel and don't do anything
new Promise((resolve) => {
Expand Down
20 changes: 20 additions & 0 deletions extensions/cli/src/services/MCPService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import { getErrorString } from "../util/error.js";
import { logger } from "../util/logger.js";

import {

Check failure on line 18 in extensions/cli/src/services/MCPService.ts

View workflow job for this annotation

GitHub Actions / lint

`@continuedev/config-yaml` import should occur before import of `@continuedev/sdk`

Check failure on line 18 in extensions/cli/src/services/MCPService.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
decodeSecretLocation,
getTemplateVariables,
} from "@continuedev/config-yaml";
import { BaseService, ServiceWithDependencies } from "./BaseService.js";
import { serviceContainer } from "./ServiceContainer.js";
import {
Expand Down Expand Up @@ -248,7 +252,23 @@
this.connections.set(serverName, connection);
this.updateState();

const vars = getTemplateVariables(JSON.stringify(serverConfig));
const unrendered = vars.map((v) => {
return decodeSecretLocation(v.replace("secrets.", "")).secretName;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodeSecretLocation is being invoked on every template variable, so any non-secret placeholder (e.g. ${{ inputs.* }}) makes rest undefined inside decodeSecretLocation and causes connectServer to throw before establishing the connection.

Prompt for AI agents
Address the following comment on extensions/cli/src/services/MCPService.ts at line 257:

<comment>decodeSecretLocation is being invoked on every template variable, so any non-secret placeholder (e.g. ${{ inputs.* }}) makes rest undefined inside decodeSecretLocation and causes connectServer to throw before establishing the connection.</comment>

<file context>
@@ -248,7 +252,23 @@ export class MCPService
 
+    const vars = getTemplateVariables(JSON.stringify(serverConfig));
+    const unrendered = vars.map((v) =&gt; {
+      return decodeSecretLocation(v.replace(&quot;secrets.&quot;, &quot;&quot;)).secretName;
+    });
+
</file context>
Fix with Cubic

});

try {
if (unrendered.length > 0) {
const message = `${serverConfig.name} MCP Server has unresolved secrets: ${unrendered.join(", ")}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems duplicate but the message is different enough for CLI since process.env is supported that I decided to leave them separate.

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.
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.`;
if (this.isHeadless) {
throw new Error(message);
} else {
connection.warnings.push(message);
}
}

const client = await this.getConnectedClient(serverConfig);

connection.client = client;
Expand Down
Loading