Skip to content

Commit 607063d

Browse files
committed
Add configuration for MCP servers, updated documentation, created manual testing support
1 parent 9ead098 commit 607063d

18 files changed

Lines changed: 2009 additions & 68 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
@@ -294,9 +294,20 @@ user_data_collection:
294294

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

297+
**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.
298+
297299
#### Configuring MCP Servers
298300

299-
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`:
301+
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`.
302+
303+
**Basic Configuration Structure:**
304+
305+
Each MCP server requires three fields:
306+
- `name`: Unique identifier for the MCP server
307+
- `provider_id`: MCP provider identification (typically `"model-context-protocol"`)
308+
- `url`: The endpoint where the MCP server is running
309+
310+
**Minimal Example:**
300311

301312
```yaml
302313
mcp_servers:
@@ -306,24 +317,126 @@ mcp_servers:
306317
- name: "git-tools"
307318
provider_id: "model-context-protocol"
308319
url: "http://localhost:3001"
309-
- name: "database-tools"
320+
```
321+
322+
In addition to the basic configuration above, you can configure authentication headers for your MCP servers to securely communicate with services that require credentials.
323+
324+
#### Configuring MCP Server Authentication
325+
326+
Lightspeed Core Stack supports three methods for authenticating with MCP servers, each suited for different use cases:
327+
328+
##### 1. Static Tokens from Files (Recommended for Service Credentials)
329+
330+
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:
331+
332+
```yaml
333+
mcp_servers:
334+
- name: "api-service"
310335
provider_id: "model-context-protocol"
311-
url: "http://localhost:3002"
336+
url: "http://api-service:8080"
337+
authorization_headers:
338+
Authorization: "/var/secrets/api-token" # Path to file containing token
339+
X-API-Key: "/var/secrets/api-key" # Multiple headers supported
312340
```
313341
314-
**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.
342+
The secret files should contain only the header value (tokens are automatically stripped of whitespace):
315343
316-
#### Configuring MCP Headers
344+
```bash
345+
# /var/secrets/api-token
346+
Bearer sk-abc123def456...
317347
318-
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:
348+
# /var/secrets/api-key
349+
my-api-key-value
350+
```
351+
352+
##### 2. Kubernetes Service Account Tokens (For K8s Deployments)
353+
354+
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:
355+
356+
```yaml
357+
mcp_servers:
358+
- name: "k8s-internal-service"
359+
provider_id: "model-context-protocol"
360+
url: "http://internal-mcp.default.svc.cluster.local:8080"
361+
authorization_headers:
362+
Authorization: "kubernetes" # Uses user's k8s token from request auth
363+
```
364+
365+
The user's Kubernetes token is extracted from the incoming request's `Authorization` header and forwarded to the MCP server.
366+
367+
##### 3. Client-Provided Tokens (For Per-User Authentication)
368+
369+
Use the special `"client"` keyword to allow clients to provide custom tokens per-request. This enables user-specific authentication:
370+
371+
```yaml
372+
mcp_servers:
373+
- name: "user-specific-service"
374+
provider_id: "model-context-protocol"
375+
url: "http://user-service:8080"
376+
authorization_headers:
377+
Authorization: "client" # Token provided via MCP-HEADERS
378+
X-User-Token: "client" # Multiple client headers supported
379+
```
380+
381+
Clients then provide tokens via the `MCP-HEADERS` HTTP header:
319382

320383
```bash
321384
curl -X POST "http://localhost:8080/v1/query" \
322385
-H "Content-Type: application/json" \
323-
-H "MCP-HEADERS: {\"filesystem-tools\": {\"Authorization\": \"Bearer token123\"}}" \
324-
-d '{"query": "List files in /tmp"}'
386+
-H "MCP-HEADERS: {\"user-specific-service\": {\"Authorization\": \"Bearer user-token-123\", \"X-User-Token\": \"custom-value\"}}" \
387+
-d '{"query": "Get my data"}'
325388
```
326389

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

328441
### Llama Stack project and configuration
329442

@@ -988,6 +1101,36 @@ The version X.Y.Z indicates:
9881101
* Y is the minor version (backward-compatible), and
9891102
* Z is the patch version (backward-compatible bug fix).
9901103
1104+
# Development Tools
1105+
1106+
Lightspeed Core Stack includes development utilities to help with local testing and debugging. These tools are located in the `dev-tools/` directory.
1107+
1108+
## MCP Mock Server
1109+
1110+
A lightweight mock MCP server for testing MCP integrations locally without requiring real MCP infrastructure.
1111+
1112+
**Quick Start:**
1113+
```bash
1114+
# Start the mock server
1115+
python dev-tools/mcp-mock-server/server.py
1116+
1117+
# Configure Lightspeed Core Stack to use it
1118+
# Add to lightspeed-stack.yaml:
1119+
mcp_servers:
1120+
- name: "mock-test"
1121+
url: "http://localhost:3000"
1122+
authorization_headers:
1123+
Authorization: "/tmp/test-token"
1124+
```
1125+
1126+
**Features:**
1127+
- Test authorization header configuration
1128+
- Debug MCP connectivity issues
1129+
- Inspect captured headers via debug endpoints
1130+
- No external dependencies (pure Python stdlib)
1131+
1132+
For detailed usage instructions, see [`dev-tools/mcp-mock-server/README.md`](dev-tools/mcp-mock-server/README.md).
1133+
9911134
# Konflux
9921135
9931136
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)