Skip to content

Commit c9859ba

Browse files
committed
fix: fix mcp and virtual-key tests
1 parent 8ca7ecc commit c9859ba

File tree

3 files changed

+73
-16
lines changed

3 files changed

+73
-16
lines changed

.github/workflows/configs/default/config.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@
3737
"network_config": {
3838
"default_request_timeout_in_seconds": 300
3939
}
40+
},
41+
"anthropic": {
42+
"keys": [
43+
{
44+
"name": "e2e-anthropic-key",
45+
"value": "env.ANTHROPIC_API_KEY",
46+
"weight": 1,
47+
"use_for_batch_api": true
48+
}
49+
],
50+
"network_config": {
51+
"default_request_timeout_in_seconds": 300
52+
}
4053
}
4154
}
4255
}

.github/workflows/e2e-tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name: E2E Tests
22

33
on:
44
push:
5-
branches: ["02-09-fix_fix_e2e_tests"]
6-
5+
branches: ["02-11-fix_fix_mcp_and_virtual-key_tests"]
6+
77
concurrency:
88
group: e2e-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
99
cancel-in-progress: true
@@ -49,8 +49,8 @@ jobs:
4949
- name: Run E2E UI tests
5050
env:
5151
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
52-
# Optional: for SSE MCP tests (e.g. remote proxy). Set in repo secrets.
53-
MCP_SSE_URL: ${{ secrets.MCP_SSE_URL }}
52+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
53+
# Optional: for SSE MCP tests (e.g. remote proxy). Set in repo secrets.s
5454
MCP_SSE_HEADERS: ${{ secrets.MCP_SSE_HEADERS }}
5555
run: ./.github/workflows/scripts/test-e2e-ui.sh
5656

tests/e2e/features/mcp-registry/mcp-registry.data.ts

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { resolve } from 'path'
1+
import { join, resolve } from 'path'
22
import { MCPClientConfig, EnvVarLike } from './pages/mcp-registry.page'
33

44
/** Normalize header value from env (string or EnvVarLike) to EnvVarLike */
@@ -7,20 +7,62 @@ function toEnvVarLike(v: string | EnvVarLike): EnvVarLike {
77
return { value: String(v), env_var: '', from_env: false }
88
}
99

10-
/** Build headers from MCP_SSE_HEADERS JSON (injected in workflow). No defaults in code. */
10+
/**
11+
* Resolve header value: if string starts with "env.", use process.env[VAR_NAME].
12+
*/
13+
function resolveHeaderValue(v: EnvVarLike): EnvVarLike {
14+
if (v.value.startsWith('env.')) {
15+
const envVar = v.value.slice(4)
16+
const resolved = process.env[envVar]
17+
if (resolved !== undefined) {
18+
return { value: resolved, env_var: envVar, from_env: true }
19+
}
20+
}
21+
return v
22+
}
23+
24+
/**
25+
* Parse MCP_SSE_HEADERS: supports single object, array of objects, or concatenated objects.
26+
* e.g. {"Authorization":"Bearer ..."},{"ENV_EXA_API_KEY":"..."} → merged into one record
27+
*/
28+
function parseSSEHeadersRaw(raw: string): Record<string, string | EnvVarLike> {
29+
const trimmed = raw.trim()
30+
if (!trimmed) return {}
31+
try {
32+
const parsed = JSON.parse(trimmed)
33+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
34+
return parsed
35+
}
36+
} catch {
37+
// Fallback: concatenated objects {"a":1},{"b":2} → wrap in [ ] and merge
38+
}
39+
try {
40+
const asArray = JSON.parse('[' + trimmed + ']')
41+
if (Array.isArray(asArray) && asArray.every((o) => typeof o === 'object' && o !== null)) {
42+
return Object.assign({}, ...asArray)
43+
}
44+
} catch {
45+
// ignore
46+
}
47+
return {}
48+
}
49+
50+
/**
51+
* Build headers from MCP_SSE_HEADERS JSON (injected in workflow).
52+
* Supports: {"Authorization":"Bearer ..."},{"ENV_EXA_API_KEY":"..."} (concatenated objects)
53+
* or single object. Values starting with "env." are resolved from process.env.
54+
*/
1155
function getSSEHeadersFromEnv(): Record<string, EnvVarLike> {
1256
const raw = process.env.MCP_SSE_HEADERS
1357
if (!raw) return {}
14-
try {
15-
const parsed = JSON.parse(raw) as Record<string, string | EnvVarLike>
16-
const out: Record<string, EnvVarLike> = {}
17-
for (const [k, v] of Object.entries(parsed)) {
18-
if (v !== undefined && v !== null) out[k] = toEnvVarLike(v)
58+
const parsed = parseSSEHeadersRaw(raw)
59+
const out: Record<string, EnvVarLike> = {}
60+
for (const [k, v] of Object.entries(parsed)) {
61+
if (v !== undefined && v !== null) {
62+
out[k] = resolveHeaderValue(toEnvVarLike(v))
1963
}
20-
return out
21-
} catch {
22-
return {}
2364
}
65+
return out
2466
}
2567

2668
/**
@@ -55,7 +97,7 @@ export function createHTTPClientData(overrides: Partial<MCPClientConfig> = {}):
5597
* When unset, uses local http://localhost:3001/sse and no headers (no secrets in code).
5698
*/
5799
export function createSSEClientData(overrides: Partial<MCPClientConfig> = {}): MCPClientConfig {
58-
const connectionUrl = process.env.MCP_SSE_URL ?? 'http://localhost:3001/sse'
100+
const connectionUrl = "https://ts-mcp-sse-proxy.fly.dev/npx%20-y%20exa-mcp-server/sse"
59101
const headers = getSSEHeadersFromEnv()
60102
const hasHeaders = headers && Object.keys(headers).length > 0
61103
return createMCPClientData({
@@ -74,8 +116,10 @@ export function createSSEClientData(overrides: Partial<MCPClientConfig> = {}): M
74116
*/
75117
export function createSTDIOClientData(overrides: Partial<MCPClientConfig> = {}): MCPClientConfig {
76118
// Use the built test-tools-server
77-
const serverPath = resolve(__dirname, '../../../../examples/mcps/test-tools-server/dist/index.js')
119+
const REPO_ROOT = resolve(__dirname, '..', '..', '..', '..')
78120

121+
// Then for the stdio server:
122+
const serverPath = join(REPO_ROOT, 'examples', 'mcps', 'test-tools-server', 'dist', 'index.js')
79123
return createMCPClientData({
80124
name: `stdio_client_${Date.now()}`,
81125
connectionType: 'stdio',

0 commit comments

Comments
 (0)