Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.
Merged
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
298 changes: 64 additions & 234 deletions test/integration/mcp-connection.test.ts
Original file line number Diff line number Diff line change
@@ -1,165 +1,7 @@
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'
import { chromium, Browser, Page } from 'playwright'
import { readFileSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const testDir = join(__dirname, '..')
const testStateFile = join(testDir, 'node_modules/.cache/use-mcp-tests/test-state.json')

// Get MCP servers to test (ports determined at runtime)
function getMCPServers() {
try {
const stateData = readFileSync(testStateFile, 'utf-8')
const state = JSON.parse(stateData)

if (!state.honoPort) {
throw new Error('hono-mcp port not found in test state')
}

if (!state.cfAgentsPort) {
throw new Error('cf-agents port not found in test state')
}

return [
{
name: 'hono-mcp',
url: `http://localhost:${state.honoPort}/mcp`,
expectedTools: 1, // Minimum expected tools count
},
{
name: 'cf-agents',
url: `http://localhost:${state.cfAgentsPort}/public/mcp`,
expectedTools: 1, // Minimum expected tools count
},
{
name: 'cf-agents-sse',
url: `http://localhost:${state.cfAgentsPort}/public/sse`,
expectedTools: 1, // Minimum expected tools count
},
{
name: 'cf-agents-auth',
url: `http://localhost:${state.cfAgentsPort}/mcp`,
expectedTools: 1, // Minimum expected tools count
},
{
name: 'cf-agents-auth-sse',
url: `http://localhost:${state.cfAgentsPort}/sse`,
expectedTools: 1, // Minimum expected tools count
},
]
} catch (error) {
throw new Error(`Test environment not properly initialized: ${error}`)
}
}

async function connectToMCPServer(
page: Page,
serverUrl: string,
transportType: 'auto' | 'http' | 'sse' = 'auto',
): Promise<{ success: boolean; tools: string[]; debugLog: string }> {
// Navigate to the inspector
const stateData = readFileSync(testStateFile, 'utf-8')
const state = JSON.parse(stateData)

if (!state.staticPort) {
throw new Error('Static server port not available - state: ' + JSON.stringify(state))
}
const staticPort = state.staticPort

await page.goto(`http://localhost:${staticPort}`)

// Wait for the page to load
await page.waitForSelector('input[placeholder="Enter MCP server URL"]', { timeout: 10000 })

// Enter the server URL
const urlInput = page.locator('input[placeholder="Enter MCP server URL"]')
await urlInput.fill(serverUrl)

// Set transport type
const transportSelect = page.locator('select')
await transportSelect.selectOption(transportType)

// Click connect button
const connectButton = page.locator('button:has-text("Connect")')
await connectButton.click()

// Wait for connection attempt to complete (max 10 seconds)
await page.waitForTimeout(1000) // Initial wait

// Check for connection status
let attempts = 0
const maxAttempts = 20 // 10 seconds total (500ms * 20)
let isConnected = false

while (attempts < maxAttempts && !isConnected) {
try {
// Check if status badge shows "Connected"
const statusBadge = page.locator('.px-2.py-1.rounded-full')
if ((await statusBadge.count()) > 0) {
const statusText = await statusBadge.textContent({ timeout: 500 })
if (statusText?.toLowerCase().includes('connected')) {
isConnected = true
break
}
}

// Also check if tools count is > 0
const toolsHeader = page.locator('h3:has-text("Available Tools")')
if ((await toolsHeader.count()) > 0) {
const toolsText = await toolsHeader.textContent()
if (toolsText && /\d+/.test(toolsText)) {
const toolsCount = parseInt(toolsText.match(/\d+/)?.[0] || '0')
if (toolsCount > 0) {
isConnected = true
break
}
}
}
} catch (e) {
// Continue waiting
}

await page.waitForTimeout(500)
attempts++
}

// Extract available tools
const tools: string[] = []
try {
// Look for tool cards in the tools container
const toolCards = page.locator('.bg-white.rounded.border')
const toolCount = await toolCards.count()

for (let i = 0; i < toolCount; i++) {
const toolNameElement = toolCards.nth(i).locator('h4.font-bold.text-base.text-black')
const toolName = await toolNameElement.textContent()
if (toolName?.trim()) {
tools.push(toolName.trim())
}
}
} catch (e) {
console.warn('Could not extract tools list:', e)
}

// Extract debug log
let debugLog = ''
try {
const debugContainer = page.locator('.h-32.overflow-y-auto.font-mono.text-xs')
if ((await debugContainer.count()) > 0) {
debugLog = (await debugContainer.first().textContent()) || ''
}
} catch (e) {
console.warn('Could not extract debug log:', e)
}

return {
success: isConnected,
tools,
debugLog,
}
}
import { SERVER_CONFIGS } from './server-configs.js'
import { getTestState, connectToMCPServer, cleanupProcess } from './test-utils.js'

describe('MCP Connection Integration Tests', () => {
let browser: Browser
Expand All @@ -176,33 +18,21 @@ describe('MCP Connection Integration Tests', () => {
await browser.close()
}

// Force cleanup before Vitest exits - don't throw errors
// Force cleanup before Vitest exits
const state = globalThis.__INTEGRATION_TEST_STATE__
try {
if (state?.honoServer && !state.honoServer.killed) {
console.log('🔥 Force cleanup before test exit...')
state.honoServer.kill('SIGKILL')
}
} catch (e) {
// Ignore errors - process might already be dead
if (state?.honoServer) {
cleanupProcess(state.honoServer, 'hono-mcp')
}

try {
if (state?.cfAgentsServer && !state.cfAgentsServer.killed) {
console.log('🔥 Force cleanup cf-agents server...')
state.cfAgentsServer.kill('SIGKILL')
}
} catch (e) {
// Ignore errors - process might already be dead
if (state?.cfAgentsServer) {
cleanupProcess(state.cfAgentsServer, 'cf-agents')
}

try {
if (state?.staticServer) {
if (state?.staticServer) {
try {
state.staticServer.close()
state.staticServer.closeAllConnections?.()
} catch (e) {
// Ignore errors
}
} catch (e) {
// Ignore errors
}
})

Expand All @@ -225,59 +55,59 @@ describe('MCP Connection Integration Tests', () => {
}
})

const testScenarios = [
// Hono examples (MCP only)
{ serverName: 'hono-mcp', transportType: 'auto' as const },
{ serverName: 'hono-mcp', transportType: 'http' as const },

// Agents, no auth
{ serverName: 'cf-agents', transportType: 'auto' as const },
{ serverName: 'cf-agents', transportType: 'http' as const },
{ serverName: 'cf-agents-sse', transportType: 'sse' as const },
{ serverName: 'cf-agents-sse', transportType: 'auto' as const },

// Agents, with auth
{ serverName: 'cf-agents-auth', transportType: 'auto' as const },
{ serverName: 'cf-agents-auth', transportType: 'http' as const },
{ serverName: 'cf-agents-auth-sse', transportType: 'sse' as const },
{ serverName: 'cf-agents-auth-sse', transportType: 'auto' as const },
]

test.each(testScenarios)(
'should connect to $serverName with $transportType transport',
async ({ serverName, transportType }) => {
const servers = getMCPServers()
const server = servers.find((s) => s.name === serverName)

if (!server) {
throw new Error(`Server ${serverName} not found. Available servers: ${servers.map((s) => s.name).join(', ')}`)
}

console.log(`\n🔗 Testing connection to ${server.name} at ${server.url} with ${transportType} transport`)

const result = await connectToMCPServer(page, server.url, transportType)

if (result.success) {
console.log(`✅ Successfully connected to ${server.name}`)
console.log(`📋 Available tools (${result.tools.length}):`)
result.tools.forEach((tool, index) => {
console.log(` ${index + 1}. ${tool}`)
})

// Verify connection success
expect(result.success).toBe(true)
expect(result.tools.length).toBeGreaterThanOrEqual(server.expectedTools)
} else {
console.log(`❌ Failed to connect to ${server.name}`)
if (result.debugLog) {
console.log(`🐛 Debug log:`)
console.log(result.debugLog)
// Test each server configuration
for (const serverConfig of SERVER_CONFIGS) {
describe(`${serverConfig.name} server`, () => {
// Test each endpoint for this server
for (const endpoint of serverConfig.endpoints) {
// Test each transport type for this endpoint
for (const transportType of endpoint.transportTypes) {
test(`should connect to ${endpoint.path} with ${transportType} transport`, async () => {
const testState = getTestState()
const port = testState[serverConfig.portKey]

if (!port) {
throw new Error(`Port not found for ${serverConfig.name} (${serverConfig.portKey})`)
}

const serverUrl = `http://localhost:${port}${endpoint.path}`
console.log(`\n🔗 Testing connection to ${serverConfig.name} at ${serverUrl} with ${transportType} transport`)

const result = await connectToMCPServer(page, serverUrl, transportType)

if (result.success) {
console.log(`✅ Successfully connected to ${serverConfig.name}`)
console.log(`📋 Available tools (${result.tools.length}):`)
result.tools.forEach((tool, index) => {
console.log(` ${index + 1}. ${tool}`)
})

// Verify connection success
expect(result.success).toBe(true)
expect(result.tools.length).toBeGreaterThanOrEqual(serverConfig.expectedTools)
} else {
console.log(`❌ Failed to connect to ${serverConfig.name}`)
if (result.debugLog) {
console.log(`🐛 Debug log:`)
console.log(result.debugLog)
}

// Check if this is an expected failure case
const isExpectedFailure = endpoint.path.endsWith('/sse') && transportType === 'auto'

if (isExpectedFailure) {
console.log(`ℹ️ Expected failure: SSE endpoint with auto transport`)
expect(result.success).toBe(false)
} else {
// Fail the test with detailed information
throw new Error(
`Expected to connect to ${serverConfig.name} with ${transportType} transport but failed. Debug log: ${result.debugLog}`,
)
}
}
}, 45000)
}

// Fail the test with detailed information
throw new Error(`Expected to connect to ${server.name} with ${transportType} transport but failed. Debug log: ${result.debugLog}`)
}
},
45000,
)
})
}
})
Loading
Loading