Initial commit
This commit is contained in:
221
skills/mcpproxy-debug/SKILL.md
Normal file
221
skills/mcpproxy-debug/SKILL.md
Normal file
@@ -0,0 +1,221 @@
|
||||
---
|
||||
name: mcpproxy-debug
|
||||
description: This skill should be used when debugging, configuring, or troubleshooting MCPProxy (smart-mcp-proxy/mcpproxy-go). It provides workflows for checking server status, diagnosing connection failures, fixing configuration issues, and understanding Docker isolation behavior.
|
||||
---
|
||||
|
||||
# MCPProxy Debug
|
||||
|
||||
## Overview
|
||||
|
||||
MCPProxy is a Go-based smart proxy for Model Context Protocol (MCP) servers. This skill provides the capability to diagnose and fix MCPProxy issues systematically.
|
||||
|
||||
**Use this skill when:**
|
||||
- MCPProxy server won't start or connect
|
||||
- MCP servers show `connected: false` in status
|
||||
- Docker isolation is causing failures
|
||||
- Configuration changes aren't working
|
||||
- Need to verify MCPProxy is running correctly
|
||||
|
||||
**Do NOT use this skill for:**
|
||||
- Using MCPProxy tools normally → Use `dev-tools:using-mcpproxy-tools` instead
|
||||
|
||||
## Core Architecture (Quick Reference)
|
||||
|
||||
- **Core Server**: `mcpproxy` process at `127.0.0.1:8080` (default)
|
||||
- **Config**: `~/.mcpproxy/mcp_config.json`
|
||||
- **Logs**: `~/Library/Logs/mcpproxy/` (macOS) or `~/.mcpproxy/logs/` (Linux)
|
||||
- **Database**: `~/.mcpproxy/config.db` (locked when running)
|
||||
|
||||
## Navigation Map - Start Here
|
||||
|
||||
Use this decision tree to find the right reference:
|
||||
|
||||
```
|
||||
Problem: Where do I look?
|
||||
├─ Server won't connect / shows errors
|
||||
│ └─ Read: references/connection-failures.md
|
||||
│
|
||||
├─ Docker isolation issues / "not a TTY" errors
|
||||
│ └─ Read: references/docker-isolation-guide.md
|
||||
│
|
||||
├─ Adding/configuring servers / config file questions
|
||||
│ └─ Read: references/configuration-patterns.md
|
||||
│
|
||||
└─ Need detailed examples from real debugging sessions
|
||||
└─ Read: references/debugging-examples.md (already exists)
|
||||
```
|
||||
|
||||
**Progressive disclosure principle**: Load only what you need. Start with the quick checks below. If those don't solve it, read the specific reference file.
|
||||
|
||||
## Quick Health Check (Do This First)
|
||||
|
||||
```bash
|
||||
# 1. Is mcpproxy running?
|
||||
ps aux | grep mcpproxy | grep -v grep
|
||||
|
||||
# 2. Get API key
|
||||
grep '"api_key"' ~/.mcpproxy/mcp_config.json
|
||||
|
||||
# 3. Check server status
|
||||
curl -s "http://127.0.0.1:8080/api/v1/servers?apikey=YOUR_KEY" | python3 -m json.tool
|
||||
|
||||
# 4. Check for recent errors
|
||||
tail -50 ~/Library/Logs/mcpproxy/main.log | grep -i error
|
||||
```
|
||||
|
||||
**Key status fields to check:**
|
||||
- `connected`: Boolean - is the server connected?
|
||||
- `status`: String - current state (connecting, ready, error)
|
||||
- `last_error`: String - most recent error message
|
||||
- `tool_count`: Number - how many tools available
|
||||
|
||||
**If status looks bad** → Read the appropriate reference file from Navigation Map above.
|
||||
|
||||
## Top 3 Common Issues (One-Line Fixes)
|
||||
|
||||
### 1. "the input device is not a TTY" (Docker servers)
|
||||
|
||||
**Fix:** Add `"isolation": {"enabled": false}` to the Docker-based server config.
|
||||
|
||||
**Why:** Docker isolation wraps Docker commands in Docker (Docker-in-Docker). See `references/docker-isolation-guide.md` for details.
|
||||
|
||||
### 2. "unexpected argument found" (uvx/npx servers)
|
||||
|
||||
**Fix:** Put package name as first arg: `["mcp-server-name", "--arg", "value"]`
|
||||
|
||||
**Why:** Package managers need package name first, then its arguments. See `references/configuration-patterns.md` for examples.
|
||||
|
||||
### 3. "Invalid or missing API key" after restart
|
||||
|
||||
**Fix:** Check `echo $MCPPROXY_API_KEY` - environment variable overrides config file.
|
||||
|
||||
**Why:** Tray app may set `MCPPROXY_API_KEY`. Get current key from logs: `grep "api_key_prefix" ~/Library/Logs/mcpproxy/main.log | tail -1`
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Restart MCPProxy
|
||||
```bash
|
||||
pkill mcpproxy
|
||||
sleep 2
|
||||
open /Applications/mcpproxy.app # macOS
|
||||
# OR
|
||||
mcpproxy & # Linux/headless
|
||||
```
|
||||
|
||||
### Check Specific Server Logs
|
||||
```bash
|
||||
# See server-specific log (most revealing for connection issues)
|
||||
tail -50 ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
|
||||
# Find errors in server log
|
||||
grep -i "error\|stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
```
|
||||
|
||||
### Trigger Config Reload
|
||||
```bash
|
||||
# Touch config to trigger file watcher
|
||||
touch ~/.mcpproxy/mcp_config.json
|
||||
|
||||
# Verify reload happened
|
||||
grep -i "config.*reload" ~/Library/Logs/mcpproxy/main.log | tail -3
|
||||
```
|
||||
|
||||
### Docker Container Check
|
||||
```bash
|
||||
# List MCPProxy containers
|
||||
docker ps | grep mcpproxy
|
||||
|
||||
# Check container logs
|
||||
docker logs CONTAINER_NAME
|
||||
```
|
||||
|
||||
## Helper Scripts
|
||||
|
||||
Located in `scripts/` directory:
|
||||
|
||||
- **`check_status.sh`** - Quick health check of mcpproxy and all servers
|
||||
- **`get_api_key.sh`** - Extract current API key from config or logs
|
||||
- **`diagnose_server.sh SERVER_NAME`** - Comprehensive server diagnosis with error pattern detection
|
||||
- **`compare_servers.sh WORKING BROKEN`** - Compare configs and status to find differences
|
||||
|
||||
Usage: `~/.claude/skills/mcpproxy-debug/scripts/SCRIPT_NAME.sh`
|
||||
|
||||
## References - Deep Dives
|
||||
|
||||
Load these on-demand when quick fixes don't solve the problem:
|
||||
|
||||
### `references/connection-failures.md`
|
||||
**When to read:** Server shows `connected: false` or connection errors
|
||||
|
||||
**Contains:**
|
||||
- Step-by-step connection diagnosis workflow
|
||||
- Common error patterns with detailed explanations
|
||||
- "context deadline exceeded" root cause analysis
|
||||
- Server-specific log investigation techniques
|
||||
- Real patterns: uvx args, Docker TTY, missing packages
|
||||
|
||||
### `references/docker-isolation-guide.md`
|
||||
**When to read:** Docker isolation enabled and servers failing, or "not a TTY" errors
|
||||
|
||||
**Contains:**
|
||||
- How Docker isolation works in MCPProxy
|
||||
- Configuration options and defaults
|
||||
- Docker-in-Docker prevention strategies
|
||||
- Colima context support
|
||||
- When to disable isolation (with examples)
|
||||
- Volume mounting for file access
|
||||
|
||||
### `references/configuration-patterns.md`
|
||||
**When to read:** Adding new servers or fixing config issues
|
||||
|
||||
**Contains:**
|
||||
- Complete config structures for all server types
|
||||
- uvx/npx package manager patterns
|
||||
- Docker-based server patterns
|
||||
- HTTP/SSE server patterns
|
||||
- Common configuration mistakes with fixes
|
||||
- Environment variable handling
|
||||
- Quarantine settings
|
||||
|
||||
### `references/debugging-examples.md` (already exists)
|
||||
**When to read:** Need detailed walkthroughs from real debugging sessions
|
||||
|
||||
**Contains:**
|
||||
- Real-world case studies
|
||||
- Complete diagnostic workflows with root cause analysis
|
||||
- Pattern recognition guides for complex failure modes
|
||||
|
||||
## When to Load References
|
||||
|
||||
**Don't load references preemptively.** Use this workflow:
|
||||
|
||||
1. Run Quick Health Check (above)
|
||||
2. Identify the problem category
|
||||
3. Check Top 3 Common Issues for one-line fix
|
||||
4. If not solved → Read the specific reference file from Navigation Map
|
||||
5. Follow the detailed workflow in that reference
|
||||
|
||||
**Why:** Loading all references upfront = 4,000+ tokens of mostly irrelevant content. Progressive disclosure keeps context lean and relevant.
|
||||
|
||||
## Environment Variables Reference
|
||||
|
||||
- `MCPPROXY_API_KEY` - Set API key (overrides config file)
|
||||
- `MCPPROXY_LISTEN` - Override bind address (e.g., `:8080`)
|
||||
- `MCPPROXY_DEBUG` - Enable debug mode
|
||||
- `HEADLESS` - Run without launching browser
|
||||
|
||||
**API Key Priority:** ENV var > config file > auto-generated
|
||||
|
||||
## Summary
|
||||
|
||||
This skill is a **navigation map**, not a documentation dump.
|
||||
|
||||
**Start with:**
|
||||
1. Quick Health Check
|
||||
2. Top 3 Common Issues
|
||||
|
||||
**If not solved:**
|
||||
3. Use Navigation Map to find the right reference
|
||||
4. Read only that reference file
|
||||
|
||||
**Result:** Fast diagnosis with minimal context overhead. Load ~1,400 tokens initially, then ~1,600 more only when needed for specific problems.
|
||||
641
skills/mcpproxy-debug/references/configuration-patterns.md
Normal file
641
skills/mcpproxy-debug/references/configuration-patterns.md
Normal file
@@ -0,0 +1,641 @@
|
||||
# Configuration Patterns - Complete Reference
|
||||
|
||||
**When to use this reference:** Adding new MCP servers to MCPProxy or fixing configuration issues.
|
||||
|
||||
This reference provides complete configuration structures for all server types with detailed explanations.
|
||||
|
||||
## Configuration File Location
|
||||
|
||||
`~/.mcpproxy/mcp_config.json`
|
||||
|
||||
**Important:** After editing, trigger reload:
|
||||
```bash
|
||||
touch ~/.mcpproxy/mcp_config.json
|
||||
# OR restart mcpproxy
|
||||
pkill mcpproxy && open /Applications/mcpproxy.app
|
||||
```
|
||||
|
||||
## Complete Configuration Patterns
|
||||
|
||||
### Pattern 1: uvx/npx Servers (Package Managers)
|
||||
|
||||
**Key rule:** Package name MUST be first argument.
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"server-name": {
|
||||
"protocol": "stdio",
|
||||
"command": "uvx", // or "npx"
|
||||
"args": [
|
||||
"package-name", // CRITICAL: Package name FIRST
|
||||
"--arg1", // Then package arguments
|
||||
"value1",
|
||||
"--arg2",
|
||||
"value2"
|
||||
],
|
||||
"env": {
|
||||
// Optional environment variables
|
||||
"API_KEY": "secret",
|
||||
"DEBUG": "true"
|
||||
},
|
||||
"working_dir": "/path/to/dir", // Optional working directory
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real examples:**
|
||||
|
||||
#### Time Server with Timezone
|
||||
```json
|
||||
{
|
||||
"time": {
|
||||
"protocol": "stdio",
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"mcp-server-time",
|
||||
"--local-timezone",
|
||||
"America/New_York"
|
||||
],
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### SQLite Server with Database Path
|
||||
```json
|
||||
{
|
||||
"sqlite": {
|
||||
"protocol": "stdio",
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"mcp-server-sqlite",
|
||||
"--db-path",
|
||||
"/Users/username/data/mydb.sqlite"
|
||||
],
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Filesystem Server with Paths
|
||||
```json
|
||||
{
|
||||
"filesystem": {
|
||||
"protocol": "stdio",
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"/Users/username/workspace",
|
||||
"/Users/username/Documents"
|
||||
],
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Common mistakes:**
|
||||
```json
|
||||
// ❌ WRONG - Arguments before package name
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["--local-timezone", "America/New_York"]
|
||||
// Error: "unexpected argument '--local-timezone' found"
|
||||
}
|
||||
|
||||
// ✅ CORRECT - Package name first
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-time", "--local-timezone", "America/New_York"]
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Docker-Based Servers
|
||||
|
||||
**Key rules:**
|
||||
1. Use `-i` (NOT `-it`) for stdin pipe
|
||||
2. ALWAYS disable isolation to prevent Docker-in-Docker
|
||||
|
||||
```json
|
||||
{
|
||||
"docker-server": {
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i", // CRITICAL: -i only, not -it
|
||||
"--rm", // Clean up container after exit
|
||||
"-e", "VAR_NAME", // Pass environment variables
|
||||
"image:tag", // Docker image
|
||||
"subcommand" // Optional: server entrypoint
|
||||
],
|
||||
"env": {
|
||||
"VAR_NAME": "value" // Values for -e flags
|
||||
},
|
||||
"isolation": {
|
||||
"enabled": false // CRITICAL: Disable to prevent Docker-in-Docker
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real examples:**
|
||||
|
||||
#### Basic Docker MCP Server
|
||||
```json
|
||||
{
|
||||
"docker-mcp": {
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"ghcr.io/example/mcp-server:latest"
|
||||
],
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Docker Server with Environment Variables
|
||||
```json
|
||||
{
|
||||
"api-server": {
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e", "API_KEY",
|
||||
"-e", "API_URL",
|
||||
"mycompany/api-mcp:v1.0"
|
||||
],
|
||||
"env": {
|
||||
"API_KEY": "sk-xxxx",
|
||||
"API_URL": "https://api.example.com"
|
||||
},
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Docker Server with Volume Mounts
|
||||
```json
|
||||
{
|
||||
"file-processor": {
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-v", "/Users/username/data:/data:ro",
|
||||
"mycompany/file-mcp:latest",
|
||||
"--data-dir", "/data"
|
||||
],
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Common mistakes:**
|
||||
```json
|
||||
// ❌ WRONG - Using -it flags
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-it", "--rm", "image:tag"]
|
||||
// Error: "the input device is not a TTY"
|
||||
}
|
||||
|
||||
// ❌ WRONG - Isolation enabled
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image:tag"],
|
||||
"isolation": {"enabled": true}
|
||||
// Error: Docker-in-Docker, "not a TTY"
|
||||
}
|
||||
|
||||
// ✅ CORRECT - Use -i only, disable isolation
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image:tag"],
|
||||
"isolation": {"enabled": false}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: HTTP/SSE Servers
|
||||
|
||||
For servers accessed via HTTP or Server-Sent Events.
|
||||
|
||||
```json
|
||||
{
|
||||
"http-server": {
|
||||
"protocol": "http", // or "sse"
|
||||
"url": "https://api.example.com/mcp",
|
||||
"headers": {
|
||||
// Optional authentication headers
|
||||
"Authorization": "Bearer token",
|
||||
"X-API-Key": "secret"
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real examples:**
|
||||
|
||||
#### HTTP Server with Bearer Token
|
||||
```json
|
||||
{
|
||||
"remote-api": {
|
||||
"protocol": "http",
|
||||
"url": "https://mcp.example.com/v1",
|
||||
"headers": {
|
||||
"Authorization": "Bearer sk-xxxxxxxxxxxx"
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### SSE Server with API Key
|
||||
```json
|
||||
{
|
||||
"streaming-api": {
|
||||
"protocol": "sse",
|
||||
"url": "https://stream.example.com/mcp",
|
||||
"headers": {
|
||||
"X-API-Key": "api-key-here"
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### HTTP Server Without Authentication
|
||||
```json
|
||||
{
|
||||
"public-api": {
|
||||
"protocol": "http",
|
||||
"url": "http://localhost:3000/mcp",
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Local Command Servers
|
||||
|
||||
For locally installed commands (not uvx/npx).
|
||||
|
||||
```json
|
||||
{
|
||||
"local-server": {
|
||||
"protocol": "stdio",
|
||||
"command": "/usr/local/bin/mcp-server", // Full path or command in PATH
|
||||
"args": [
|
||||
"--config", "/path/to/config.json",
|
||||
"--verbose"
|
||||
],
|
||||
"env": {
|
||||
"HOME": "/Users/username",
|
||||
"PYTHONPATH": "/path/to/modules"
|
||||
},
|
||||
"working_dir": "/Users/username/workspace",
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Real examples:**
|
||||
|
||||
#### Python Script as Server
|
||||
```json
|
||||
{
|
||||
"custom-python": {
|
||||
"protocol": "stdio",
|
||||
"command": "python",
|
||||
"args": [
|
||||
"/Users/username/mcp-servers/my_server.py",
|
||||
"--config", "production"
|
||||
],
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1"
|
||||
},
|
||||
"working_dir": "/Users/username/mcp-servers",
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Node.js Script as Server
|
||||
```json
|
||||
{
|
||||
"custom-node": {
|
||||
"protocol": "stdio",
|
||||
"command": "node",
|
||||
"args": [
|
||||
"/Users/username/mcp-servers/server.js"
|
||||
],
|
||||
"env": {
|
||||
"NODE_ENV": "production"
|
||||
},
|
||||
"working_dir": "/Users/username/mcp-servers",
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Configuration File Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"api_key": "mcpproxy-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"listen": "127.0.0.1:8080",
|
||||
"docker_isolation": {
|
||||
"enabled": true,
|
||||
"memory_limit": "512m",
|
||||
"cpu_limit": "1.0",
|
||||
"timeout": "30s",
|
||||
"network_mode": "bridge",
|
||||
"default_images": {
|
||||
"uvx": "python:3.11",
|
||||
"npx": "node:20",
|
||||
"python": "python:3.11",
|
||||
"node": "node:20"
|
||||
}
|
||||
},
|
||||
"mcpServers": {
|
||||
"server1": {
|
||||
"protocol": "stdio",
|
||||
"command": "uvx",
|
||||
"args": ["package-name"],
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
},
|
||||
"server2": {
|
||||
"protocol": "http",
|
||||
"url": "https://api.example.com",
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Common Configuration Mistakes
|
||||
|
||||
### 1. Missing Package Name (uvx/npx)
|
||||
```json
|
||||
// ❌ WRONG
|
||||
{"command": "uvx", "args": ["--arg", "value"]}
|
||||
|
||||
// ✅ CORRECT
|
||||
{"command": "uvx", "args": ["package-name", "--arg", "value"]}
|
||||
```
|
||||
|
||||
### 2. Wrong Docker Flags
|
||||
```json
|
||||
// ❌ WRONG - Using -it
|
||||
{"command": "docker", "args": ["run", "-it", "--rm", "image"]}
|
||||
|
||||
// ✅ CORRECT - Using -i only
|
||||
{"command": "docker", "args": ["run", "-i", "--rm", "image"]}
|
||||
```
|
||||
|
||||
### 3. Docker Isolation Not Disabled
|
||||
```json
|
||||
// ❌ WRONG - Isolation enabled for Docker
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image"],
|
||||
"isolation": {"enabled": true} // Docker-in-Docker!
|
||||
}
|
||||
|
||||
// ✅ CORRECT - Isolation disabled
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image"],
|
||||
"isolation": {"enabled": false}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Wrong Protocol for Server Type
|
||||
```json
|
||||
// ❌ WRONG - Using stdio for URL
|
||||
{"protocol": "stdio", "url": "https://api.example.com"}
|
||||
|
||||
// ❌ WRONG - Using http for command
|
||||
{"protocol": "http", "command": "uvx", "args": ["package"]}
|
||||
|
||||
// ✅ CORRECT - Match protocol to type
|
||||
{"protocol": "http", "url": "https://api.example.com"}
|
||||
{"protocol": "stdio", "command": "uvx", "args": ["package"]}
|
||||
```
|
||||
|
||||
### 5. Server Still Quarantined
|
||||
```json
|
||||
// ❌ WRONG - Quarantine prevents execution
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["package"],
|
||||
"quarantined": true // Tools return security analysis!
|
||||
}
|
||||
|
||||
// ✅ CORRECT - Set to false to use tools
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["package"],
|
||||
"quarantined": false
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Invalid JSON
|
||||
```json
|
||||
// ❌ WRONG - Trailing comma
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["package"],
|
||||
"enabled": true, // Trailing comma breaks JSON
|
||||
}
|
||||
|
||||
// ✅ CORRECT - No trailing comma
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["package"],
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Built-in Environment Variables
|
||||
|
||||
MCPProxy automatically provides:
|
||||
- `HOME` - User's home directory
|
||||
- `PATH` - System PATH
|
||||
|
||||
### Custom Environment Variables
|
||||
|
||||
Add via `env` field:
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"API_KEY": "secret",
|
||||
"DEBUG": "true",
|
||||
"CUSTOM_VAR": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variable Priority
|
||||
|
||||
For Docker servers:
|
||||
1. Variables in Docker args (`-e VAR=value`)
|
||||
2. Variables in `env` field passed via `-e VAR` (value from env)
|
||||
3. Host environment (if not overridden)
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run", "-i", "--rm",
|
||||
"-e", "API_KEY", // Value from env field
|
||||
"-e", "DEBUG=true", // Value in args
|
||||
"image:tag"
|
||||
],
|
||||
"env": {
|
||||
"API_KEY": "secret" // Used by -e API_KEY above
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Quarantine Settings
|
||||
|
||||
New servers are automatically quarantined for security. To use them:
|
||||
|
||||
```json
|
||||
{
|
||||
"quarantined": false // Set to false to enable tool execution
|
||||
}
|
||||
```
|
||||
|
||||
**What quarantine does:**
|
||||
- `quarantined: true` - Tools return security analysis instead of executing
|
||||
- `quarantined: false` - Tools execute normally
|
||||
|
||||
**Best practice:** Review new servers before setting `quarantined: false`.
|
||||
|
||||
## Docker Isolation Configuration
|
||||
|
||||
See `references/docker-isolation-guide.md` for detailed Docker isolation configuration.
|
||||
|
||||
**Quick reference:**
|
||||
|
||||
```json
|
||||
{
|
||||
// Global settings
|
||||
"docker_isolation": {
|
||||
"enabled": true, // Master switch
|
||||
"memory_limit": "512m", // Default memory per container
|
||||
"cpu_limit": "1.0", // Default CPU per container
|
||||
"network_mode": "bridge" // Default network mode
|
||||
},
|
||||
|
||||
// Per-server override
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"isolation": {
|
||||
"enabled": false, // Disable isolation
|
||||
// OR customize:
|
||||
"enabled": true,
|
||||
"image": "python:3.12",
|
||||
"memory_limit": "1g",
|
||||
"cpu_limit": "2.0",
|
||||
"network_mode": "host"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verification After Configuration
|
||||
|
||||
After adding or modifying server configuration:
|
||||
|
||||
```bash
|
||||
# 1. Trigger reload
|
||||
touch ~/.mcpproxy/mcp_config.json
|
||||
|
||||
# 2. Wait for connection (30 seconds)
|
||||
sleep 30
|
||||
|
||||
# 3. Check server status
|
||||
curl -s "http://127.0.0.1:8080/api/v1/servers?apikey=YOUR_KEY" | \
|
||||
python3 -m json.tool | grep -A 10 '"name": "SERVER_NAME"'
|
||||
|
||||
# 4. Verify connection
|
||||
# Look for:
|
||||
# "connected": true
|
||||
# "status": "ready"
|
||||
# "tool_count": > 0
|
||||
|
||||
# 5. If not connected, check logs
|
||||
tail -50 ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
## Configuration Checklist
|
||||
|
||||
When adding a new server, verify:
|
||||
|
||||
- [ ] JSON is valid (no trailing commas, quotes matched)
|
||||
- [ ] Protocol matches server type (stdio/http/sse)
|
||||
- [ ] For uvx/npx: Package name is first argument
|
||||
- [ ] For Docker: Using `-i` not `-it`
|
||||
- [ ] For Docker: Isolation disabled (`"enabled": false`)
|
||||
- [ ] `enabled` is set to `true`
|
||||
- [ ] `quarantined` is set to `false` (after review)
|
||||
- [ ] Environment variables defined if needed
|
||||
- [ ] Config file reloaded (touch or restart)
|
||||
- [ ] Server status shows `connected: true` (wait 30s)
|
||||
|
||||
If server won't connect, see `references/connection-failures.md` for debugging.
|
||||
|
||||
## Summary
|
||||
|
||||
Configuration patterns vary by server type. The most common mistakes are:
|
||||
1. Missing package name for uvx/npx
|
||||
2. Using `-it` instead of `-i` for Docker
|
||||
3. Leaving isolation enabled for Docker-based servers
|
||||
4. Leaving servers quarantined
|
||||
|
||||
Follow the pattern for your server type, verify with the checklist, and check logs if it doesn't connect.
|
||||
372
skills/mcpproxy-debug/references/connection-failures.md
Normal file
372
skills/mcpproxy-debug/references/connection-failures.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# Connection Failures - Detailed Diagnosis
|
||||
|
||||
**When to use this reference:** Server shows `connected: false` or has connection errors in status API.
|
||||
|
||||
This reference provides step-by-step workflows for diagnosing why an MCP server won't connect through MCPProxy.
|
||||
|
||||
## Systematic Diagnosis Workflow
|
||||
|
||||
### Step 1: Check Server-Specific Logs
|
||||
|
||||
Server-specific logs contain the most revealing information, especially stderr output from the failing server.
|
||||
|
||||
```bash
|
||||
# List all server logs (most recent first)
|
||||
ls -lhrt ~/Library/Logs/mcpproxy/server-*.log | tail -10
|
||||
|
||||
# Check specific server log (last 50 lines)
|
||||
tail -50 ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
|
||||
# Find errors in server log
|
||||
grep -i "error\|failed\|stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
|
||||
# Focus on stderr (most revealing)
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Error messages in stderr output
|
||||
- Stack traces indicating crashes
|
||||
- Missing dependencies or packages
|
||||
- Permission errors
|
||||
- Network connection failures
|
||||
|
||||
### Step 2: Identify Error Patterns
|
||||
|
||||
Most connection failures follow recognizable patterns. Match the error message to the pattern below.
|
||||
|
||||
## Common Error Patterns
|
||||
|
||||
### Pattern: "unexpected argument found"
|
||||
|
||||
**Example stderr:**
|
||||
```
|
||||
error: unexpected argument '--local-timezone' found
|
||||
```
|
||||
|
||||
**Root cause:** Package manager (uvx/npx) received server arguments before package name.
|
||||
|
||||
**Commands affected:** `uvx`, `npx`, `yarn dlx`, `bunx`
|
||||
|
||||
**How it happens:**
|
||||
```json
|
||||
// WRONG - Arguments passed to uvx instead of the package
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": ["--local-timezone", "America/New_York"]
|
||||
}
|
||||
|
||||
// Package manager sees: uvx --local-timezone America/New_York
|
||||
// And thinks: "--local-timezone is not a uvx option!"
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
```json
|
||||
// CORRECT - Package name first, then its arguments
|
||||
{
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"mcp-server-time", // Package name FIRST
|
||||
"--local-timezone", // Then package's arguments
|
||||
"America/New_York"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Verification:**
|
||||
```bash
|
||||
# After fixing config, check server log for successful connection
|
||||
tail -20 ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | grep -i "connected\|ready"
|
||||
```
|
||||
|
||||
### Pattern: "the input device is not a TTY"
|
||||
|
||||
**Example stderr:**
|
||||
```
|
||||
the input device is not a TTY
|
||||
```
|
||||
|
||||
**Root causes:**
|
||||
|
||||
#### Cause 1: Using `-it` with Docker
|
||||
|
||||
MCPProxy communicates via stdio pipes, not terminal TTY sessions. Using `-it` with Docker tries to allocate a TTY, which fails in pipe mode.
|
||||
|
||||
```json
|
||||
// WRONG - Docker with -it flags
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-it", "--rm", "image:tag"]
|
||||
}
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
```json
|
||||
// CORRECT - Only -i for stdin pipe
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image:tag"]
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause 2: Docker Isolation on Docker-based Server
|
||||
|
||||
MCPProxy's Docker isolation feature wraps commands in Docker containers. When the command itself is Docker, you get Docker-in-Docker, which causes TTY issues.
|
||||
|
||||
```json
|
||||
// WRONG - Docker isolation wrapping a Docker command
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image:tag"],
|
||||
"isolation": {
|
||||
"enabled": true // This wraps Docker in Docker!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
```json
|
||||
// CORRECT - Disable isolation for Docker commands
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "image:tag"],
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why this happens:** MCPProxy auto-detects Docker commands and should skip isolation, but explicit configuration is more reliable.
|
||||
|
||||
**Verification:**
|
||||
```bash
|
||||
# Check if isolation was applied
|
||||
grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
|
||||
|
||||
# Verify no Docker containers running for this server
|
||||
docker ps | grep mcpproxy-SERVER_NAME
|
||||
```
|
||||
|
||||
### Pattern: "context deadline exceeded"
|
||||
|
||||
**Example error:**
|
||||
```
|
||||
last_error: "context deadline exceeded"
|
||||
status: "error"
|
||||
```
|
||||
|
||||
**Root cause:** Server failed to initialize within timeout (usually 30 seconds).
|
||||
|
||||
**Common reasons:**
|
||||
|
||||
1. **Underlying error hidden** - Check stderr for the real error:
|
||||
```bash
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
```
|
||||
|
||||
2. **Missing package name** (uvx/npx) - Look for "unexpected argument":
|
||||
```bash
|
||||
grep "unexpected argument" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
3. **Docker TTY issue** - Look for "not a TTY":
|
||||
```bash
|
||||
grep "TTY" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
4. **Docker image pull failed**:
|
||||
```bash
|
||||
grep -i "pull\|not found" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
5. **Server crashed during startup**:
|
||||
```bash
|
||||
grep -i "stack trace\|panic\|exception" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
6. **Missing environment variables**:
|
||||
```bash
|
||||
grep -i "missing\|required.*variable" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
7. **Network issues** (HTTP servers):
|
||||
```bash
|
||||
grep -i "connection refused\|timeout" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
```
|
||||
|
||||
**Investigation workflow:**
|
||||
|
||||
```bash
|
||||
# 1. Check if process even started
|
||||
grep "Starting connection\|Docker isolation setup" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
|
||||
|
||||
# 2. Check stderr for the real error
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
|
||||
# 3. If Docker isolation enabled, check container logs
|
||||
docker ps -a | grep mcpproxy-SERVER_NAME
|
||||
docker logs CONTAINER_ID
|
||||
|
||||
# 4. Check Docker command being executed
|
||||
grep "docker_run_args" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -3
|
||||
```
|
||||
|
||||
**Fix:** Address the underlying error found in stderr.
|
||||
|
||||
### Pattern: "database is locked"
|
||||
|
||||
**Example error:**
|
||||
```
|
||||
ERROR: database is locked
|
||||
```
|
||||
|
||||
**Root cause:** Another mcpproxy instance is running and has locked `~/.mcpproxy/config.db`.
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Kill all mcpproxy instances
|
||||
pkill mcpproxy
|
||||
|
||||
# Wait for processes to clean up
|
||||
sleep 2
|
||||
|
||||
# Verify no mcpproxy processes remain
|
||||
ps aux | grep mcpproxy | grep -v grep
|
||||
|
||||
# Restart mcpproxy
|
||||
open /Applications/mcpproxy.app # macOS
|
||||
# OR
|
||||
mcpproxy & # Linux/headless
|
||||
```
|
||||
|
||||
**Prevention:** Always use `pkill mcpproxy` before starting a new instance.
|
||||
|
||||
### Pattern: "transport error" / "EOF"
|
||||
|
||||
**Example error:**
|
||||
```
|
||||
last_error: "transport error: EOF"
|
||||
```
|
||||
|
||||
**Root cause:** Server process exited unexpectedly or closed stdio pipes.
|
||||
|
||||
**Investigation:**
|
||||
```bash
|
||||
# Check if server crashed
|
||||
grep -i "exit\|crash\|terminated" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -10
|
||||
|
||||
# Look for error messages before EOF
|
||||
grep -B 20 "EOF" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -30
|
||||
|
||||
# Check stderr for crash details
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -20
|
||||
```
|
||||
|
||||
**Common causes:**
|
||||
- Missing dependencies in Docker image
|
||||
- Server code bug causing crash
|
||||
- Memory/resource limits hit (Docker isolation)
|
||||
- Permission errors accessing files
|
||||
|
||||
**Fix:** Depends on stderr output. Often requires fixing server code or Docker image.
|
||||
|
||||
## Step 3: Docker Isolation Checks
|
||||
|
||||
If Docker isolation is enabled and server is failing:
|
||||
|
||||
```bash
|
||||
# Check if isolation is active for this server
|
||||
grep -i "docker isolation enabled\|docker isolation setup" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
|
||||
|
||||
# List running containers
|
||||
docker ps | grep mcpproxy
|
||||
|
||||
# Check container status
|
||||
docker ps -a | grep mcpproxy-SERVER_NAME
|
||||
|
||||
# View container logs
|
||||
docker logs CONTAINER_NAME
|
||||
|
||||
# Check Docker context (for Colima users)
|
||||
docker context show
|
||||
```
|
||||
|
||||
**If Docker isolation is interfering:**
|
||||
1. See `references/docker-isolation-guide.md` for detailed Docker troubleshooting
|
||||
2. Consider disabling isolation for this server (add `"isolation": {"enabled": false}`)
|
||||
|
||||
## Step 4: Configuration Verification
|
||||
|
||||
Verify the server configuration is correct:
|
||||
|
||||
```bash
|
||||
# View server config (pretty-printed)
|
||||
cat ~/.mcpproxy/mcp_config.json | python3 -m json.tool | grep -A 20 '"name": "SERVER_NAME"'
|
||||
|
||||
# Check for common mistakes:
|
||||
# - uvx/npx: Package name is first argument?
|
||||
# - Docker: Using -i not -it?
|
||||
# - Docker servers: isolation disabled?
|
||||
# - Quarantined: "quarantined": false?
|
||||
```
|
||||
|
||||
For detailed configuration patterns, see `references/configuration-patterns.md`.
|
||||
|
||||
## Step 5: Test Server Command Manually
|
||||
|
||||
Test if the server command works outside MCPProxy:
|
||||
|
||||
```bash
|
||||
# For uvx servers
|
||||
uvx mcp-server-name --arg value
|
||||
|
||||
# For Docker servers (remove -i for manual testing)
|
||||
docker run --rm -it image:tag
|
||||
|
||||
# For npx servers
|
||||
npx mcp-server-name --arg value
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Does the command fail with same error?
|
||||
- Is the package/image available?
|
||||
- Are arguments correct?
|
||||
|
||||
## Debugging Checklist
|
||||
|
||||
Use this checklist systematically:
|
||||
|
||||
- [ ] Checked server-specific log for errors
|
||||
- [ ] Examined stderr output (most revealing)
|
||||
- [ ] Matched error to common patterns above
|
||||
- [ ] Verified command syntax (uvx: package name first, Docker: -i not -it)
|
||||
- [ ] Checked Docker isolation status (disabled for Docker commands?)
|
||||
- [ ] Verified configuration file is valid JSON
|
||||
- [ ] Tested command manually outside MCPProxy
|
||||
- [ ] Triggered config reload (touch config file or restart mcpproxy)
|
||||
- [ ] Waited 30 seconds for connection to initialize
|
||||
- [ ] Checked main.log for global errors
|
||||
|
||||
If all checks pass and server still won't connect, see `references/debugging-examples.md` for real-world case studies.
|
||||
|
||||
## Success Verification
|
||||
|
||||
After fixing the issue:
|
||||
|
||||
```bash
|
||||
# 1. Check server status via API
|
||||
curl -s "http://127.0.0.1:8080/api/v1/servers?apikey=YOUR_KEY" | python3 -m json.tool | grep -A 10 '"name": "SERVER_NAME"'
|
||||
|
||||
# Look for:
|
||||
# "connected": true
|
||||
# "status": "ready"
|
||||
# "tool_count": > 0
|
||||
|
||||
# 2. Check server log for successful connection
|
||||
tail -20 ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | grep -i "connected\|ready\|discovered"
|
||||
|
||||
# 3. Verify tools are available
|
||||
curl -s "http://127.0.0.1:8080/api/v1/tools?apikey=YOUR_KEY" | python3 -m json.tool | grep "SERVER_NAME:"
|
||||
```
|
||||
|
||||
If `connected: true` and `tool_count > 0`, the issue is resolved.
|
||||
258
skills/mcpproxy-debug/references/debugging-examples.md
Normal file
258
skills/mcpproxy-debug/references/debugging-examples.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# Real-World MCPProxy Debugging Examples
|
||||
|
||||
This file contains detailed walkthroughs of actual debugging sessions, providing concrete examples of how to diagnose and fix MCPProxy issues.
|
||||
|
||||
## Example 1: Buildkite Server - Docker Isolation Conflict
|
||||
|
||||
**Date**: October 2025
|
||||
**Symptom**: Buildkite MCP server failing to connect with "the input device is not a TTY" error
|
||||
**Server Type**: Docker-based MCP server (`ghcr.io/buildkite/buildkite-mcp-server:latest`)
|
||||
|
||||
### Initial Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "buildkite",
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--pull=always",
|
||||
"-q",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e",
|
||||
"BUILDKITE_API_TOKEN",
|
||||
"ghcr.io/buildkite/buildkite-mcp-server:latest",
|
||||
"stdio"
|
||||
],
|
||||
"env": {
|
||||
"BUILDKITE_API_TOKEN": "${keyring:buildkite_token}"
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
```
|
||||
|
||||
### Diagnostic Process
|
||||
|
||||
1. **Ran diagnostic script**:
|
||||
|
||||
```bash
|
||||
~/.claude/skills/mcpproxy-debug/scripts/diagnose_server.sh buildkite
|
||||
```
|
||||
|
||||
2. **Key findings from stderr**:
|
||||
|
||||
```
|
||||
"the input device is not a TTY"
|
||||
```
|
||||
|
||||
3. **Pattern recognition**: This error typically indicates:
|
||||
|
||||
- Either `-it` flags being used (but config showed `-i` only)
|
||||
- OR Docker isolation wrapping a Docker command (Docker-in-Docker)
|
||||
|
||||
4. **Checked Docker isolation status**:
|
||||
- Global `docker_isolation.enabled` was `true`
|
||||
- Server had no explicit isolation override
|
||||
- MCPProxy was wrapping the Docker command in another container
|
||||
|
||||
### Root Cause
|
||||
|
||||
Docker isolation was enabled globally, and MCPProxy was attempting to run:
|
||||
|
||||
```
|
||||
docker run [isolation-wrapper-args] docker run [server-args] ...
|
||||
```
|
||||
|
||||
This creates a Docker-in-Docker situation where the inner Docker command can't allocate a TTY because it's running inside a container.
|
||||
|
||||
### Solution
|
||||
|
||||
Added explicit isolation disable to the server configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "buildkite",
|
||||
"protocol": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"--pull=always",
|
||||
"-q",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e",
|
||||
"BUILDKITE_API_TOKEN",
|
||||
"ghcr.io/buildkite/buildkite-mcp-server:latest",
|
||||
"stdio"
|
||||
],
|
||||
"env": {
|
||||
"BUILDKITE_API_TOKEN": "${keyring:buildkite_token}"
|
||||
},
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
},
|
||||
"enabled": true,
|
||||
"quarantined": false
|
||||
}
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
After restarting mcpproxy:
|
||||
|
||||
1. **Process inspection**:
|
||||
|
||||
```bash
|
||||
ps aux | grep mcpproxy
|
||||
```
|
||||
|
||||
Confirmed the buildkite server was now running directly:
|
||||
|
||||
```
|
||||
docker run --cidfile ... --pull=always -q -i --rm -e BUILDKITE_API_TOKEN ghcr.io/buildkite/buildkite-mcp-server:latest stdio
|
||||
```
|
||||
|
||||
2. **Connection verification**:
|
||||
|
||||
```bash
|
||||
~/.claude/skills/mcpproxy-debug/scripts/diagnose_server.sh buildkite
|
||||
```
|
||||
|
||||
Output showed:
|
||||
|
||||
```
|
||||
Successfully connected and initialized
|
||||
server_name: "buildkite-mcp-server"
|
||||
server_version: "0.7.2"
|
||||
tool_count: 28
|
||||
```
|
||||
|
||||
3. **No more TTY errors** in recent logs
|
||||
|
||||
### Key Lessons
|
||||
|
||||
1. **Docker isolation auto-skip may fail**: The intended automatic skip for Docker commands didn't work in this case
|
||||
2. **Always explicitly disable isolation for Docker commands**: Best practice to prevent Docker-in-Docker issues
|
||||
3. **Stderr is the most revealing**: The "TTY" error in stderr immediately pointed to the issue
|
||||
4. **The diagnostic script is highly effective**: Automated pattern detection caught the problem immediately
|
||||
|
||||
### Applicable to Other Servers
|
||||
|
||||
This same issue and solution applies to any Docker-based MCP server:
|
||||
|
||||
- `ghcr.io/github/github-mcp-server`
|
||||
- `ghcr.io/sooperset/mcp-atlassian:latest`
|
||||
- Any custom Docker image serving MCP
|
||||
|
||||
**Template solution**:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "any-docker-mcp-server",
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "-e", "ENV_VAR", "image:tag"],
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example 2: API Key Mismatch After Restart
|
||||
|
||||
**Symptom**: API calls return "Invalid or missing API key" after restarting mcpproxy
|
||||
|
||||
### Diagnostic Process
|
||||
|
||||
1. **Check config file API key**:
|
||||
|
||||
```bash
|
||||
grep '"api_key"' ~/.mcpproxy/mcp_config.json
|
||||
```
|
||||
|
||||
Result: `"api_key": "d380462e333f25a1c61bad1d5d3f673277d5167dcdba18954effc7d6f0401c37"`
|
||||
|
||||
2. **API call with config key fails**:
|
||||
|
||||
```bash
|
||||
curl -H "X-API-Key: d380462e333f25a1c61bad1d5d3f673277d5167dcdba18954effc7d6f0401c37" \
|
||||
http://127.0.0.1:8080/api/v1/servers
|
||||
```
|
||||
|
||||
Result: `{"success": false, "error": "Invalid or missing API key"}`
|
||||
|
||||
3. **Check logs for API key source**:
|
||||
```bash
|
||||
grep -i "api.*key" ~/Library/Logs/mcpproxy/main.log | tail -10
|
||||
```
|
||||
Result: `API key authentication enabled | {"source": "environment variable", "api_key_prefix": "9fc1****ee1c"}`
|
||||
|
||||
### Root Cause
|
||||
|
||||
The `MCPPROXY_API_KEY` environment variable was set (likely by the tray app), which takes precedence over the config file. The actual API key was `9fc15eb0...` (different from config).
|
||||
|
||||
### Solution
|
||||
|
||||
Use the environment variable key or unset the environment variable:
|
||||
|
||||
**Option 1**: Use the actual key from logs
|
||||
|
||||
```bash
|
||||
# Extract from log prefix
|
||||
grep "api_key_prefix" ~/Library/Logs/mcpproxy/main.log | tail -1
|
||||
```
|
||||
|
||||
**Option 2**: Unset environment variable to use config file
|
||||
|
||||
```bash
|
||||
unset MCPPROXY_API_KEY
|
||||
pkill mcpproxy
|
||||
open /Applications/mcpproxy.app
|
||||
```
|
||||
|
||||
### Key Lesson
|
||||
|
||||
Always check both environment variables and config file when debugging API authentication. Environment variables take precedence.
|
||||
|
||||
## Pattern: Missing Package Name in uvx/npx
|
||||
|
||||
**Error**: `unexpected argument '--some-flag' found`
|
||||
|
||||
**Example**:
|
||||
|
||||
```json
|
||||
// WRONG
|
||||
{"command": "uvx", "args": ["--local-timezone", "America/New_York"]}
|
||||
|
||||
// CORRECT
|
||||
{"command": "uvx", "args": ["mcp-server-time", "--local-timezone", "America/New_York"]}
|
||||
```
|
||||
|
||||
**Diagnostic**: Check stderr in server logs for "unexpected argument" errors, then verify args array has package name first.
|
||||
|
||||
## Pattern: Context Deadline Exceeded
|
||||
|
||||
**Error**: `MCP initialize failed: transport error: context deadline exceeded`
|
||||
|
||||
**Common Causes**:
|
||||
|
||||
1. Missing package name (uvx/npx) - check stderr for "unexpected argument"
|
||||
2. Docker TTY issue - check stderr for "not a TTY"
|
||||
3. Server crashed on startup - check stderr for stack traces
|
||||
4. Environment variables missing - check stderr for "missing" or "required"
|
||||
|
||||
**Diagnostic Workflow**:
|
||||
|
||||
```bash
|
||||
# 1. Check stderr for actual error
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-{SERVER_NAME}.log | tail -20
|
||||
|
||||
# 2. Check if server started at all
|
||||
grep "Starting connection" ~/Library/Logs/mcpproxy/server-{SERVER_NAME}.log | tail -5
|
||||
|
||||
# 3. Check Docker container if isolation enabled
|
||||
docker ps | grep mcpproxy
|
||||
docker logs CONTAINER_ID
|
||||
```
|
||||
458
skills/mcpproxy-debug/references/docker-isolation-guide.md
Normal file
458
skills/mcpproxy-debug/references/docker-isolation-guide.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# Docker Isolation - Complete Guide
|
||||
|
||||
**When to use this reference:** Docker isolation is enabled and servers are failing, or you see "not a TTY" errors.
|
||||
|
||||
This reference explains how MCPProxy's Docker isolation feature works and how to debug issues with it.
|
||||
|
||||
## What is Docker Isolation?
|
||||
|
||||
MCPProxy can run stdio MCP servers inside Docker containers for security isolation. This prevents untrusted servers from accessing your filesystem or network.
|
||||
|
||||
**Key concept:** MCPProxy wraps the server command in `docker run`, manages the container lifecycle, and handles stdio communication between Claude Code and the containerized server.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Normal Flow (No Isolation)
|
||||
|
||||
```bash
|
||||
# User configures:
|
||||
command: "uvx"
|
||||
args: ["mcp-server-sqlite", "--db-path", "/path/to/db"]
|
||||
|
||||
# MCPProxy runs directly:
|
||||
uvx mcp-server-sqlite --db-path /path/to/db
|
||||
```
|
||||
|
||||
### With Docker Isolation Enabled
|
||||
|
||||
```bash
|
||||
# User configures same as above
|
||||
# MCPProxy detects runtime (uvx → Python) and wraps in Docker:
|
||||
|
||||
docker run -i --rm \
|
||||
--memory="512m" \
|
||||
--cpus="1.0" \
|
||||
--network=bridge \
|
||||
python:3.11 \
|
||||
uvx mcp-server-sqlite --db-path /path/to/db
|
||||
```
|
||||
|
||||
**MCPProxy automatically:**
|
||||
1. Detects the runtime from the command (uvx→Python, npx→Node.js)
|
||||
2. Selects appropriate Docker image
|
||||
3. Wraps command in `docker run` with resource limits
|
||||
4. Tracks container lifecycle
|
||||
5. Cleans up container on exit
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Docker Isolation Settings
|
||||
|
||||
Located in `~/.mcpproxy/mcp_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"docker_isolation": {
|
||||
"enabled": true, // Master switch
|
||||
"memory_limit": "512m", // Per-container memory limit
|
||||
"cpu_limit": "1.0", // CPU cores (1.0 = 1 core)
|
||||
"timeout": "30s", // Container startup timeout
|
||||
"network_mode": "bridge", // Docker network mode
|
||||
"default_images": {
|
||||
"uvx": "python:3.11", // Image for uvx commands
|
||||
"npx": "node:20", // Image for npx commands
|
||||
"python": "python:3.11", // Image for python commands
|
||||
"node": "node:20" // Image for node commands
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Per-Server Isolation Override
|
||||
|
||||
You can override isolation settings for specific servers:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-server",
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-name"],
|
||||
"isolation": {
|
||||
"enabled": false, // Disable isolation for this server
|
||||
// OR customize settings:
|
||||
"enabled": true,
|
||||
"image": "python:3.12-slim", // Custom image
|
||||
"memory_limit": "1g", // More memory
|
||||
"cpu_limit": "2.0", // More CPU
|
||||
"network_mode": "none", // No network access
|
||||
"working_dir": "/workspace" // Working directory in container
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Checking Docker Isolation Status
|
||||
|
||||
### Is Isolation Enabled for a Server?
|
||||
|
||||
```bash
|
||||
# Check server log for isolation setup
|
||||
grep -i "docker isolation enabled\|docker isolation setup" \
|
||||
~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
|
||||
|
||||
# Look for:
|
||||
# "Docker isolation enabled for server: SERVER_NAME"
|
||||
# "Docker isolation setup successful"
|
||||
```
|
||||
|
||||
### View the Docker Command Being Used
|
||||
|
||||
```bash
|
||||
# See actual docker run command
|
||||
grep "docker_run_args" ~/Library/Logs/mcpproxy/main.log | tail -3
|
||||
|
||||
# Example output:
|
||||
# docker_run_args: ["run", "-i", "--rm", "--memory=512m", "--cpus=1.0",
|
||||
# "--network=bridge", "python:3.11", "uvx", "mcp-server-name"]
|
||||
```
|
||||
|
||||
### List Running Containers
|
||||
|
||||
```bash
|
||||
# List all MCPProxy containers
|
||||
docker ps | grep mcpproxy
|
||||
|
||||
# Check specific server container
|
||||
docker ps | grep mcpproxy-SERVER_NAME
|
||||
|
||||
# Check container health
|
||||
docker inspect --format='{{.State.Status}}' CONTAINER_ID
|
||||
```
|
||||
|
||||
### View Container Logs
|
||||
|
||||
```bash
|
||||
# If container is running
|
||||
docker logs CONTAINER_NAME
|
||||
|
||||
# If container exited, find it in history
|
||||
docker ps -a | grep mcpproxy-SERVER_NAME
|
||||
docker logs CONTAINER_ID
|
||||
```
|
||||
|
||||
## Common Docker Isolation Issues
|
||||
|
||||
### Issue 1: Docker-in-Docker (Most Common)
|
||||
|
||||
**Symptom:** "the input device is not a TTY" error for Docker-based servers
|
||||
|
||||
**Root cause:** MCPProxy's Docker isolation wraps a Docker command in Docker, creating nested containers.
|
||||
|
||||
```json
|
||||
// Server config uses Docker directly
|
||||
{
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "mcp-image:latest"]
|
||||
}
|
||||
|
||||
// MCPProxy wraps it in another Docker (if isolation enabled):
|
||||
docker run ... python:3.11 docker run -i --rm mcp-image:latest
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
This fails: Docker-in-Docker
|
||||
```
|
||||
|
||||
**Solution:** Explicitly disable isolation for Docker-based servers:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "docker-server",
|
||||
"command": "docker",
|
||||
"args": ["run", "-i", "--rm", "mcp-image:latest"],
|
||||
"isolation": {
|
||||
"enabled": false // CRITICAL: Always disable for Docker commands
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why explicit is better:** MCPProxy should auto-detect Docker commands and skip isolation, but explicit configuration is more reliable and prevents edge cases.
|
||||
|
||||
### Issue 2: File Access Problems
|
||||
|
||||
**Symptom:** Server can't access local files, permission errors
|
||||
|
||||
**Root cause:** Container can't access host filesystem by default.
|
||||
|
||||
**Solution 1: Disable isolation** (if file access is required):
|
||||
```json
|
||||
{
|
||||
"isolation": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Solution 2: Mount volumes** (more secure):
|
||||
```json
|
||||
{
|
||||
"isolation": {
|
||||
"enabled": true,
|
||||
"volumes": [
|
||||
"/host/path:/container/path:ro" // Read-only mount
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Volume mounting requires MCPProxy support. Check documentation for current status.
|
||||
|
||||
### Issue 3: Network Access Blocked
|
||||
|
||||
**Symptom:** Server can't make API calls, network timeouts
|
||||
|
||||
**Root cause:** Container network mode blocks external access.
|
||||
|
||||
**Check current network mode:**
|
||||
```bash
|
||||
grep "network_mode" ~/.mcpproxy/mcp_config.json
|
||||
```
|
||||
|
||||
**Solution:** Change network mode:
|
||||
```json
|
||||
{
|
||||
"isolation": {
|
||||
"enabled": true,
|
||||
"network_mode": "bridge" // Default, allows external access
|
||||
// OR
|
||||
"network_mode": "host" // Full host network access
|
||||
// OR
|
||||
"network_mode": "none" // No network (most secure)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Issue 4: Container Image Not Found
|
||||
|
||||
**Symptom:** "context deadline exceeded", stderr shows "pull" or "not found"
|
||||
|
||||
**Investigation:**
|
||||
```bash
|
||||
# Check stderr for pull errors
|
||||
grep -i "pull\|not found" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
|
||||
|
||||
# Try pulling image manually
|
||||
docker pull python:3.11
|
||||
```
|
||||
|
||||
**Solution:** Ensure Docker image exists locally or can be pulled:
|
||||
```bash
|
||||
# Pull image before starting mcpproxy
|
||||
docker pull python:3.11
|
||||
|
||||
# Or specify a custom image that exists
|
||||
{
|
||||
"isolation": {
|
||||
"image": "python:3.12-slim" // Different image
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Issue 5: Resource Limits Too Low
|
||||
|
||||
**Symptom:** Container exits unexpectedly, out of memory errors
|
||||
|
||||
**Investigation:**
|
||||
```bash
|
||||
# Check container exit status
|
||||
docker ps -a | grep mcpproxy-SERVER_NAME
|
||||
|
||||
# Look for OOMKilled status
|
||||
docker inspect CONTAINER_ID | grep -i "oom"
|
||||
```
|
||||
|
||||
**Solution:** Increase resource limits:
|
||||
```json
|
||||
{
|
||||
"isolation": {
|
||||
"enabled": true,
|
||||
"memory_limit": "2g", // Increase from default 512m
|
||||
"cpu_limit": "2.0" // Increase from default 1.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Docker Context Support (Colima)
|
||||
|
||||
MCPProxy uses your system's default Docker context. For Colima users:
|
||||
|
||||
```bash
|
||||
# Check current Docker context
|
||||
docker context show
|
||||
|
||||
# List all contexts
|
||||
docker context ls
|
||||
|
||||
# Example output:
|
||||
# NAME DESCRIPTION DOCKER ENDPOINT
|
||||
# default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||
# colima * colima unix:///Users/.../.colima/docker.sock
|
||||
|
||||
# MCPProxy uses whichever has the asterisk (*)
|
||||
```
|
||||
|
||||
**To change context:**
|
||||
```bash
|
||||
docker context use colima
|
||||
docker context use default
|
||||
```
|
||||
|
||||
**After changing context:** Restart mcpproxy for changes to take effect.
|
||||
|
||||
## Disabling Docker Isolation
|
||||
|
||||
### Globally (All Servers)
|
||||
|
||||
Edit `~/.mcpproxy/mcp_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"docker_isolation": {
|
||||
"enabled": false // Disables for all servers
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Per-Server (Recommended)
|
||||
|
||||
Only disable for servers that need it:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "special-server",
|
||||
"command": "docker", // Or any command that needs no isolation
|
||||
"args": ["..."],
|
||||
"isolation": {
|
||||
"enabled": false // Only this server runs without isolation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Best practice:** Keep isolation enabled globally, disable per-server only when necessary.
|
||||
|
||||
## Debugging Workflow for Docker Isolation Issues
|
||||
|
||||
Use this systematic workflow:
|
||||
|
||||
### Step 1: Verify Isolation Status
|
||||
```bash
|
||||
# Is isolation enabled for this server?
|
||||
grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
|
||||
```
|
||||
|
||||
### Step 2: Check Container Status
|
||||
```bash
|
||||
# Is container running?
|
||||
docker ps | grep mcpproxy-SERVER_NAME
|
||||
|
||||
# Did container exit?
|
||||
docker ps -a | grep mcpproxy-SERVER_NAME
|
||||
```
|
||||
|
||||
### Step 3: View Container Logs
|
||||
```bash
|
||||
# Get container ID
|
||||
CONTAINER_ID=$(docker ps -a | grep mcpproxy-SERVER_NAME | awk '{print $1}')
|
||||
|
||||
# View logs
|
||||
docker logs $CONTAINER_ID
|
||||
```
|
||||
|
||||
### Step 4: Check Docker Command
|
||||
```bash
|
||||
# See exact command being used
|
||||
grep "docker_run_args" ~/Library/Logs/mcpproxy/main.log | tail -3
|
||||
```
|
||||
|
||||
### Step 5: Test Manually
|
||||
```bash
|
||||
# Extract docker run command from logs and test it manually
|
||||
# Example:
|
||||
docker run -i --rm --memory=512m --cpus=1.0 python:3.11 uvx mcp-server-name
|
||||
```
|
||||
|
||||
### Step 6: Apply Fix
|
||||
|
||||
Based on the issue:
|
||||
- Docker-in-Docker → Disable isolation
|
||||
- File access → Disable isolation or mount volumes
|
||||
- Network issues → Change network_mode
|
||||
- Resource limits → Increase memory/CPU
|
||||
- Image not found → Pull image or change image
|
||||
|
||||
### Step 7: Reload and Verify
|
||||
```bash
|
||||
# Trigger config reload
|
||||
touch ~/.mcpproxy/mcp_config.json
|
||||
|
||||
# Or restart
|
||||
pkill mcpproxy && open /Applications/mcpproxy.app
|
||||
|
||||
# Verify fix
|
||||
curl -s "http://127.0.0.1:8080/api/v1/servers?apikey=YOUR_KEY" | \
|
||||
python3 -m json.tool | grep -A 10 '"name": "SERVER_NAME"'
|
||||
```
|
||||
|
||||
## When to Use Docker Isolation
|
||||
|
||||
### ✅ Use Docker Isolation When:
|
||||
- Running untrusted third-party MCP servers
|
||||
- Need security boundaries between servers
|
||||
- Want resource limits per server
|
||||
- Servers don't need host filesystem access
|
||||
- Servers don't need special network configurations
|
||||
|
||||
### ❌ Disable Docker Isolation When:
|
||||
- Server needs to access local files
|
||||
- Server command is already Docker (prevents Docker-in-Docker)
|
||||
- Server needs host network access
|
||||
- Troubleshooting connection issues
|
||||
- Performance is critical (isolation adds overhead)
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Check if isolation is active
|
||||
```bash
|
||||
grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-NAME.log | tail -5
|
||||
```
|
||||
|
||||
### List containers
|
||||
```bash
|
||||
docker ps | grep mcpproxy
|
||||
```
|
||||
|
||||
### View container logs
|
||||
```bash
|
||||
docker logs CONTAINER_NAME
|
||||
```
|
||||
|
||||
### Disable isolation for server
|
||||
```json
|
||||
{"isolation": {"enabled": false}}
|
||||
```
|
||||
|
||||
### Increase resources
|
||||
```json
|
||||
{"isolation": {"memory_limit": "2g", "cpu_limit": "2.0"}}
|
||||
```
|
||||
|
||||
### Change network mode
|
||||
```json
|
||||
{"isolation": {"network_mode": "host"}}
|
||||
```
|
||||
|
||||
### Use custom image
|
||||
```json
|
||||
{"isolation": {"image": "python:3.12-slim"}}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Docker isolation provides security but adds complexity. Start with isolation disabled while getting servers working, then enable it once everything is stable. Always disable isolation explicitly for Docker-based servers to prevent Docker-in-Docker issues.
|
||||
89
skills/mcpproxy-debug/scripts/check_status.sh
Executable file
89
skills/mcpproxy-debug/scripts/check_status.sh
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
# Quick health check for MCPProxy
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "=== MCPProxy Health Check ==="
|
||||
echo
|
||||
|
||||
# Check if mcpproxy is running
|
||||
echo -n "Process Status: "
|
||||
if pgrep -x "mcpproxy" > /dev/null; then
|
||||
echo -e "${GREEN}Running${NC}"
|
||||
ps aux | grep mcpproxy | grep -v grep | head -1
|
||||
else
|
||||
echo -e "${RED}Not Running${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
|
||||
# Get API key from config
|
||||
API_KEY=$(grep '"api_key"' ~/.mcpproxy/mcp_config.json 2> /dev/null | cut -d'"' -f4 || echo "")
|
||||
|
||||
if [ -z "$API_KEY" ]; then
|
||||
echo -e "${YELLOW}Warning: No API key found in config${NC}"
|
||||
echo "Checking logs for auto-generated key..."
|
||||
API_KEY=$(grep "api_key_prefix" ~/Library/Logs/mcpproxy/main.log 2> /dev/null | tail -1 | grep -o '"api_key":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
fi
|
||||
|
||||
if [ -z "$API_KEY" ]; then
|
||||
echo -e "${RED}Error: Could not find API key${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check server status via API
|
||||
echo "Server Status:"
|
||||
RESPONSE=$(curl -s -H "X-API-Key: $API_KEY" "http://127.0.0.1:8080/api/v1/servers" 2> /dev/null)
|
||||
|
||||
if [ -z "$RESPONSE" ]; then
|
||||
echo -e "${RED}Error: API returned empty response${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if echo "$RESPONSE" | python3 -c "import sys, json; data=json.load(sys.stdin); exit(0 if data.get('success', False) else 1)" 2> /dev/null; then
|
||||
# Parse and display server info
|
||||
echo "$RESPONSE" | python3 << 'PYTHON'
|
||||
import sys, json
|
||||
|
||||
data = json.load(sys.stdin)
|
||||
stats = data.get('data', {}).get('stats', {})
|
||||
servers = data.get('data', {}).get('servers', [])
|
||||
|
||||
print(f" Total Servers: {stats.get('total_servers', 0)}")
|
||||
print(f" Connected: {stats.get('connected_servers', 0)}")
|
||||
print(f" Quarantined: {stats.get('quarantined_servers', 0)}")
|
||||
print(f" Total Tools: {stats.get('total_tools', 0)}")
|
||||
print(f" Docker Containers: {stats.get('docker_containers', 0)}")
|
||||
print()
|
||||
|
||||
if servers:
|
||||
print("Servers:")
|
||||
for server in servers:
|
||||
status_icon = "✓" if server.get('connected') else "✗"
|
||||
name = server.get('name', 'unknown')
|
||||
status = server.get('status', 'unknown')
|
||||
tools = server.get('tool_count', 0)
|
||||
error = server.get('last_error', '')
|
||||
|
||||
print(f" {status_icon} {name}: {status} ({tools} tools)")
|
||||
if error:
|
||||
print(f" Error: {error}")
|
||||
PYTHON
|
||||
else
|
||||
echo -e "${RED}API Error:${NC}"
|
||||
echo "$RESPONSE" | python3 -m json.tool 2> /dev/null || echo "$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Docker Containers ==="
|
||||
docker ps --filter "name=mcpproxy" --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" || echo "None running"
|
||||
|
||||
echo
|
||||
echo -e "${GREEN}Health check complete!${NC}"
|
||||
74
skills/mcpproxy-debug/scripts/compare_servers.sh
Executable file
74
skills/mcpproxy-debug/scripts/compare_servers.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Compare two servers (one working, one broken) to find differences
|
||||
# Usage: ./compare_servers.sh <working-server> <broken-server>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 <working-server-name> <broken-server-name>"
|
||||
echo "Example: $0 glean buildkite"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WORKING="$1"
|
||||
BROKEN="$2"
|
||||
|
||||
echo "=== Comparing Servers: $WORKING (working) vs $BROKEN (broken) ==="
|
||||
echo
|
||||
|
||||
# Compare configurations
|
||||
echo "Configuration Comparison"
|
||||
echo "------------------------"
|
||||
echo "Working server ($WORKING):"
|
||||
grep -A 15 "\"name\": \"$WORKING\"" ~/.mcpproxy/mcp_config.json | head -20
|
||||
echo
|
||||
echo "Broken server ($BROKEN):"
|
||||
grep -A 15 "\"name\": \"$BROKEN\"" ~/.mcpproxy/mcp_config.json | head -20
|
||||
echo
|
||||
|
||||
# Compare connection status
|
||||
echo "Connection Status Comparison"
|
||||
echo "----------------------------"
|
||||
echo "$WORKING status:"
|
||||
grep "$WORKING" ~/Library/Logs/mcpproxy/main.log 2> /dev/null | grep -i "connected\|initialized" | tail -3 \
|
||||
|| grep "$WORKING" ~/.mcpproxy/logs/main.log 2> /dev/null | grep -i "connected\|initialized" | tail -3 \
|
||||
|| echo "No connection info found"
|
||||
echo
|
||||
|
||||
echo "$BROKEN status:"
|
||||
grep "$BROKEN" ~/Library/Logs/mcpproxy/main.log 2> /dev/null | grep -i "error\|failed" | tail -3 \
|
||||
|| grep "$BROKEN" ~/.mcpproxy/logs/main.log 2> /dev/null | grep -i "error\|failed" | tail -3 \
|
||||
|| echo "No error info found"
|
||||
echo
|
||||
|
||||
# Compare stderr output
|
||||
echo "Stderr Comparison"
|
||||
echo "-----------------"
|
||||
echo "$WORKING recent stderr:"
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-${WORKING}.log 2> /dev/null | tail -5 \
|
||||
|| grep "stderr" ~/.mcpproxy/logs/server-${WORKING}.log 2> /dev/null | tail -5 \
|
||||
|| echo "No stderr output"
|
||||
echo
|
||||
|
||||
echo "$BROKEN recent stderr:"
|
||||
grep "stderr" ~/Library/Logs/mcpproxy/server-${BROKEN}.log 2> /dev/null | tail -5 \
|
||||
|| grep "stderr" ~/.mcpproxy/logs/server-${BROKEN}.log 2> /dev/null | tail -5 \
|
||||
|| echo "No stderr output"
|
||||
echo
|
||||
|
||||
# Docker container comparison
|
||||
echo "Docker Container Comparison"
|
||||
echo "---------------------------"
|
||||
echo "$WORKING container:"
|
||||
docker ps --filter "name=mcpproxy-${WORKING}" --format "{{.Names}}\t{{.Status}}\t{{.Image}}" 2> /dev/null || echo "No container"
|
||||
echo
|
||||
|
||||
echo "$BROKEN container:"
|
||||
docker ps --filter "name=mcpproxy-${BROKEN}" --format "{{.Names}}\t{{.Status}}\t{{.Image}}" 2> /dev/null || echo "No container"
|
||||
echo
|
||||
|
||||
echo "=== Key Differences to Investigate ==="
|
||||
echo "1. Check 'command' and 'args' differences in config"
|
||||
echo "2. Check if error patterns match known issues (uvx package, Docker -it)"
|
||||
echo "3. Check stderr for specific error messages"
|
||||
echo "4. Check if Docker container is running for working but not broken"
|
||||
93
skills/mcpproxy-debug/scripts/diagnose_server.sh
Executable file
93
skills/mcpproxy-debug/scripts/diagnose_server.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
# Diagnose a specific MCP server following mcpproxy-debug skill workflow
|
||||
# Usage: ./diagnose_server.sh <server-name>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <server-name>"
|
||||
echo "Example: $0 buildkite"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SERVER_NAME="$1"
|
||||
LOG_FILE="$HOME/Library/Logs/mcpproxy/server-${SERVER_NAME}.log"
|
||||
|
||||
# Check if log file exists (Linux fallback)
|
||||
if [ ! -f "$LOG_FILE" ]; then
|
||||
LOG_FILE="$HOME/.mcpproxy/logs/server-${SERVER_NAME}.log"
|
||||
fi
|
||||
|
||||
if [ ! -f "$LOG_FILE" ]; then
|
||||
echo "Error: Log file not found for server '$SERVER_NAME'"
|
||||
echo "Checked locations:"
|
||||
echo " - ~/Library/Logs/mcpproxy/server-${SERVER_NAME}.log (macOS)"
|
||||
echo " - ~/.mcpproxy/logs/server-${SERVER_NAME}.log (Linux)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== MCPProxy Server Diagnosis: $SERVER_NAME ==="
|
||||
echo
|
||||
|
||||
# Step 1: Check connection status
|
||||
echo "Step 1: Connection Status"
|
||||
echo "-------------------------"
|
||||
grep -i "connected\|error\|failed" ~/Library/Logs/mcpproxy/main.log 2> /dev/null | grep "$SERVER_NAME" | tail -5 \
|
||||
|| grep -i "connected\|error\|failed" ~/.mcpproxy/logs/main.log 2> /dev/null | grep "$SERVER_NAME" | tail -5 \
|
||||
|| echo "No recent connection status found in main log"
|
||||
echo
|
||||
|
||||
# Step 2: Check for stderr messages (most revealing)
|
||||
echo "Step 2: Recent stderr output (shows actual errors)"
|
||||
echo "---------------------------------------------------"
|
||||
grep "stderr" "$LOG_FILE" | tail -10
|
||||
echo
|
||||
|
||||
# Step 3: Check for error patterns
|
||||
echo "Step 3: Error Pattern Detection"
|
||||
echo "--------------------------------"
|
||||
|
||||
if grep -q "unexpected argument" "$LOG_FILE"; then
|
||||
echo "❌ Found: 'unexpected argument' error"
|
||||
echo " → Likely cause: Missing package name for uvx/npx"
|
||||
echo " → Fix: Add package name as first argument"
|
||||
echo
|
||||
fi
|
||||
|
||||
if grep -q "not a TTY" "$LOG_FILE"; then
|
||||
echo "❌ Found: 'input device is not a TTY' error"
|
||||
echo " → Likely cause: Using -it flag with Docker"
|
||||
echo " → Fix: Use -i only (not -it) for stdin pipe"
|
||||
echo
|
||||
fi
|
||||
|
||||
if grep -q "context deadline exceeded" "$LOG_FILE"; then
|
||||
echo "❌ Found: 'context deadline exceeded' error"
|
||||
echo " → Likely cause: Server failed to initialize within timeout"
|
||||
echo " → Check stderr above for specific reason"
|
||||
echo
|
||||
fi
|
||||
|
||||
if grep -q "Successfully connected" "$LOG_FILE"; then
|
||||
echo "✅ Server successfully connected at some point"
|
||||
grep "Successfully connected" "$LOG_FILE" | tail -1
|
||||
echo
|
||||
fi
|
||||
|
||||
# Step 4: Check Docker container status
|
||||
echo "Step 4: Docker Container Status"
|
||||
echo "--------------------------------"
|
||||
if docker ps --filter "name=mcpproxy-${SERVER_NAME}" --format "{{.Names}}\t{{.Status}}\t{{.Image}}" 2> /dev/null | grep -q .; then
|
||||
docker ps --filter "name=mcpproxy-${SERVER_NAME}" --format "{{.Names}}\t{{.Status}}\t{{.Image}}"
|
||||
else
|
||||
echo "No running Docker container found for $SERVER_NAME"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Step 5: Recent log activity
|
||||
echo "Step 5: Last 10 log entries"
|
||||
echo "----------------------------"
|
||||
tail -10 "$LOG_FILE"
|
||||
echo
|
||||
|
||||
echo "=== End of Diagnosis ==="
|
||||
24
skills/mcpproxy-debug/scripts/get_api_key.sh
Executable file
24
skills/mcpproxy-debug/scripts/get_api_key.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Extract current API key from config or logs
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Try config file first
|
||||
API_KEY=$(grep '"api_key"' ~/.mcpproxy/mcp_config.json 2> /dev/null | cut -d'"' -f4 || echo "")
|
||||
|
||||
if [ -n "$API_KEY" ]; then
|
||||
echo "$API_KEY"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Try logs for auto-generated key
|
||||
echo "No API key in config, checking logs..." >&2
|
||||
API_KEY=$(grep -i "api key" ~/Library/Logs/mcpproxy/main.log 2> /dev/null | grep -o '"api_key":"[^"]*"' | tail -1 | cut -d'"' -f4 || echo "")
|
||||
|
||||
if [ -n "$API_KEY" ]; then
|
||||
echo "$API_KEY"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Error: Could not find API key" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user