feat: scope query param auth to MCP endpoints

Restrict api_key query parameter to /mcp/tools, /mcp/tool/call,
and /mcp/sse only. Updated documentation to reflect query param
usage for ChatGPT UI without header support.
This commit is contained in:
2026-01-29 21:07:37 +01:00
parent b990c6c527
commit 0a2a21cc52
3 changed files with 21 additions and 34 deletions

View File

@@ -77,9 +77,12 @@ API key authentication ENABLED (1 key(s) configured)
# Without key - should fail with 401 # Without key - should fail with 401
curl https://mcp.yourdomain.com/mcp/tools curl https://mcp.yourdomain.com/mcp/tools
# With valid key - should succeed # With valid key (header) - should succeed
curl -H "Authorization: Bearer YOUR_KEY_HERE" \ curl -H "Authorization: Bearer YOUR_KEY_HERE" \
https://mcp.yourdomain.com/mcp/tools https://mcp.yourdomain.com/mcp/tools
# With valid key (query param) - should succeed
curl "https://mcp.yourdomain.com/mcp/tools?api_key=YOUR_KEY_HERE"
``` ```
--- ---

View File

@@ -29,8 +29,7 @@ aegis-gitea-mcp Up 0.0.0.0:8080->8080/tcp
```bash ```bash
# Replace YOUR_API_KEY with your actual key # Replace YOUR_API_KEY with your actual key
curl -H "Authorization: Bearer YOUR_API_KEY" \ curl "https://mcp.yourdomain.com/mcp/tools?api_key=YOUR_API_KEY"
https://mcp.yourdomain.com/mcp/tools
# Expected: JSON response with available tools # Expected: JSON response with available tools
# If error: Check AUTH_SETUP.md troubleshooting # If error: Check AUTH_SETUP.md troubleshooting
@@ -50,22 +49,12 @@ curl -H "Authorization: Bearer YOUR_API_KEY" \
3. **Enter Server Details** 3. **Enter Server Details**
``` ```
Name: AegisGitea MCP Name: AegisGitea MCP
URL: https://mcp.yourdomain.com URL: https://mcp.yourdomain.com?api_key=YOUR_API_KEY_HERE
Type: HTTP/SSE (Server-Sent Events) Type: HTTP/SSE (Server-Sent Events)
Auth: None (or Mixed, leave OAuth fields empty)
``` ```
4. **Add Custom Header** 4. **Save Configuration**
```
Header Name: Authorization
Header Value: Bearer YOUR_API_KEY_HERE
```
**Important:**
- Include the word "Bearer" followed by a space
- Then paste your full 64-character API key
- No quotes around the key
5. **Save Configuration**
### Step 4: Test Connection ### Step 4: Test Connection
@@ -168,18 +157,18 @@ curl https://mcp.yourdomain.com/health
### Issue: "Authentication failed" ### Issue: "Authentication failed"
**Check 1: Authorization header format** **Check 1: MCP Server URL format**
Correct: Correct:
``` ```
Authorization: Bearer a1b2c3d4e5f6g7h8... https://mcp.yourdomain.com?api_key=YOUR_KEY
``` ```
Wrong: Wrong:
``` ```
Authorization: a1b2c3d4... (missing "Bearer ") https://mcp.yourdomain.com (missing api_key)
Authorization: "Bearer a1b2c3d4..." (extra quotes) https://mcp.yourdomain.com?api_key= (empty key)
Authorization:Bearer a1b2c3d4... (missing space after colon) https://mcp.yourdomain.com?api_key=short (too short)
``` ```
**Check 2: Key matches .env** **Check 2: Key matches .env**
@@ -197,7 +186,7 @@ docker-compose logs aegis-mcp | tail -50
Look for: Look for:
- `invalid_api_key` → Key doesn't match - `invalid_api_key` → Key doesn't match
- `missing_api_key` → Header not sent - `missing_api_key` → api_key not provided
- `invalid_key_format` → Key too short - `invalid_key_format` → Key too short
### Issue: "No repositories visible" ### Issue: "No repositories visible"
@@ -211,8 +200,7 @@ Look for:
**Test manually:** **Test manually:**
```bash ```bash
curl -H "Authorization: Bearer YOUR_KEY" \ curl "https://mcp.yourdomain.com/mcp/tool/call?api_key=YOUR_KEY" \
https://mcp.yourdomain.com/mcp/tool/call \
-X POST \ -X POST \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"tool": "list_repositories", "arguments": {}}' -d '{"tool": "list_repositories", "arguments": {}}'
@@ -241,8 +229,7 @@ Too many failed authentication attempts
**Verify tools are registered:** **Verify tools are registered:**
```bash ```bash
curl -H "Authorization: Bearer YOUR_KEY" \ curl "https://mcp.yourdomain.com/mcp/tools?api_key=YOUR_KEY"
https://mcp.yourdomain.com/mcp/tools
``` ```
Should return JSON with tools array. Should return JSON with tools array.
@@ -320,8 +307,7 @@ You can call tools directly via API:
```bash ```bash
# List repositories # List repositories
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \ curl -X POST "https://mcp.yourdomain.com/mcp/tool/call?api_key=YOUR_KEY" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"tool": "list_repositories", "tool": "list_repositories",
@@ -329,8 +315,7 @@ curl -X POST https://mcp.yourdomain.com/mcp/tool/call \
}' }'
# Get file contents # Get file contents
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \ curl -X POST "https://mcp.yourdomain.com/mcp/tool/call?api_key=YOUR_KEY" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"tool": "get_file_contents", "tool": "get_file_contents",
@@ -350,8 +335,7 @@ For automated workflows, you can integrate MCP tools into CI/CD:
# Example GitHub Actions (future enhancement) # Example GitHub Actions (future enhancement)
- name: Sync to Gitea via MCP - name: Sync to Gitea via MCP
run: | run: |
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \ curl -X POST "https://mcp.yourdomain.com/mcp/tool/call?api_key=${{ secrets.MCP_API_KEY }}" \
-H "Authorization: Bearer ${{ secrets.MCP_API_KEY }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{...}' -d '{...}'
``` ```

View File

@@ -74,8 +74,8 @@ async def authenticate_request(request: Request, call_next):
auth_header = request.headers.get("authorization") auth_header = request.headers.get("authorization")
api_key = auth_validator.extract_bearer_token(auth_header) api_key = auth_validator.extract_bearer_token(auth_header)
# Fallback: allow API key via query parameter (for ChatGPT UI without headers) # Fallback: allow API key via query parameter only for MCP endpoints
if not api_key: if not api_key and request.url.path in {"/mcp/tools", "/mcp/tool/call", "/mcp/sse"}:
api_key = request.query_params.get("api_key") api_key = request.query_params.get("api_key")
# Validate API key # Validate API key