|
6 | 6 | readEnvWithDeprecation, |
7 | 7 | resolveAllowDegradedTenancy, |
8 | 8 | resolveSearchPinyinEnabled, |
| 9 | + isMcpServerEnabled, |
| 10 | + resolveMcpStdioAutoStart, |
9 | 11 | } from './env.js'; |
10 | 12 |
|
11 | 13 | describe('readEnvWithDeprecation', () => { |
@@ -172,3 +174,66 @@ describe('resolveSearchPinyinEnabled (#2486)', () => { |
172 | 174 | } |
173 | 175 | }); |
174 | 176 | }); |
| 177 | + |
| 178 | +describe('MCP switches — HTTP surface vs stdio auto-start are decoupled (#3167)', () => { |
| 179 | + const origServer = process.env.OS_MCP_SERVER_ENABLED; |
| 180 | + const origServerLegacy = process.env.MCP_SERVER_ENABLED; |
| 181 | + const origStdio = process.env.OS_MCP_STDIO_ENABLED; |
| 182 | + const restore = (key: string, val: string | undefined) => { |
| 183 | + if (val === undefined) delete process.env[key]; |
| 184 | + else process.env[key] = val; |
| 185 | + }; |
| 186 | + afterEach(() => { |
| 187 | + restore('OS_MCP_SERVER_ENABLED', origServer); |
| 188 | + restore('MCP_SERVER_ENABLED', origServerLegacy); |
| 189 | + restore('OS_MCP_STDIO_ENABLED', origStdio); |
| 190 | + }); |
| 191 | + |
| 192 | + it('isMcpServerEnabled (HTTP surface): default-on, only explicit falsy opts out', () => { |
| 193 | + delete process.env.OS_MCP_SERVER_ENABLED; |
| 194 | + expect(isMcpServerEnabled()).toBe(true); |
| 195 | + for (const v of ['false', '0', 'off', 'no', 'FALSE']) { |
| 196 | + process.env.OS_MCP_SERVER_ENABLED = v; |
| 197 | + expect(isMcpServerEnabled(), `${v} should opt out`).toBe(false); |
| 198 | + } |
| 199 | + for (const v of ['true', '1', 'anything']) { |
| 200 | + process.env.OS_MCP_SERVER_ENABLED = v; |
| 201 | + expect(isMcpServerEnabled(), `${v} keeps HTTP on`).toBe(true); |
| 202 | + } |
| 203 | + }); |
| 204 | + |
| 205 | + it('stdio auto-start: default OFF when nothing is set', () => { |
| 206 | + delete process.env.OS_MCP_SERVER_ENABLED; |
| 207 | + delete process.env.OS_MCP_STDIO_ENABLED; |
| 208 | + expect(resolveMcpStdioAutoStart()).toEqual({ enabled: false, viaDeprecatedAlias: false }); |
| 209 | + }); |
| 210 | + |
| 211 | + it('stdio auto-start: canonical OS_MCP_STDIO_ENABLED (truthy, no deprecation)', () => { |
| 212 | + delete process.env.OS_MCP_SERVER_ENABLED; |
| 213 | + for (const v of ['1', 'true', 'on', 'yes', 'TRUE']) { |
| 214 | + process.env.OS_MCP_STDIO_ENABLED = v; |
| 215 | + expect(resolveMcpStdioAutoStart(), v).toEqual({ enabled: true, viaDeprecatedAlias: false }); |
| 216 | + } |
| 217 | + }); |
| 218 | + |
| 219 | + it('stdio auto-start: legacy OS_MCP_SERVER_ENABLED=true still starts it, flagged deprecated', () => { |
| 220 | + delete process.env.OS_MCP_STDIO_ENABLED; |
| 221 | + process.env.OS_MCP_SERVER_ENABLED = 'true'; |
| 222 | + expect(resolveMcpStdioAutoStart()).toEqual({ enabled: true, viaDeprecatedAlias: true }); |
| 223 | + }); |
| 224 | + |
| 225 | + it('stdio auto-start: OS_MCP_SERVER_ENABLED=false (or other) never starts stdio — no footgun', () => { |
| 226 | + delete process.env.OS_MCP_STDIO_ENABLED; |
| 227 | + for (const v of ['false', '0', 'off', '1', 'on', 'yes']) { |
| 228 | + process.env.OS_MCP_SERVER_ENABLED = v; |
| 229 | + // Only the literal `true` was ever the legacy stdio trigger. |
| 230 | + expect(resolveMcpStdioAutoStart().enabled, `server=${v}`).toBe(false); |
| 231 | + } |
| 232 | + }); |
| 233 | + |
| 234 | + it('canonical switch wins over the legacy alias (no deprecation flag)', () => { |
| 235 | + process.env.OS_MCP_STDIO_ENABLED = 'true'; |
| 236 | + process.env.OS_MCP_SERVER_ENABLED = 'true'; |
| 237 | + expect(resolveMcpStdioAutoStart()).toEqual({ enabled: true, viaDeprecatedAlias: false }); |
| 238 | + }); |
| 239 | +}); |
0 commit comments