Skip to content

Commit 26f3dde

Browse files
committed
Add configuration for MCP servers, updated documentation, created manual testing support
1 parent 9989b7a commit 26f3dde

18 files changed

Lines changed: 2010 additions & 69 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ openai_api_key.txt
180180
# Dev stuff
181181
dev/
182182

183+
# Mock server certificates (auto-generated)
184+
dev-tools/mcp-mock-server/.certs/
185+
183186
# VSCode
184187
.vscode/
185188

README.md

Lines changed: 151 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,20 @@ user_data_collection:
297297

298298
**Note**: The `run.yaml` configuration is currently an implementation detail. In the future, all configuration will be available directly from the lightspeed-core config.
299299

300+
**Important**: Only MCP servers defined in the `lightspeed-stack.yaml` configuration are available to the agents. Tools configured in the llama-stack `run.yaml` are not accessible to lightspeed-core agents.
301+
300302
#### Configuring MCP Servers
301303

302-
MCP (Model Context Protocol) servers provide tools and capabilities to the AI agents. These are configured in the `mcp_servers` section of your `lightspeed-stack.yaml`:
304+
MCP (Model Context Protocol) servers provide tools and capabilities to the AI agents. These are configured in the `mcp_servers` section of your `lightspeed-stack.yaml`.
305+
306+
**Basic Configuration Structure:**
307+
308+
Each MCP server requires three fields:
309+
- `name`: Unique identifier for the MCP server
310+
- `provider_id`: MCP provider identification (typically `"model-context-protocol"`)
311+
- `url`: The endpoint where the MCP server is running
312+
313+
**Minimal Example:**
303314

304315
```yaml
305316
mcp_servers:
@@ -309,24 +320,126 @@ mcp_servers:
309320
- name: "git-tools"
310321
provider_id: "model-context-protocol"
311322
url: "http://localhost:3001"
312-
- name: "database-tools"
323+
```
324+
325+
In addition to the basic configuration above, you can configure authentication headers for your MCP servers to securely communicate with services that require credentials.
326+
327+
#### Configuring MCP Server Authentication
328+
329+
Lightspeed Core Stack supports three methods for authenticating with MCP servers, each suited for different use cases:
330+
331+
##### 1. Static Tokens from Files (Recommended for Service Credentials)
332+
333+
Store authentication tokens in secret files and reference them in your configuration. This is ideal for API keys, service tokens, or any credentials that don't change per-user:
334+
335+
```yaml
336+
mcp_servers:
337+
- name: "api-service"
313338
provider_id: "model-context-protocol"
314-
url: "http://localhost:3002"
339+
url: "http://api-service:8080"
340+
authorization_headers:
341+
Authorization: "/var/secrets/api-token" # Path to file containing token
342+
X-API-Key: "/var/secrets/api-key" # Multiple headers supported
315343
```
316344
317-
**Important**: Only MCP servers defined in the `lightspeed-stack.yaml` configuration are available to the agents. Tools configured in the llama-stack `run.yaml` are not accessible to lightspeed-core agents.
345+
The secret files should contain only the header value (tokens are automatically stripped of whitespace):
318346
319-
#### Configuring MCP Headers
347+
```bash
348+
# /var/secrets/api-token
349+
Bearer sk-abc123def456...
320350
321-
MCP headers allow you to pass authentication tokens, API keys, or other metadata to MCP servers. These are configured **per request** via the `MCP-HEADERS` HTTP header:
351+
# /var/secrets/api-key
352+
my-api-key-value
353+
```
354+
355+
##### 2. Kubernetes Service Account Tokens (For K8s Deployments)
356+
357+
Use the special `"kubernetes"` keyword to automatically use the authenticated user's Kubernetes token. This is perfect for MCP servers running in the same Kubernetes cluster:
358+
359+
```yaml
360+
mcp_servers:
361+
- name: "k8s-internal-service"
362+
provider_id: "model-context-protocol"
363+
url: "http://internal-mcp.default.svc.cluster.local:8080"
364+
authorization_headers:
365+
Authorization: "kubernetes" # Uses user's k8s token from request auth
366+
```
367+
368+
The user's Kubernetes token is extracted from the incoming request's `Authorization` header and forwarded to the MCP server.
369+
370+
##### 3. Client-Provided Tokens (For Per-User Authentication)
371+
372+
Use the special `"client"` keyword to allow clients to provide custom tokens per-request. This enables user-specific authentication:
373+
374+
```yaml
375+
mcp_servers:
376+
- name: "user-specific-service"
377+
provider_id: "model-context-protocol"
378+
url: "http://user-service:8080"
379+
authorization_headers:
380+
Authorization: "client" # Token provided via MCP-HEADERS
381+
X-User-Token: "client" # Multiple client headers supported
382+
```
383+
384+
Clients then provide tokens via the `MCP-HEADERS` HTTP header:
322385

323386
```bash
324387
curl -X POST "http://localhost:8080/v1/query" \
325388
-H "Content-Type: application/json" \
326-
-H "MCP-HEADERS: {\"filesystem-tools\": {\"Authorization\": \"Bearer token123\"}}" \
327-
-d '{"query": "List files in /tmp"}'
389+
-H "MCP-HEADERS: {\"user-specific-service\": {\"Authorization\": \"Bearer user-token-123\", \"X-User-Token\": \"custom-value\"}}" \
390+
-d '{"query": "Get my data"}'
328391
```
329392

393+
**Note**: The `MCP-HEADERS` dictionary is keyed by **server name** (not URL), matching the `name` field in your MCP server configuration.
394+
395+
##### Combining Authentication Methods
396+
397+
You can mix and match authentication methods across different MCP servers, and even combine multiple methods for a single server:
398+
399+
```yaml
400+
mcp_servers:
401+
# Static credentials for public API
402+
- name: "weather-api"
403+
provider_id: "model-context-protocol"
404+
url: "http://weather-api:8080"
405+
authorization_headers:
406+
X-API-Key: "/var/secrets/weather-api-key"
407+
408+
# Kubernetes auth for internal services
409+
- name: "internal-db"
410+
provider_id: "model-context-protocol"
411+
url: "http://db-mcp.cluster.local:8080"
412+
authorization_headers:
413+
Authorization: "kubernetes"
414+
415+
# Mixed: static API key + per-user token
416+
- name: "multi-tenant-service"
417+
provider_id: "model-context-protocol"
418+
url: "http://multi-tenant:8080"
419+
authorization_headers:
420+
X-Service-Key: "/var/secrets/service-key" # Static service credential
421+
Authorization: "client" # User-specific token
422+
```
423+
424+
##### Authentication Method Comparison
425+
426+
| Method | Use Case | Configuration | Token Scope | Example |
427+
|--------|----------|---------------|-------------|---------|
428+
| **Static File** | Service tokens, API keys | File path in config | Global (all users) | `"/var/secrets/token"` |
429+
| **Kubernetes** | K8s service accounts | `"kubernetes"` keyword | Per-user (from auth) | `"kubernetes"` |
430+
| **Client** | User-specific tokens | `"client"` keyword + HTTP header | Per-request | `"client"` |
431+
432+
##### Important: Automatic Server Skipping
433+
434+
**If an MCP server has `authorization_headers` configured but the required tokens cannot be resolved at runtime, the server will be automatically skipped for that request.** This prevents failed authentication attempts to MCP servers.
435+
436+
**Examples:**
437+
- A server with `Authorization: "kubernetes"` will be skipped if the user's request doesn't include a Kubernetes token
438+
- A server with `Authorization: "client"` will be skipped if no `MCP-HEADERS` are provided in the request
439+
- A server with multiple headers will be skipped if **any** required header cannot be resolved
440+
441+
Skipped servers are logged as warnings. Check Lightspeed Core logs to see which servers were skipped and why.
442+
330443

331444
### Llama Stack project and configuration
332445

@@ -995,6 +1108,36 @@ The version X.Y.Z indicates:
9951108
* Y is the minor version (backward-compatible), and
9961109
* Z is the patch version (backward-compatible bug fix).
9971110
1111+
# Development Tools
1112+
1113+
Lightspeed Core Stack includes development utilities to help with local testing and debugging. These tools are located in the `dev-tools/` directory.
1114+
1115+
## MCP Mock Server
1116+
1117+
A lightweight mock MCP server for testing MCP integrations locally without requiring real MCP infrastructure.
1118+
1119+
**Quick Start:**
1120+
```bash
1121+
# Start the mock server
1122+
python dev-tools/mcp-mock-server/server.py
1123+
1124+
# Configure Lightspeed Core Stack to use it
1125+
# Add to lightspeed-stack.yaml:
1126+
mcp_servers:
1127+
- name: "mock-test"
1128+
url: "http://localhost:3000"
1129+
authorization_headers:
1130+
Authorization: "/tmp/test-token"
1131+
```
1132+
1133+
**Features:**
1134+
- Test authorization header configuration
1135+
- Debug MCP connectivity issues
1136+
- Inspect captured headers via debug endpoints
1137+
- No external dependencies (pure Python stdlib)
1138+
1139+
For detailed usage instructions, see [`dev-tools/mcp-mock-server/README.md`](dev-tools/mcp-mock-server/README.md).
1140+
9981141
# Konflux
9991142
10001143
The official image of Lightspeed Core Stack is built on [Konflux](https://konflux-ui.apps.kflux-prd-rh02.0fk9.p1.openshiftapps.com/ns/lightspeed-core-tenant/applications/lightspeed-stack).

dev-tools/MANUAL_TESTING.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Manual Testing Guide for MCP Authorization
2+
3+
This guide walks through testing the MCP server authorization feature using the mock MCP server.
4+
5+
## Prerequisites
6+
7+
### 1. Create Test Secret File
8+
9+
```bash
10+
echo "Bearer test-secret-token-12345" > /tmp/lightspeed-mcp-test-token
11+
```
12+
13+
### 2. Start Mock MCP Server
14+
15+
```bash
16+
# Terminal 1: Start mock MCP server on HTTP port 9000
17+
python3 dev-tools/mcp-mock-server/server.py 9000
18+
```
19+
20+
Verify the server starts and shows the HTTP endpoint.
21+
22+
### 3. Install Library Mode Dependencies
23+
24+
The test configuration uses Llama Stack in library mode, which requires additional dependencies:
25+
26+
```bash
27+
uv pip install emoji langdetect aiosqlite pythainlp asyncpg nltk 'mcp>=1.23.0' matplotlib 'sqlalchemy[asyncio]' chardet scikit-learn faiss-cpu pillow 'datasets>=4.0.0' psycopg2-binary pandas pypdf pymongo redis tree_sitter requests
28+
```
29+
30+
**Note:** These dependencies are needed for Llama Stack's inline providers (agents, vector_io, eval, etc.) to work in library mode. This is a one-time installation.
31+
32+
### 4. Start Lightspeed Core
33+
34+
```bash
35+
# Terminal 2: Start Lightspeed Core with test config (Llama Stack runs as library)
36+
# Make sure OPENAI_API_KEY is set first!
37+
export OPENAI_API_KEY="your-api-key-here"
38+
uv run src/lightspeed_stack.py --config dev-tools/test-configs/mcp-mock-test.yaml
39+
```
40+
41+
Wait for Lightspeed Core to start (you should see "Application startup complete").
42+
43+
**Note:** The test configuration uses Llama Stack in library mode with a dedicated test config (`dev-tools/test-configs/llama-stack-mcp-test.yaml`), so you don't need to start it separately!
44+
45+
---
46+
47+
## Test: All Three Authorization Types in One Request
48+
49+
The test configuration defines **3 MCP servers**, which means **every query will contact all 3 servers** to discover their tools. This allows us to test all three authorization types in a single request.
50+
51+
### Step 1: Make a Query Request
52+
53+
```bash
54+
# Terminal 3: Make test query with all required headers
55+
curl -X POST http://localhost:8080/v1/streaming_query \
56+
-H "Content-Type: application/json" \
57+
-H "Authorization: Bearer my-k8s-token" \
58+
-H 'MCP-HEADERS: {"mock-client-auth": {"Authorization": "Bearer my-client-token"}}' \
59+
-d '{"query": "Test all MCP auth types"}'
60+
```
61+
62+
**What This Tests:**
63+
- **`mock-file-auth`**: Uses static token from `/tmp/lightspeed-mcp-test-token`
64+
- **`mock-k8s-auth`**: Forwards the Kubernetes token from your `Authorization` header
65+
- **`mock-client-auth`**: Uses the client-provided token from `MCP-HEADERS`
66+
67+
### Step 2: Verify All Three Auth Types Worked
68+
69+
Check the mock server terminal output. You should see **6 requests total** (2 per server: initialize + list_tools):
70+
71+
1. **First pair (mock-file-auth)**:
72+
- `Authorization: Bearer test-secret-token-12345`
73+
74+
2. **Second pair (mock-k8s-auth)**:
75+
- `Authorization: Bearer my-k8s-token`
76+
77+
3. **Third pair (mock-client-auth)**:
78+
- `Authorization: Bearer my-client-token`
79+
80+
Or check the debug endpoint:
81+
82+
```bash
83+
curl http://localhost:9000/debug/requests | jq
84+
```
85+
86+
### Expected Result
87+
88+
The mock server should return unique tool names for each auth type:
89+
- `mock_tool_file` - from `mock-file-auth`
90+
- `mock_tool_k8s` - from `mock-k8s-auth`
91+
- `mock_tool_client` - from `mock-client-auth`
92+
93+
Check the Lightspeed Core logs, you should see:
94+
```
95+
DEBUG Configured 3 MCP tools: ['mock-file-auth', 'mock-k8s-auth', 'mock-client-auth']
96+
```
97+
98+
### Step 3: View Request History
99+
100+
```bash
101+
curl http://localhost:9000/debug/requests | jq
102+
```
103+
104+
This will show all 6 requests with their respective Authorization headers.
105+
106+
---
107+
108+
## Additional Test Scenarios
109+
110+
### Test Without Client Headers
111+
112+
Test what happens when you don't provide `MCP-HEADERS`:
113+
114+
```bash
115+
curl -X POST http://localhost:8080/v1/streaming_query \
116+
-H "Content-Type: application/json" \
117+
-H "Authorization: Bearer my-k8s-token" \
118+
-d '{"query": "Test without client headers"}'
119+
```
120+
121+
**Expected Result:**
122+
- `mock-file-auth`: ✅ Works (static token)
123+
- `mock-k8s-auth`: ✅ Works (uses your k8s token)
124+
- `mock-client-auth`: ⚠️ **Skipped** (required auth header not available - see warning in logs)
125+
126+
## Cleanup
127+
128+
Stop all services (Ctrl+C in each terminal):
129+
1. Terminal 1: Mock MCP server
130+
2. Terminal 2: Lightspeed Core (includes Llama Stack)
131+
132+
Remove test secret:
133+
```bash
134+
rm /tmp/lightspeed-mcp-test-token
135+
```
136+
137+
## Troubleshooting
138+
139+
### Missing OPENAI_API_KEY
140+
- Error: "API key not found" or authentication errors
141+
- Solution: Set the environment variable before starting Lightspeed Core
142+
```bash
143+
export OPENAI_API_KEY="your-api-key-here"
144+
```
145+
146+
### Lightspeed Core startup errors
147+
- Check that `dev-tools/test-configs/llama-stack-mcp-test.yaml` exists and is valid
148+
- Verify OPENAI_API_KEY is set
149+
- Check the logs for specific error messages
150+
151+
### Mock server not receiving requests
152+
- Verify mock server is running: `curl http://localhost:9000/debug/headers`
153+
- Check Lightspeed Core logs for errors
154+
- Ensure config file path is correct
155+
156+
### Headers not captured
157+
- Check mock server output for incoming requests
158+
- Verify the secret file exists and is readable
159+
- Check that the MCP server name matches in config and MCP-HEADERS
160+
161+
### Connection refused
162+
- Ensure all services are running on expected ports (9000, 8080)
163+
- Check firewall settings

dev-tools/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Development Tools
2+
3+
This directory contains utilities and tools for local development and testing of Lightspeed Core Stack.
4+
5+
## Available Tools
6+
7+
### MCP Mock Server
8+
9+
A lightweight mock Model Context Protocol (MCP) server for testing MCP integrations and authorization headers locally.
10+
11+
**Location:** `dev-tools/mcp-mock-server/`
12+
13+
**Use Cases:**
14+
- Test MCP server authentication headers without real MCP infrastructure
15+
- Debug authorization header configuration
16+
- Local development of MCP-related features
17+
- Validate MCP server connectivity
18+
19+
See [`mcp-mock-server/README.md`](mcp-mock-server/README.md) for usage instructions.
20+
21+
## Testing MCP Integration with Lightspeed Core
22+
23+
For comprehensive step-by-step instructions on manually testing MCP authorization, see [`MANUAL_TESTING.md`](MANUAL_TESTING.md).
24+
25+
## Adding New Tools
26+
27+
When adding new development tools to this directory:
28+
1. Create a subdirectory for the tool
29+
2. Include a README.md explaining what it does and how to use it
30+
3. Update this file to list the new tool
31+
4. Keep tools self-contained with their own dependencies (if any)
32+

0 commit comments

Comments
 (0)