Skip to content

Commit b30f848

Browse files
committed
adding additional e2e tests for mcp servers
1 parent fb4f030 commit b30f848

File tree

9 files changed

+394
-92
lines changed

9 files changed

+394
-92
lines changed

dev-tools/mcp-mock-server/README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ This mock server helps developers:
1919
-**HTTP & HTTPS** - Runs both protocols simultaneously for comprehensive testing
2020
-**Header Capture** - Captures and displays all request headers
2121
-**Debug Endpoints** - Inspect captured headers and request history
22-
-**MCP Protocol** - Implements basic MCP endpoints for testing
22+
-**MCP Protocol** - Implements MCP endpoints (initialize, tools/list, tools/call)
2323
-**Request Logging** - Tracks recent requests with timestamps
2424
-**Self-Signed Certs** - Auto-generates certificates for HTTPS testing
25+
-**Tool Execution** - Returns mock results for tool/call testing
2526

2627
## Quick Start
2728

@@ -46,8 +47,11 @@ HTTPS: https://localhost:3001
4647
Debug endpoints:
4748
• /debug/headers - View captured headers
4849
• /debug/requests - View request log
49-
MCP endpoint:
50-
• POST /mcp/v1/list_tools
50+
MCP endpoints:
51+
• POST with JSON-RPC (any path)
52+
- method: "initialize"
53+
- method: "tools/list"
54+
- method: "tools/call"
5155
======================================================================
5256
Note: HTTPS uses a self-signed certificate (for testing only)
5357
```
@@ -270,8 +274,9 @@ python dev-tools/mcp-mock-server/server.py 8080
270274
This is a **development/testing tool only**:
271275
- ❌ Not for production use
272276
- ❌ No authentication/security
273-
- ❌ Limited MCP protocol implementation
277+
- ❌ Limited MCP protocol implementation (initialize, tools/list, tools/call only)
274278
- ❌ Single-threaded (one request at a time)
279+
- ❌ Mock responses only (not real tool execution)
275280

276281
For production, use real MCP servers.
277282

dev-tools/mcp-mock-server/server.py

Lines changed: 96 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -73,75 +73,109 @@ def do_POST(self) -> None: # pylint: disable=invalid-name
7373
request_id = request_data.get("id", 1)
7474
method = request_data.get("method", "unknown")
7575
except (json.JSONDecodeError, UnicodeDecodeError):
76+
request_data = {}
7677
request_id = 1
7778
method = "unknown"
7879

7980
# Determine tool name based on authorization header to avoid collisions
8081
auth_header = self.headers.get("Authorization", "")
8182

83+
# Initialize tool info defaults
84+
tool_name = "mock_tool_no_auth"
85+
tool_desc = "Mock tool with no authorization"
86+
8287
# Match based on token content
83-
match auth_header:
84-
case _ if "test-secret-token" in auth_header:
85-
tool_name = "mock_tool_file"
86-
tool_desc = "Mock tool with file-based auth"
87-
case _ if "my-k8s-token" in auth_header:
88-
tool_name = "mock_tool_k8s"
89-
tool_desc = "Mock tool with Kubernetes token"
90-
case _ if "my-client-token" in auth_header:
91-
tool_name = "mock_tool_client"
92-
tool_desc = "Mock tool with client-provided token"
93-
case _:
94-
# No auth header or unrecognized token
95-
tool_name = "mock_tool_no_auth"
96-
tool_desc = "Mock tool with no authorization"
97-
98-
# Handle MCP protocol methods
99-
if method == "initialize":
100-
# Return MCP initialize response
101-
response = {
102-
"jsonrpc": "2.0",
103-
"id": request_id,
104-
"result": {
105-
"protocolVersion": "2024-11-05",
106-
"capabilities": {
107-
"tools": {},
88+
if "test-secret-token" in auth_header:
89+
tool_name = "mock_tool_file"
90+
tool_desc = "Mock tool with file-based auth"
91+
elif "my-k8s-token" in auth_header:
92+
tool_name = "mock_tool_k8s"
93+
tool_desc = "Mock tool with Kubernetes token"
94+
elif "my-client-token" in auth_header:
95+
tool_name = "mock_tool_client"
96+
tool_desc = "Mock tool with client-provided token"
97+
98+
# Handle MCP protocol methods using match statement
99+
response: dict = {}
100+
match method:
101+
case "initialize":
102+
# Return MCP initialize response
103+
response = {
104+
"jsonrpc": "2.0",
105+
"id": request_id,
106+
"result": {
107+
"protocolVersion": "2024-11-05",
108+
"capabilities": {
109+
"tools": {},
110+
},
111+
"serverInfo": {
112+
"name": "mock-mcp-server",
113+
"version": "1.0.0",
114+
},
108115
},
109-
"serverInfo": {
110-
"name": "mock-mcp-server",
111-
"version": "1.0.0",
112-
},
113-
},
114-
}
115-
elif method == "tools/list":
116-
# Return list of tools with unique name
117-
response = {
118-
"jsonrpc": "2.0",
119-
"id": request_id,
120-
"result": {
121-
"tools": [
122-
{
123-
"name": tool_name,
124-
"description": tool_desc,
125-
"inputSchema": {
126-
"type": "object",
127-
"properties": {
128-
"message": {
129-
"type": "string",
130-
"description": "Test message",
131-
}
116+
}
117+
118+
case "tools/list":
119+
# Return list of tools with unique name
120+
response = {
121+
"jsonrpc": "2.0",
122+
"id": request_id,
123+
"result": {
124+
"tools": [
125+
{
126+
"name": tool_name,
127+
"description": tool_desc,
128+
"inputSchema": {
129+
"type": "object",
130+
"properties": {
131+
"message": {
132+
"type": "string",
133+
"description": "Test message",
134+
}
135+
},
132136
},
133-
},
134-
}
135-
]
136-
},
137-
}
138-
else:
139-
# Generic success response for other methods
140-
response = {
141-
"jsonrpc": "2.0",
142-
"id": request_id,
143-
"result": {"status": "ok"},
144-
}
137+
}
138+
]
139+
},
140+
}
141+
142+
case "tools/call":
143+
# Handle tool execution
144+
params = request_data.get("params", {})
145+
tool_called = params.get("name", "unknown")
146+
arguments = params.get("arguments", {})
147+
148+
# Build result text
149+
auth_preview = (
150+
auth_header[:50] if len(auth_header) > 50 else auth_header
151+
)
152+
result_text = (
153+
f"Mock tool '{tool_called}' executed successfully "
154+
f"with arguments: {arguments}. Auth used: {auth_preview}..."
155+
)
156+
157+
# Return successful tool execution result
158+
response = {
159+
"jsonrpc": "2.0",
160+
"id": request_id,
161+
"result": {
162+
"content": [
163+
{
164+
"type": "text",
165+
"text": result_text,
166+
}
167+
],
168+
"isError": False,
169+
},
170+
}
171+
172+
case _:
173+
# Generic success response for other methods
174+
response = {
175+
"jsonrpc": "2.0",
176+
"id": request_id,
177+
"result": {"status": "ok"},
178+
}
145179

146180
self.send_response(200)
147181
self.send_header("Content-Type", "application/json")
@@ -273,10 +307,10 @@ def main() -> None:
273307
https_port = http_port + 1
274308

275309
# Create HTTP server
276-
http_server = HTTPServer(("", http_port), MCPMockHandler)
310+
http_server = HTTPServer(("", http_port), MCPMockHandler) # type: ignore[arg-type]
277311

278312
# Create HTTPS server with self-signed certificate
279-
https_server = HTTPServer(("", https_port), MCPMockHandler)
313+
https_server = HTTPServer(("", https_port), MCPMockHandler) # type: ignore[arg-type]
280314

281315
# Generate or load self-signed certificate
282316
script_dir = Path(__file__).parent

docker-compose-library.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ services:
6666
- WATSONX_API_KEY=${WATSONX_API_KEY:-}
6767
# Enable debug logging if needed
6868
- LLAMA_STACK_LOGGING=${LLAMA_STACK_LOGGING:-}
69+
entrypoint: >
70+
/bin/bash -c "
71+
echo 'test-secret-token-123' > /tmp/lightspeed-mcp-test-token &&
72+
/opt/app-root/src/scripts/run.sh
73+
"
6974
healthcheck:
7075
test: ["CMD", "curl", "-f", "http://localhost:8080/liveness"]
7176
interval: 10s # how often to run the check

0 commit comments

Comments
 (0)