chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
/**
* Test: Remote MCP Server with Streamable HTTP (auth headers)
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { writeFileSync, rmSync, readdirSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { buildRequestHeaders } from '../src/transport/headers.js';
import type { StreamableServerEntry } from '../src/types.js';
// Test constants
const TEST_CONFIG_DIR = join(tmpdir(), 'test-mcp-remote-headers');
const TEST_URL = 'https://mcp.coze.cn/v1/plugins/7407724292865130515';
// 注意: 这是临时测试 token不要固化到代码中
const TEST_AUTH_TOKEN = process.env.TEST_AUTH_TOKEN || 'Bearer cztei_xxx';
const TEST_HEADERS = {
Authorization: TEST_AUTH_TOKEN,
};
// Helper to create a test config file
function createTestConfig(serverName: string, headers?: Record<string, string>): string {
const configPath = join(TEST_CONFIG_DIR, `${serverName}.json`);
const config = {
mcpServers: {
[serverName]: {
url: TEST_URL,
transport: 'streamable-http',
headers: headers || TEST_HEADERS,
},
},
};
writeFileSync(configPath, JSON.stringify(config), 'utf-8');
return configPath;
}
// Helper to cleanup test files
function cleanupTestFiles() {
try {
const files = readdirSync(TEST_CONFIG_DIR);
for (const file of files) {
rmSync(file);
}
} catch {
// ignore
}
}
describe('buildRequestHeaders', () => {
beforeEach(() => {
cleanupTestFiles();
});
it('should return undefined when entry has no headers or authToken', () => {
const entry: StreamableServerEntry = {
url: TEST_URL,
transport: 'streamable-http',
};
const result = buildRequestHeaders(entry);
expect(result).toBeUndefined();
});
it('should return headers with Bearer prefix when entry has authToken', () => {
const rawToken = 'my-auth-token';
const entry: StreamableServerEntry = {
url: TEST_URL,
transport: 'streamable-http',
authToken: rawToken,
};
const result = buildRequestHeaders(entry);
expect(result).toEqual({
Authorization: `Bearer ${rawToken}`,
});
});
it('should return headers directly when entry has headers', () => {
const customHeaders = {
'X-Custom-Header': 'custom-value',
Authorization: 'CustomAuth custom-token',
};
const entry: StreamableServerEntry = {
url: TEST_URL,
transport: 'streamable-http',
headers: customHeaders,
};
const result = buildRequestHeaders(entry);
expect(result).toEqual(customHeaders);
});
it('should let authToken override headers.Authorization when both are provided', () => {
const customHeaders = {
Authorization: 'CustomAuth custom-token',
};
const entry: StreamableServerEntry = {
url: TEST_URL,
transport: 'streamable-http',
headers: customHeaders,
authToken: 'override-token',
};
const result = buildRequestHeaders(entry);
// authToken 会覆盖 headers 中的 Authorization
expect(result).toEqual({
Authorization: 'Bearer override-token',
});
});
it('should return undefined when entry is a stdio entry (no url)', () => {
const entry = {
command: 'npx',
args: ['-y', 'some-mcp-server'],
} as unknown as StreamableServerEntry;
const result = buildRequestHeaders(entry);
expect(result).toBeUndefined();
});
});
describe('detectProtocol with auth failure', () => {
// 这个测试需要真实的网络请求, 仅用于调试目的
// 注意: 不要在 CI 中启用, 因为 token 会过期
it.skip('should handle 401 auth failure gracefully', async () => {
const { detectProtocol } = await import('../src/detect.js');
const invalidToken = 'Bearer invalid-token-for-testing';
const result = await detectProtocol(TEST_URL, {
Authorization: invalidToken,
});
// 即使鉴权失败, 也应该返回一个协议类型(默认 sse
expect(['sse', 'stream']).toContain(result);
});
});