Skip to content

Commit 4baf6af

Browse files
Copilotdata-douser
andauthored
Add stdio transport support to client integration test runner (#77)
* Initial plan * feat: add stdio transport support to MCP client integration tests - Update client to support both stdio and http transport modes (MCP_MODE env var, default: stdio) - In stdio mode, client spawns server via StdioClientTransport from MCP SDK - Update run-integration-tests.sh to skip manual server start/stop in stdio mode - Add test:integration:http and test:integration:stdio scripts to client/package.json - Update CI workflow to test both transport modes via matrix strategy - Update docs/testing.md to document stdio as default transport - Update docs/getting-started.md and docs/public.md to recommend VSIX installation Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> * feat: make stdio server path configurable via MCP_SERVER_PATH env var Add MCP_SERVER_PATH env var support for configuring the server binary path in stdio mode. Update CLI help text to document new environment variables. Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> * Fixes for stdio-based client integration tests * fix bugs in stdio MCP client Bug 1 — CWD mismatch in stdio mode (both platforms): StdioClientTransport inherited the client/ working directory, so relative paths passed to CodeQL CLI (e.g. server/ql/javascript/...) resolved to client/server/ql/... which does not exist. Add cwd: repoRoot to the transport options to match the HTTP-mode behavior where start-server.sh explicitly cd's to the repo root. Bug 2 — False success on Windows in stdio mode: StdioClientTransport.close() could cause an abrupt process exit on Windows before printTestSummary() and process.exit(exitCode) were reached, so the shell script saw exit code 0 and reported success despite test failures. Move summary printing and process.exitCode assignment above the disconnect() call in all four run methods so results are always reported even if disconnect triggers an early exit. * fix: address review feedback on transport selection and shell arg forwarding - Normalize MCP_MODE to lowercase in client constructor so that MCP_MODE=STDIO works the same as MCP_MODE=stdio - Select stdio transport by default; only use HTTP when MCP_MODE === "http" (previously any non-"stdio" value fell through to HTTP) - Add shift 2 in run_tests_in_mode() so mode_name and enable_monitoring positional args are not forwarded to node as extra CLI arguments Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> Co-authored-by: Nathan Randall <data-douser@github.com>
1 parent cb4e5a4 commit 4baf6af

File tree

9 files changed

+175
-70
lines changed

9 files changed

+175
-70
lines changed

.github/workflows/client-integration-tests.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@ permissions:
2626

2727
jobs:
2828
integration-tests:
29-
name: Integration Tests (${{ matrix.os }})
29+
name: Integration Tests (${{ matrix.os }}, ${{ matrix.mcp-mode }})
3030
runs-on: ${{ matrix.os }}
3131

3232
strategy:
3333
fail-fast: false
3434
matrix:
35+
mcp-mode: [http, stdio]
3536
os: [ubuntu-latest, windows-latest]
3637

3738
env:
3839
HTTP_HOST: 'localhost'
3940
HTTP_PORT: '3000'
41+
MCP_MODE: ${{ matrix.mcp-mode }}
4042
TIMEOUT_SECONDS: '30'
4143
URL_SCHEME: 'http'
4244

@@ -110,7 +112,7 @@ jobs:
110112
run: npm run test:integration --workspace=client
111113

112114
- name: MCP Integration Tests - Stop the background MCP server process
113-
if: always()
115+
if: always() && matrix.mcp-mode == 'http'
114116
shell: bash
115117
run: |
116118
if [ -f server.pid ]; then
@@ -141,8 +143,8 @@ jobs:
141143
- name: MCP Integration Tests - Summary
142144
shell: bash
143145
run: |
144-
echo "## Integration Tests Summary (${{ matrix.os }})" >> $GITHUB_STEP_SUMMARY
145-
echo "✅ MCP server integration tests passed on ${{ matrix.os }}" >> $GITHUB_STEP_SUMMARY
146+
echo "## Integration Tests Summary (${{ matrix.os }}, ${{ matrix.mcp-mode }})" >> $GITHUB_STEP_SUMMARY
147+
echo "✅ MCP server integration tests passed on ${{ matrix.os }} with ${{ matrix.mcp-mode }} transport" >> $GITHUB_STEP_SUMMARY
146148
147149
codeql-path-tests:
148150
name: CODEQL_PATH Tests (${{ matrix.os }})

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ codeql-development-mcp-server.code-workspace
4949
# Prevent accidentally committing integration test output files in root directory
5050
# These should only be in client/integration-tests/primitives/tools/*/after/ directories
5151
/evaluator-log.json
52+
/client/query-results/
53+
/client/query-results.bqrs
54+
/client/query-results.sarif
5255
/query-results/
5356
/query-results.bqrs
5457
/query-results.sarif

client/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@
5555
"test:coverage": "echo 'NOOP client test:coverage'",
5656
"test:integration": "scripts/run-integration-tests.sh --no-install-packs",
5757
"test:integration:default": "ENABLE_MONITORING_TOOLS=false scripts/run-integration-tests.sh --no-install-packs",
58+
"test:integration:http": "MCP_MODE=http scripts/run-integration-tests.sh --no-install-packs",
5859
"test:integration:install-packs": "scripts/run-integration-tests.sh",
59-
"test:integration:monitoring": "ENABLE_MONITORING_TOOLS=true scripts/run-integration-tests.sh",
60+
"test:integration:monitoring": "ENABLE_MONITORING_TOOLS=true scripts/run-integration-tests.sh --no-install-packs",
61+
"test:integration:stdio": "MCP_MODE=stdio scripts/run-integration-tests.sh --no-install-packs",
6062
"tidy": "npm run lint && npm run format"
6163
}
6264
}

client/scripts/run-integration-tests.sh

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
# 2. Monitoring mode (monitoring tools enabled) - tests session_* tools
99
#
1010
# Environment Variables:
11-
# HTTP_HOST - Server host (default: localhost)
12-
# HTTP_PORT - Server port (default: 3000)
11+
# MCP_MODE - MCP transport mode (default: stdio, also: http)
12+
# HTTP_HOST - Server host for HTTP mode (default: localhost)
13+
# HTTP_PORT - Server port for HTTP mode (default: 3000)
1314
# TIMEOUT_SECONDS - Request timeout (default: 30)
1415
# ENABLE_MONITORING_TOOLS - Force a specific mode instead of running both:
1516
# "true" = only run with monitoring tools enabled
@@ -20,6 +21,7 @@
2021
# ./run-integration-tests.sh # Run in BOTH modes (recommended)
2122
# ENABLE_MONITORING_TOOLS=false ./run-integration-tests.sh # Only default mode
2223
# ENABLE_MONITORING_TOOLS=true ./run-integration-tests.sh # Only monitoring mode
24+
# MCP_MODE=http ./run-integration-tests.sh # Run using HTTP transport
2325
# ./run-integration-tests.sh --tools session_end # Filter to specific tools
2426

2527
set -e
@@ -29,6 +31,7 @@ CLIENT_DIR="$(dirname "$SCRIPT_DIR")"
2931
SERVER_DIR="$(dirname "$CLIENT_DIR")/server"
3032

3133
# Set default environment variables
34+
export MCP_MODE="${MCP_MODE:-stdio}"
3235
export HTTP_HOST="${HTTP_HOST:-localhost}"
3336
export HTTP_PORT="${HTTP_PORT:-3000}"
3437
export TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-30}"
@@ -65,7 +68,10 @@ for arg in "$@"; do
6568
done
6669

6770
echo "🚀 Starting CodeQL MCP Integration Tests"
68-
echo "Server URL: $URL_SCHEME://$HTTP_HOST:$HTTP_PORT/mcp"
71+
echo "MCP Mode: $MCP_MODE"
72+
if [ "$MCP_MODE" = "http" ]; then
73+
echo "Server URL: $URL_SCHEME://$HTTP_HOST:$HTTP_PORT/mcp"
74+
fi
6975

7076
# Step 1: Build and bundle the server code
7177
echo "📦 Building CodeQL MCP server bundle..."
@@ -81,43 +87,56 @@ else
8187
fi
8288

8389
cd "$CLIENT_DIR"
84-
export MCP_MODE=http
85-
export MCP_SERVER_URL="$URL_SCHEME://$HTTP_HOST:$HTTP_PORT/mcp"
90+
91+
# For HTTP mode, set the server URL for the client
92+
if [ "$MCP_MODE" = "http" ]; then
93+
export MCP_SERVER_URL="$URL_SCHEME://$HTTP_HOST:$HTTP_PORT/mcp"
94+
fi
8695

8796
# Function to run tests in a specific mode
8897
run_tests_in_mode() {
8998
local mode_name="$1"
9099
local enable_monitoring="$2"
91-
100+
shift 2
101+
92102
echo ""
93103
echo "═══════════════════════════════════════════════════════════════"
94104
echo "🧪 Running integration tests: $mode_name"
95105
echo "═══════════════════════════════════════════════════════════════"
96-
106+
97107
# Set the monitoring tools flag for this run
98108
export ENABLE_MONITORING_TOOLS="$enable_monitoring"
99-
100-
# Start MCP server with current settings
101-
echo "🚀 Starting MCP server (monitoring=$enable_monitoring)..."
102-
"$SCRIPT_DIR/start-server.sh"
103-
104-
# Wait for server startup
105-
echo "⏳ Waiting for server startup..."
106-
"$SCRIPT_DIR/wait-for-server.sh"
107-
109+
110+
if [ "$MCP_MODE" = "http" ]; then
111+
# HTTP mode: start server in background, run tests, stop server
112+
echo "🚀 Starting MCP server (monitoring=$enable_monitoring)..."
113+
"$SCRIPT_DIR/start-server.sh"
114+
115+
# Wait for server startup
116+
echo "⏳ Waiting for server startup..."
117+
"$SCRIPT_DIR/wait-for-server.sh"
118+
else
119+
# stdio mode: client spawns server directly via StdioClientTransport
120+
echo "📡 Using stdio transport (client spawns server directly)"
121+
fi
122+
108123
# Run the integration tests (skip pack installation since we already did it)
109124
echo "🧪 Running tests..."
110125
node src/ql-mcp-client.js integration-tests --no-install-packs "$@"
111-
112-
# Stop the server before next mode
113-
echo "🛑 Stopping server..."
114-
"$SCRIPT_DIR/stop-server.sh"
126+
127+
if [ "$MCP_MODE" = "http" ]; then
128+
# Stop the server before next mode
129+
echo "🛑 Stopping server..."
130+
"$SCRIPT_DIR/stop-server.sh"
131+
fi
115132
}
116133

117134
# Trap to ensure cleanup happens even if script fails
118135
cleanup() {
119136
echo "🧹 Cleaning up..."
120-
"$SCRIPT_DIR/stop-server.sh" 2>/dev/null || true
137+
if [ "$MCP_MODE" = "http" ]; then
138+
"$SCRIPT_DIR/stop-server.sh" 2>/dev/null || true
139+
fi
121140
}
122141
trap cleanup EXIT
123142

client/src/lib/cli-parser.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ OPTIONS:
133133
Example: --timeout 600
134134
135135
--help Display help information
136+
137+
ENVIRONMENT VARIABLES:
138+
MCP_MODE MCP transport mode: stdio (default) or http
139+
MCP_SERVER_PATH Path to the MCP server JS entry point (stdio mode only)
140+
MCP_SERVER_URL MCP server URL (http mode only, default: http://localhost:3000/mcp)
141+
ENABLE_MONITORING_TOOLS Enable session_* monitoring tools (default: false)
136142
`;
137143
}
138144

0 commit comments

Comments
 (0)