From 045fe02fff99cda231cee32b80911ebd0abe4d32 Mon Sep 17 00:00:00 2001 From: nlea Date: Thu, 4 Dec 2025 10:43:22 +0100 Subject: [PATCH 1/5] WIP: docs reorganization --- astro.config.ts | 40 +- src/assets/add-mcp-server-form.png | Bin 0 -> 48433 bytes src/assets/adding-mcp-server.png | Bin 0 -> 53130 bytes src/assets/mcp-server-logs.png | Bin 0 -> 77792 bytes src/assets/terminal-output.png | Bin 0 -> 26065 bytes .../mcp-gateway/concepts/authentication.md | 80 +++ .../docs/mcp-gateway/concepts/proxy.md | 135 +++++ .../docs/mcp-gateway/configuration/cli.md | 113 +++++ .../docs/mcp-gateway/configuration/storage.md | 142 ++++++ .../core-concepts/activity-logging.md | 239 --------- .../mcp-gateway/core-concepts/interfaces.md | 254 ---------- .../core-concepts/server-management.md | 180 ------- src/content/docs/mcp-gateway/docs.md | 208 ++++++++ .../docs/mcp-gateway/features/cli-options.md | 241 --------- .../docs/mcp-gateway/features/storage.md | 370 -------------- .../docs/mcp-gateway/features/terminal-ui.md | 309 ------------ .../mcp-gateway/features/web-interface.md | 360 -------------- .../docs/mcp-gateway/getting-started.md | 120 ----- .../docs/mcp-gateway/getting-started.mdx | 115 +++++ src/content/docs/mcp-gateway/index.md | 114 +++-- .../interfaces/gateway-mcp-server.md | 89 ++++ .../docs/mcp-gateway/interfaces/rest-api.md | 278 +++++++++++ .../docs/mcp-gateway/interfaces/web-ui.md | 91 ++++ .../docs/mcp-gateway/troubleshooting.md | 469 ------------------ src/content/docs/reference/example.md | 11 - 25 files changed, 1328 insertions(+), 2630 deletions(-) create mode 100644 src/assets/add-mcp-server-form.png create mode 100644 src/assets/adding-mcp-server.png create mode 100644 src/assets/mcp-server-logs.png create mode 100644 src/assets/terminal-output.png create mode 100644 src/content/docs/mcp-gateway/concepts/authentication.md create mode 100644 src/content/docs/mcp-gateway/concepts/proxy.md create mode 100644 src/content/docs/mcp-gateway/configuration/cli.md create mode 100644 src/content/docs/mcp-gateway/configuration/storage.md delete mode 100644 src/content/docs/mcp-gateway/core-concepts/activity-logging.md delete mode 100644 src/content/docs/mcp-gateway/core-concepts/interfaces.md delete mode 100644 src/content/docs/mcp-gateway/core-concepts/server-management.md create mode 100644 src/content/docs/mcp-gateway/docs.md delete mode 100644 src/content/docs/mcp-gateway/features/cli-options.md delete mode 100644 src/content/docs/mcp-gateway/features/storage.md delete mode 100644 src/content/docs/mcp-gateway/features/terminal-ui.md delete mode 100644 src/content/docs/mcp-gateway/features/web-interface.md delete mode 100644 src/content/docs/mcp-gateway/getting-started.md create mode 100644 src/content/docs/mcp-gateway/getting-started.mdx create mode 100644 src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md create mode 100644 src/content/docs/mcp-gateway/interfaces/rest-api.md create mode 100644 src/content/docs/mcp-gateway/interfaces/web-ui.md delete mode 100644 src/content/docs/mcp-gateway/troubleshooting.md delete mode 100644 src/content/docs/reference/example.md diff --git a/astro.config.ts b/astro.config.ts index 67bfc42..52bff77 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -143,46 +143,28 @@ export default defineConfig({ items: [ { label: "Overview", link: "/mcp-gateway" }, { label: "Getting Started", link: "/mcp-gateway/getting-started" }, + { label: "Authentication", link: "/mcp-gateway/authentication" }, { - label: "Core Concepts", + label: "Interfaces", collapsed: false, items: [ { - label: "Server Management", - link: "/mcp-gateway/core-concepts/server-management", - }, - { - label: "Activity Logging", - link: "/mcp-gateway/core-concepts/activity-logging", - }, - { - label: "Interfaces", - link: "/mcp-gateway/core-concepts/interfaces", - }, - ], - }, - { - label: "Features", - collapsed: false, - items: [ - { - label: "CLI Options", - link: "/mcp-gateway/features/cli-options", - }, - { - label: "Terminal UI", - link: "/mcp-gateway/features/terminal-ui", + label: "Web UI", + link: "/mcp-gateway/interfaces/web-ui", }, { - label: "Web Interface", - link: "/mcp-gateway/features/web-interface", + label: "Gateway MCP Server", + link: "/mcp-gateway/interfaces/gateway-mcp-server", }, { - label: "Storage & Registry", - link: "/mcp-gateway/features/storage", + label: "REST API", + link: "/mcp-gateway/interfaces/rest-api", }, ], }, + { label: "Proxy", link: "/mcp-gateway/proxy" }, + { label: "CLI", link: "/mcp-gateway/cli" }, + { label: "Storage", link: "/mcp-gateway/storage" }, { label: "Troubleshooting", link: "/mcp-gateway/troubleshooting" }, ], }, diff --git a/src/assets/add-mcp-server-form.png b/src/assets/add-mcp-server-form.png new file mode 100644 index 0000000000000000000000000000000000000000..8fe8ab856f48b6cb7a11c8a05dda61e1f6bef239 GIT binary patch literal 48433 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�_}>6HXM=@1uX1r0nRd=G!h82pi-P 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 literal 0 HcmV?d00001 diff --git a/src/assets/mcp-server-logs.png b/src/assets/mcp-server-logs.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b6a08349af6f43845fef4b6ebae72453618553 GIT binary patch literal 77792 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 literal 0 HcmV?d00001 diff --git a/src/assets/terminal-output.png b/src/assets/terminal-output.png new file mode 100644 index 0000000000000000000000000000000000000000..69977a068304fd6fa248e219e92df8709d04561a GIT binary patch literal 26065 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 + +Set the HTTP server port. + +```bash +mcp-gateway --port 8080 +``` + +**Default:** `3333` + +**Result:** + +- API: `http://localhost:8080/api` +- Web UI: `http://localhost:8080/ui` +- Proxy: `http://localhost:8080/s/{server}/mcp` + +--- + +### `--storage-dir ` + +Set custom storage directory for logs and registry. + +```bash +mcp-gateway --storage-dir /custom/path +``` + +**Default:** `~/.mcp-gateway` + +**Result:** + +- Registry: `/custom/path/mcp.json` +- Database: `/custom/path/gateway.db` + +--- + +### `--help` + +Display help information. + +```bash +mcp-gateway --help +``` + +--- + +### `--version` + +Display version information. + +```bash +mcp-gateway --version +``` + +## Environment Variables + +All CLI options have environment variable equivalents: + +| Environment Variable | CLI Flag | Default | +| ------------------------- | --------------- | ---------------- | +| `MCP_GATEWAY_PORT` | `--port` | `3333` | +| `MCP_GATEWAY_STORAGE_DIR` | `--storage-dir` | `~/.mcp-gateway` | +| `MCP_GATEWAY_TOKEN` | N/A | (auto-generated) | + +**Examples:** + +```bash +# Set port via environment +MCP_GATEWAY_PORT=8080 mcp-gateway + +# Set storage directory +MCP_GATEWAY_STORAGE_DIR=~/gateway mcp-gateway + +# Set custom auth token +MCP_GATEWAY_TOKEN=my-secret-token mcp-gateway +``` + +## Configuration Precedence + +Options are applied in this order (highest to lowest priority): + +1. Command-line flags +2. Environment variables +3. Default values + +**Example:** + +```bash +# Port will be 9000 (CLI flag wins) +MCP_GATEWAY_PORT=8080 mcp-gateway --port 9000 +``` + +## Next Steps + +- [**Storage**](/mcp-gateway/configuration/storage) - Understand data storage +- [**Authentication**](/mcp-gateway/concepts/authentication) - Token configuration +- [**Getting Started**](/mcp-gateway/getting-started) - Quick setup guide + + diff --git a/src/content/docs/mcp-gateway/configuration/storage.md b/src/content/docs/mcp-gateway/configuration/storage.md new file mode 100644 index 0000000..e000c56 --- /dev/null +++ b/src/content/docs/mcp-gateway/configuration/storage.md @@ -0,0 +1,142 @@ +--- +title: Storage +description: Data persistence and file organization +--- + +MCP Gateway stores server configuration and captured traffic locally using SQLite and JSON files. + +## Storage Location + +Files are stored under `~/.mcp-gateway/`: + +``` +~/.mcp-gateway/ +├── mcp.json # Server registry +├── logs.db # SQLite traffic logs +└── logs.db-* # SQLite files +``` + +### Default Directory + +``` +~/.mcp-gateway/ +``` + +### Custom Directory + +```bash +mcp-gateway --storage-dir /custom/path +``` + +Or via environment variable: + +```bash +MCP_GATEWAY_STORAGE_DIR=/custom/path mcp-gateway +``` + +## Directory Structure + +``` +~/.mcp-gateway/ +├── mcp.json # Server registry +└── gateway.db # SQLite database (captured traffic) +``` + +## Server Registry + +### File: `mcp.json` + +The registry stores server configurations in JSON format. + +### Format + +```json +{ + "servers": [ + { + "name": "github-server", + "url": "http://localhost:3000/mcp", + "headers": {} + }, + { + "name": "weather-api", + "url": "http://localhost:4000/mcp", + "headers": { + "Authorization": "Bearer token123" + } + } + ] +} +``` + +### Manual Editing + +You can manually edit `mcp.json`: + +```bash +# Edit registry +nano ~/.mcp-gateway/mcp.json + +# Restart gateway to apply changes +mcp-gateway +``` + +**Caution**: Invalid JSON will prevent the gateway from starting. + +### Backup + +```bash +# Backup registry +cp ~/.mcp-gateway/mcp.json ~/.mcp-gateway/mcp.json.backup + +# Restore from backup +cp ~/.mcp-gateway/mcp.json.backup ~/.mcp-gateway/mcp.json +``` + +## Captured Traffic (SQLite) + +### Database: `gateway.db` + +All captured MCP traffic is stored in a SQLite database for efficient querying and filtering. + +### Querying Directly + +You can query the database directly if needed: + +```bash +sqlite3 ~/.mcp-gateway/gateway.db + +# List tables +.tables + +# Query recent logs +SELECT * FROM logs ORDER BY timestamp DESC LIMIT 10; +``` + +### Data Retention + +By default, logs are kept indefinitely. Clean up via: + +**Web UI:** Use the "Clear Sessions" functionality + +**REST API:** + +```bash +curl -X POST \ + -H "Authorization: Bearer YOUR_TOKEN" \ + "http://localhost:3333/api/logs/clear?before=2025-01-01T00:00:00Z" +``` + +**Manual:** + +```bash +# Delete and recreate database +rm ~/.mcp-gateway/gateway.db +mcp-gateway +``` + +## Next Steps + +- [**CLI**](/mcp-gateway/configuration/cli) - Configure storage location +- [**Proxy**](/mcp-gateway/concepts/proxy) - How traffic is captured +- [**Web UI**](/mcp-gateway/interfaces/web-ui) - View captured traffic diff --git a/src/content/docs/mcp-gateway/core-concepts/activity-logging.md b/src/content/docs/mcp-gateway/core-concepts/activity-logging.md deleted file mode 100644 index cf3c645..0000000 --- a/src/content/docs/mcp-gateway/core-concepts/activity-logging.md +++ /dev/null @@ -1,239 +0,0 @@ ---- -title: Activity Logging -description: Track and inspect MCP requests and responses ---- - -MCP Gateway captures all traffic flowing through the proxy, providing detailed logs for debugging and monitoring. - -## What Gets Logged - -### Request Data - -For each request, the gateway logs: -- **Timestamp**: When the request was received -- **Server**: Which MCP server handled the request -- **Method**: The MCP method called -- **Parameters**: Request parameters (sanitized if needed) -- **Headers**: HTTP headers - -### Response Data - -For each response, the gateway logs: -- **Status**: Success or error -- **Result**: The response payload -- **Duration**: How long the request took -- **Size**: Response size in bytes - -### Example Log Entry - -```jsonl -{ - "timestamp": "2025-01-20T15:30:45.123Z", - "server": "github-server", - "method": "tools/list", - "params": {}, - "response": { - "tools": [ - { "name": "create_issue", "description": "..." } - ] - }, - "duration_ms": 45, - "status": "success" -} -``` - -## Log Storage - -### Storage Location - -Logs are stored in `~/.mcp-gateway/captures/`: - -``` -~/.mcp-gateway/ -├── mcp.json # Server registry -└── captures/ - ├── github-server/ - │ ├── 2025-01-20.jsonl - │ └── 2025-01-21.jsonl - └── weather-server/ - └── 2025-01-20.jsonl -``` - -### Log Format - -Logs are stored as **JSON Lines (JSONL)**: -- One JSON object per line -- Easy to parse and process -- Efficient for streaming - -### Log Rotation - -- Logs are organized by server and date -- Each day creates a new log file -- Old logs are retained based on storage settings - -## Inspecting Logs - -### Via Terminal UI - -Press `v` to open the Activity Log viewer: - -- **Navigation**: Use arrow keys to scroll -- **Filter**: Press `/` to search -- **Details**: Press Enter to view full request/response -- **Clear**: Press `c` to clear the current view (doesn't delete files) - -### Via Web UI - -Navigate to a server in the Web UI: - -1. Select a server from the dashboard -2. View the activity log in the sidebar -3. Click on entries to see details -4. Use filters to narrow down results - -### Via Command Line - -Logs are plain JSON Lines files, so you can use standard tools: - -```bash -# View today's logs for a server -cat ~/.mcp-gateway/captures/github-server/$(date +%Y-%m-%d).jsonl - -# Pretty-print logs -cat ~/.mcp-gateway/captures/github-server/*.jsonl | jq '.' - -# Filter by method -cat ~/.mcp-gateway/captures/github-server/*.jsonl | jq 'select(.method == "tools/list")' - -# Count requests per method -cat ~/.mcp-gateway/captures/github-server/*.jsonl | jq -r '.method' | sort | uniq -c -``` - -## Filtering and Searching - -### Terminal UI Filters - -In the Activity Log (`v`): -- `/`: Open search -- Type to filter by any field -- ESC to clear filter - -### Web UI Filters - -Use the filter controls to: -- Filter by date range -- Filter by server -- Filter by method -- Filter by status (success/error) -- Search in request/response data - -## Log Retention - -### Default Retention - -By default, logs are kept indefinitely. You can manually clean up old logs: - -```bash -# Remove logs older than 30 days -find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +30 -delete -``` - -### Custom Retention - -Set up a cron job for automatic cleanup: - -```bash -# Add to crontab: clean up logs older than 30 days daily -0 2 * * * find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +30 -delete -``` - -## Privacy and Security - -### Sensitive Data - -The gateway logs all request and response data. If your MCP servers handle sensitive information: - -- Avoid logging in production environments -- Implement log sanitization -- Restrict access to the storage directory -- Use encryption for log files - -### Log Access - -Protect log files with appropriate permissions: - -```bash -# Restrict access to logs -chmod 700 ~/.mcp-gateway -chmod 600 ~/.mcp-gateway/captures/**/*.jsonl -``` - -## Performance Considerations - -### Log Volume - -High-traffic servers generate large log files. Monitor disk usage: - -```bash -# Check log storage size -du -sh ~/.mcp-gateway/captures -``` - -### Impact on Gateway - -Logging has minimal performance impact: -- Logs written asynchronously -- Buffered writes for efficiency -- No impact on request/response latency - -## Use Cases - -### Debugging - -Inspect failed requests: - -```bash -# Find all errors -cat ~/.mcp-gateway/captures/*/*.jsonl | jq 'select(.status == "error")' -``` - -### Performance Analysis - -Analyze request durations: - -```bash -# Average response time -cat ~/.mcp-gateway/captures/my-server/*.jsonl | \ - jq '.duration_ms' | \ - awk '{sum+=$1; count++} END {print sum/count}' -``` - -### Usage Monitoring - -Track API usage: - -```bash -# Requests per hour -cat ~/.mcp-gateway/captures/my-server/*.jsonl | \ - jq -r '.timestamp' | \ - cut -d: -f1 | \ - sort | uniq -c -``` - -### Replay and Testing - -Use captured logs to replay requests for testing: - -```bash -# Extract a request -cat ~/.mcp-gateway/captures/my-server/*.jsonl | \ - jq 'select(.method == "tools/list") | .params' | \ - head -1 -``` - -## Next Steps - -- [**Interfaces**](/mcp-gateway/core-concepts/interfaces) - Learn about TUI and Web UI -- [**Storage & Registry**](/mcp-gateway/features/storage) - Understand data persistence -- [**Debugging**](/mcp-gateway/development/debugging) - Advanced debugging techniques diff --git a/src/content/docs/mcp-gateway/core-concepts/interfaces.md b/src/content/docs/mcp-gateway/core-concepts/interfaces.md deleted file mode 100644 index 9e7b74d..0000000 --- a/src/content/docs/mcp-gateway/core-concepts/interfaces.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -title: Interfaces -description: Terminal UI and Web UI for managing MCP Gateway ---- - -MCP Gateway provides two interfaces for managing servers and viewing logs: a Terminal UI (TUI) for keyboard-driven workflows and a Web UI for visual management. - -## Terminal UI (TUI) - -The Terminal UI runs in your console and provides fast, keyboard-driven access to all gateway features. - -### Starting the TUI - -```bash -# TUI starts by default -mcp-gateway - -# Disable TUI (headless mode) -mcp-gateway --no-tui -``` - -### Navigation - -Use keyboard shortcuts to navigate: - -- `/` - Open command menu -- `q` - Quit application -- `ESC` - Go back / Close modal -- Arrow keys - Navigate lists -- Enter - Select / View details - -### Main Views - -#### Activity Log (`v`) - -View real-time request/response activity: -- Scroll through recent events -- Filter by keyword -- View full request/response details -- Clear the current view - -#### Server Management (`m`) - -Manage MCP servers: -- View all configured servers -- See connection status -- Add new servers -- Remove servers - -#### Help (`h`) - -Access help and setup guide: -- Keyboard shortcuts reference -- Setup instructions -- Troubleshooting tips - -### Command Menu (`/`) - -Quick access to all commands: - -``` -/ - Command Menu -──────────────── -v - View Activity Log -m - Manage Servers -a - Add New Server -c - Clear Activity Logs -h - Help & Setup Guide -q - Quit -``` - -### Adding Servers - -Press `a` to add a server: - -``` -┌─ Add MCP Server ─────────────┐ -│ │ -│ Name: [____________] │ -│ URL: [____________] │ -│ │ -│ [Cancel] [Add] │ -└───────────────────────────────┘ -``` - -### Activity Log View - -``` -┌─ Activity Log ───────────────────────────────┐ -│ [Filter: ___________] │ -├──────────────────────────────────────────────┤ -│ ● 15:30:45 github-server tools/list 45ms │ -│ ● 15:30:50 weather-server query 120ms│ -│ ● 15:30:55 github-server tools/call 89ms │ -│ │ -│ Press Enter to view details │ -└──────────────────────────────────────────────┘ -``` - -### Terminal Compatibility - -Recommended terminals: -- **macOS**: iTerm2, Alacritty, Terminal.app -- **Linux**: Alacritty, kitty, gnome-terminal -- **Windows**: Windows Terminal, Alacritty - -Requirements: -- ANSI escape code support -- UTF-8 encoding -- Minimum 80x24 character size - -## Web UI - -The Web UI provides a browser-based interface for visual server management and log inspection. - -### Accessing the Web UI - -```bash -# Default URL -http://localhost:3333/ui - -# Custom port -http://localhost:8080/ui # if using --port 8080 -``` - -Or open automatically: - -```bash -open http://localhost:3333/ui # macOS -xdg-open http://localhost:3333/ui # Linux -``` - -### Dashboard - -The main dashboard shows: -- **Server List**: All configured MCP servers -- **Status Indicators**: Connection state for each server -- **Recent Activity**: Latest requests across all servers -- **Quick Actions**: Add/remove servers - -### Server Management - -Click on a server to: -- View detailed information -- See server-specific activity log -- Configure server settings -- Test connectivity -- Remove the server - -### Activity Inspection - -The activity view provides: -- **Timeline**: Chronological list of requests -- **Filters**: By server, method, date range, status -- **Search**: Full-text search in requests/responses -- **Details**: Click any entry to see full request/response - -Example log entry view: - -``` -Request -──────── -Method: tools/list -Server: github-server -Time: 2025-01-20 15:30:45 - -Response -──────── -Status: Success -Duration: 45ms -Result: -{ - "tools": [ - { - "name": "create_issue", - "description": "Create a GitHub issue" - } - ] -} -``` - -### Adding Servers - -Click "Add Server" button: - -1. Enter server name -2. Enter server URL -3. Click "Add" -4. Server appears in the list - -### Server Configuration - -Click on a server card to configure: -- Edit server name -- Update server URL -- View connection history -- Remove server - -## Choosing an Interface - -### Use Terminal UI When: - -- Working in a terminal-focused workflow -- Need keyboard-driven speed -- SSH into remote servers -- Limited screen space -- Prefer command-line tools - -### Use Web UI When: - -- Prefer visual interfaces -- Need to share view with others -- Want to keep logs visible while working -- Managing multiple servers visually -- Need detailed filtering and search - -## Running Both Simultaneously - -You can use both interfaces at the same time: - -```bash -# Start gateway (TUI + Web UI) -mcp-gateway - -# In your browser -open http://localhost:3333/ui -``` - -Both interfaces share the same data: -- Changes in TUI reflect in Web UI -- Web UI updates show in TUI -- Logs visible in both - -## Headless Mode - -Run without the TUI for background operation: - -```bash -mcp-gateway --no-tui -``` - -Useful for: -- Docker containers -- systemd services -- CI/CD environments -- Production deployments - -Access via Web UI only: `http://localhost:3333/ui` - -## Next Steps - -- [**Terminal UI Features**](/mcp-gateway/features/terminal-ui) - Master keyboard shortcuts -- [**Web Interface**](/mcp-gateway/features/web-interface) - Explore Web UI features -- [**CLI Options**](/mcp-gateway/features/cli-options) - Configure the gateway diff --git a/src/content/docs/mcp-gateway/core-concepts/server-management.md b/src/content/docs/mcp-gateway/core-concepts/server-management.md deleted file mode 100644 index 509a942..0000000 --- a/src/content/docs/mcp-gateway/core-concepts/server-management.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: Server Management -description: Add, configure, and monitor MCP servers ---- - -MCP Gateway acts as a proxy for multiple MCP servers, allowing you to manage them all from one interface. - -## Adding Servers - -### Via Terminal UI - -1. Press `a` to open the "Add Server" dialog -2. Enter server details: - - **Name**: A unique identifier for this server - - **URL**: The HTTP endpoint for the MCP server -3. Press Enter to save - -Example: -``` -Name: weather-server -URL: http://localhost:3000/mcp -``` - -### Via Web UI - -1. Navigate to `http://localhost:3333/ui` -2. Click "Add Server" -3. Fill in the form and submit - -### Via Registry File - -Manually edit `~/.mcp-gateway/mcp.json`: - -```json -{ - "servers": [ - { - "name": "weather-server", - "url": "http://localhost:3000/mcp" - }, - { - "name": "database-server", - "url": "http://localhost:4000/mcp" - } - ] -} -``` - -## Server Configuration - -### URL Format - -MCP Gateway expects HTTP endpoints that implement the MCP protocol: - -``` -http://localhost:3000/mcp -https://api.example.com/mcp -``` - -### Server Names - -- Must be unique within the registry -- Used to identify servers in logs and UI -- Can contain letters, numbers, hyphens, and underscores - -## Monitoring Servers - -### Server Status - -The gateway tracks the status of each server: - -- **Connected**: Server is reachable and responding -- **Disconnected**: Server is not responding -- **Error**: Server returned an error - -### Viewing Status - -**Terminal UI:** -- Press `m` to open Server Management -- View the status column for each server - -**Web UI:** -- Check the server dashboard -- Status indicators show connection state - -## Managing Servers - -### View Server List - -**TUI**: Press `m` -**Web UI**: Navigate to the servers page - -### Remove a Server - -**TUI**: -1. Press `m` to open Server Management -2. Select the server -3. Press `d` to delete - -**Web UI**: -1. Navigate to the server -2. Click "Remove Server" - -### Edit Server Configuration - -**Registry File**: -Edit `~/.mcp-gateway/mcp.json` and restart the gateway. - -## Connection Handling - -### Automatic Reconnection - -The gateway automatically attempts to reconnect to servers that become unavailable. - -### Connection Timeout - -If a server doesn't respond within the timeout period, it's marked as disconnected. - -### Error Handling - -Connection errors are logged in the activity log. View them with: -- **TUI**: Press `v` -- **Web UI**: Check the server's activity log - -## Multi-Server Routing - -The gateway routes requests to servers based on: -- Server name in the request -- Path-based routing (if configured) -- Round-robin (if multiple servers handle the same capability) - -## Best Practices - -### Naming Conventions - -Use descriptive names that reflect the server's purpose: -- ✅ `github-integration` -- ✅ `database-tools` -- ❌ `server1` -- ❌ `test` - -### URL Management - -- Use `http://localhost` for local development -- Use full URLs with HTTPS for production servers -- Ensure servers are accessible from the gateway's network - -### Server Organization - -Group related servers logically: -- Development servers on separate ports -- Production servers with HTTPS -- Test servers isolated from production - -## Troubleshooting - -### Server Won't Connect - -1. Verify the URL is correct -2. Check the server is running: `curl ` -3. Check for CORS issues (HTTP MCP servers) -4. Review server logs for errors - -### Server Shows Disconnected - -- Check network connectivity -- Verify the server is still running -- Look for errors in activity logs - -### Cannot Add Server - -- Ensure the name is unique -- Verify URL format is correct -- Check for typos in the URL - -## Next Steps - -- [**Activity Logging**](/mcp-gateway/core-concepts/activity-logging) - Track requests and responses -- [**Terminal UI**](/mcp-gateway/features/terminal-ui) - Master keyboard shortcuts -- [**Storage & Registry**](/mcp-gateway/features/storage) - Understand data persistence diff --git a/src/content/docs/mcp-gateway/docs.md b/src/content/docs/mcp-gateway/docs.md new file mode 100644 index 0000000..14424f4 --- /dev/null +++ b/src/content/docs/mcp-gateway/docs.md @@ -0,0 +1,208 @@ +## MCP Gateway — Technical Guide (Concise) + +Accurate, minimal docs for installing and operating MCP Gateway via a package manager. + +--- + +## Install + +Global: + +```bash +npm i -g @fiberplane/mcp-gateway +# or: yarn global add … | pnpm add -g … | bun add -g … +``` + +Ephemeral: + +```bash +npx mcp-gateway +# or: pnpm dlx @fiberplane/mcp-gateway | bunx @fiberplane/mcp-gateway +``` + +--- + +## Start + +```bash +mcp-gateway +``` + +Output includes port (default 3333) and Web UI URL with token: + +``` +Web UI: http://localhost:3333/ui?token= +``` + +--- + +## Endpoints + +- Web UI (token in query): `/ui?token=` +- REST API (Bearer token): `/api/*` +- Gateway MCP Server (Bearer token): `/gateway/mcp` +- Proxy (no auth; upstream handles auth): `/s/{serverName}/mcp` + +Auth token: + +```bash +export MCP_GATEWAY_TOKEN="my-secret-token" +mcp-gateway +``` + +--- + +## Getting Started + +- Add first server (Web UI): “Add Server” → name + URL → health check runs +- Proxy pattern: + ``` + http://localhost:3333/s/{serverName}/mcp + ``` + +--- + +## CLI + +```bash +mcp-gateway --port 8080 +mcp-gateway --storage-dir /custom/path +DEBUG=* mcp-gateway +mcp-gateway --help | --version +``` + +Env: + +- `MCP_GATEWAY_PORT` (default 3333) +- `MCP_GATEWAY_STORAGE` (default `~/.mcp-gateway`) +- `MCP_GATEWAY_TOKEN` (optional) +- `DEBUG` (`*`, `@fiberplane/*`) + +--- + +## Configuration + +Files under `~/.mcp-gateway/`: + +``` +~/.mcp-gateway/ +├── mcp.json # server registry +├── logs.db # SQLite logs +└── logs.db-* # SQLite files +``` + +HTTP server (mcp.json): + +```json +{ + "servers": [ + { + "name": "my-server", + "type": "http", + "url": "http://localhost:3000/mcp", + "enabled": true + } + ] +} +``` + +Stdio server (mcp.json): + +```json +{ + "servers": [ + { + "name": "memory", + "type": "stdio", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-memory"], + "sessionMode": "shared", + "timeout": 30000 + } + ] +} +``` + +Notes: + +- `sessionMode`: `"shared"` (default) or `"isolated"` (per `x-session-id`) +- Stdio servers are long-lived; restart via UI/API + +--- + +## REST API + +Base: + +``` +http://localhost:3333/api +``` + +Auth: + +```bash +curl -H "Authorization: Bearer " http://localhost:3333/api/servers +``` + +Common: + +- `GET /api/logs` +- `GET /api/servers` +- `POST /api/servers` +- `GET /api/health` + +Filtering and pagination: + +- Query params: `server`, `sessionId`, `method`, `limit` (max 1000), `order` (`asc|desc`) + +```bash +curl -H "Authorization: Bearer " \ + "http://localhost:3333/api/logs?server=my-server&sessionId=abc123&method=tools/list&limit=50&order=desc" +``` + +--- + +## Gateway MCP Server + +Endpoint: + +``` +http://localhost:3333/gateway/mcp +``` + +Tools: + +- `add_server`, `remove_server`, `list_servers`, `search_records` + Auth: Bearer token required. + +--- + +## Web UI + +- Activity Log (filter/search), Server management, Health, Export JSON +- Open: `http://localhost:3333/ui?token=` + +--- + +## Troubleshooting + +- Port in use: + ```bash + mcp-gateway --port 8080 + ``` +- Auth errors: + - Use full UI URL with `?token=…` or set `MCP_GATEWAY_TOKEN` +- Connectivity: + - Verify upstream URL, check UI health, inspect Activity Log +- Reset data: + ```bash + rm -rf ~/.mcp-gateway/ && mcp-gateway + ``` + +--- + +## FAQ + +- Logs location: `~/.mcp-gateway/logs.db` +- Proxy auth: upstream server handles its own auth +- Claude Desktop: no HTTP MCP support (can’t use proxy endpoints) diff --git a/src/content/docs/mcp-gateway/features/cli-options.md b/src/content/docs/mcp-gateway/features/cli-options.md deleted file mode 100644 index cde4dd1..0000000 --- a/src/content/docs/mcp-gateway/features/cli-options.md +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: CLI Options -description: Command-line configuration options for MCP Gateway ---- - -Configure MCP Gateway behavior using command-line flags. - -## Basic Usage - -```bash -mcp-gateway [options] -``` - -## Options - -### `--port ` - -Set the HTTP server port. - -```bash -# Use port 8080 instead of default 3333 -mcp-gateway --port 8080 -``` - -**Default:** `3333` - -**Example:** -```bash -mcp-gateway --port 8080 -# API: http://localhost:8080/api -# Web UI: http://localhost:8080/ui -``` - -### `--storage-dir ` - -Set custom storage directory for logs and registry. - -```bash -mcp-gateway --storage-dir /custom/path -``` - -**Default:** `~/.mcp-gateway` - -**Example:** -```bash -mcp-gateway --storage-dir ~/my-gateway-data -# Registry: ~/my-gateway-data/mcp.json -# Logs: ~/my-gateway-data/captures/ -``` - -### `--no-tui` - -Run in headless mode without the Terminal UI. - -```bash -mcp-gateway --no-tui -``` - -**Use Cases:** -- Docker containers with TTY allocated but headless mode desired -- systemd services -- CI/CD environments -- Background processes -- Multiple instances managed via Web UI only - -**Example:** -```bash -# Run in background -mcp-gateway --no-tui & - -# Access via Web UI -open http://localhost:3333/ui -``` - -### `--help` - -Display help information. - -```bash -mcp-gateway --help -``` - -**Output:** -``` -MCP Gateway - Unified proxy for MCP servers - -Usage: mcp-gateway [options] - -Options: - --port Set HTTP server port (default: 3333) - --storage-dir Set storage directory (default: ~/.mcp-gateway) - --no-tui Run without Terminal UI - --version Show version number - --help Show this help message -``` - -### `--version` - -Display version information. - -```bash -mcp-gateway --version -``` - -**Output:** -``` -@fiberplane/mcp-gateway v1.0.0 -``` - -## Combining Options - -You can combine multiple options: - -```bash -mcp-gateway --port 8080 --storage-dir ~/gateway --no-tui -``` - -This configures the gateway to: -- Run on port 8080 -- Store data in `~/gateway` -- Run without Terminal UI - -## Environment Variables - -Some configurations can be set via environment variables: - -### `MCP_GATEWAY_PORT` - -Alternative to `--port`: - -```bash -MCP_GATEWAY_PORT=8080 mcp-gateway -``` - -### `MCP_GATEWAY_STORAGE_DIR` - -Alternative to `--storage-dir`: - -```bash -MCP_GATEWAY_STORAGE_DIR=~/gateway mcp-gateway -``` - -**Note:** CLI flags take precedence over environment variables. - -## Configuration Precedence - -Options are applied in this order (highest to lowest): - -1. Command-line flags -2. Environment variables -3. Default values - -Example: - -```bash -# Port will be 9000 (CLI flag wins) -MCP_GATEWAY_PORT=8080 mcp-gateway --port 9000 -``` - -## Common Patterns - -### Development - -```bash -# Default settings, with TUI -mcp-gateway -``` - -### Production (systemd) - -```bash -# Headless, custom storage, non-default port -mcp-gateway --no-tui --port 8080 --storage-dir /var/lib/mcp-gateway -``` - -### Docker - -```bash -# Headless, standard port, volume-mounted storage -docker run -p 3333:3333 \ - -v ./data:/data \ - mcp-gateway --no-tui --storage-dir /data -``` - -### Multiple Instances - -```bash -# Instance 1 -mcp-gateway --port 3333 --storage-dir ~/.mcp-gateway-1 - -# Instance 2 -mcp-gateway --port 3334 --storage-dir ~/.mcp-gateway-2 -``` - -## Troubleshooting - -### Port Already in Use - -**Error:** `EADDRINUSE: address already in use :::3333` - -**Solution:** -```bash -# Find process using port -lsof -i :3333 - -# Kill process -kill -9 - -# Or use different port -mcp-gateway --port 8080 -``` - -### Permission Denied (Storage Directory) - -**Error:** `EACCES: permission denied, mkdir '/var/lib/mcp-gateway'` - -**Solution:** -```bash -# Create directory with proper permissions -sudo mkdir -p /var/lib/mcp-gateway -sudo chown $USER:$USER /var/lib/mcp-gateway - -# Or use user-writable directory -mcp-gateway --storage-dir ~/mcp-gateway -``` - -### Invalid Port Number - -**Error:** `Invalid port number: abc` - -**Solution:** -```bash -# Use numeric port between 1-65535 -mcp-gateway --port 3333 -``` - -## Next Steps - -- [**Terminal UI**](/mcp-gateway/features/terminal-ui) - Master keyboard shortcuts -- [**Storage & Registry**](/mcp-gateway/features/storage) - Understand data storage -- [**Production Deployment**](/mcp-gateway/deployment/production) - Deploy to production diff --git a/src/content/docs/mcp-gateway/features/storage.md b/src/content/docs/mcp-gateway/features/storage.md deleted file mode 100644 index 0459366..0000000 --- a/src/content/docs/mcp-gateway/features/storage.md +++ /dev/null @@ -1,370 +0,0 @@ ---- -title: Storage & Registry -description: Data persistence and file organization ---- - -MCP Gateway stores server configuration and captured logs in a local directory. - -## Storage Location - -### Default Directory - -``` -~/.mcp-gateway/ -``` - -### Custom Directory - -```bash -mcp-gateway --storage-dir /custom/path -``` - -Or via environment variable: - -```bash -MCP_GATEWAY_STORAGE_DIR=/custom/path mcp-gateway -``` - -## Directory Structure - -``` -~/.mcp-gateway/ -├── mcp.json # Server registry -└── captures/ # Captured logs - ├── github-server/ - │ ├── 2025-01-20.jsonl - │ ├── 2025-01-21.jsonl - │ └── 2025-01-22.jsonl - ├── weather-server/ - │ └── 2025-01-20.jsonl - └── database-server/ - └── 2025-01-20.jsonl -``` - -## Server Registry - -### File: `mcp.json` - -The registry stores server configurations. - -### Format - -```json -{ - "version": "1.0", - "servers": [ - { - "id": "github-server", - "name": "GitHub Integration", - "url": "http://localhost:3000/mcp", - "createdAt": "2025-01-20T10:00:00.000Z", - "updatedAt": "2025-01-20T10:00:00.000Z" - }, - { - "id": "weather-server", - "name": "Weather Service", - "url": "http://localhost:4000/mcp", - "createdAt": "2025-01-20T11:00:00.000Z", - "updatedAt": "2025-01-20T11:00:00.000Z" - } - ] -} -``` - -### Manual Editing - -You can manually edit `mcp.json`: - -```bash -# Edit registry -nano ~/.mcp-gateway/mcp.json - -# Restart gateway to apply changes -mcp-gateway -``` - -**Caution**: Invalid JSON will prevent the gateway from starting. - -### Backup - -```bash -# Backup registry -cp ~/.mcp-gateway/mcp.json ~/.mcp-gateway/mcp.json.backup - -# Restore from backup -cp ~/.mcp-gateway/mcp.json.backup ~/.mcp-gateway/mcp.json -``` - -## Capture Storage - -### Organization - -Logs are organized by server and date: - -``` -captures/ -└── / - └── YYYY-MM-DD.jsonl -``` - -### File Format: JSON Lines - -Each log file uses JSON Lines format: -- One JSON object per line -- Easy to parse and stream -- Append-only for performance - -### Example Log File - -```jsonl -{"timestamp":"2025-01-20T15:30:45.123Z","server":"github-server","method":"tools/list","params":{},"response":{"tools":[]},"duration_ms":45,"status":"success"} -{"timestamp":"2025-01-20T15:30:50.456Z","server":"github-server","method":"tools/call","params":{"name":"create_issue"},"response":{"content":[{"type":"text","text":"Issue created"}]},"duration_ms":89,"status":"success"} -``` - -### Log Rotation - -- New file created each day -- No automatic cleanup (manual or scripted) -- Files can be deleted without affecting the gateway - -## Data Persistence - -### When Data is Written - -**Registry (`mcp.json`):** -- When adding a server -- When removing a server -- When updating server configuration - -**Captures:** -- After each request/response -- Buffered writes for performance -- Flushed on gateway shutdown - -### Data Durability - -- Registry updates are atomic (safe from crashes) -- Logs written asynchronously (small risk of loss on crash) -- No data loss on clean shutdown - -## Disk Usage - -### Monitoring - -```bash -# Check total storage size -du -sh ~/.mcp-gateway - -# Check captures size -du -sh ~/.mcp-gateway/captures - -# Size by server -du -sh ~/.mcp-gateway/captures/* -``` - -### Example Sizes - -Approximate disk usage: -- Registry: ~1-10 KB -- Logs: ~1-10 MB per day per high-traffic server - -## Cleanup - -### Manual Cleanup - -```bash -# Remove old logs (older than 30 days) -find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +30 -delete - -# Remove all logs for a specific server -rm -rf ~/.mcp-gateway/captures/old-server -``` - -### Automated Cleanup - -Create a cron job: - -```bash -# Edit crontab -crontab -e - -# Add daily cleanup at 2 AM -0 2 * * * find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +30 -delete -``` - -### Cleanup Script - -```bash -#!/bin/bash -# cleanup-gateway-logs.sh - -STORAGE_DIR="${MCP_GATEWAY_STORAGE_DIR:-$HOME/.mcp-gateway}" -RETENTION_DAYS=30 - -find "$STORAGE_DIR/captures" \ - -name "*.jsonl" \ - -mtime +$RETENTION_DAYS \ - -delete - -echo "Cleaned up logs older than $RETENTION_DAYS days" -``` - -## Migration - -### Moving Storage Directory - -```bash -# Stop gateway -# Move directory -mv ~/.mcp-gateway ~/new-location/.mcp-gateway - -# Start with new location -mcp-gateway --storage-dir ~/new-location/.mcp-gateway -``` - -### Merging Registries - -```bash -# Backup both registries -cp ~/.mcp-gateway-1/mcp.json mcp1.json -cp ~/.mcp-gateway-2/mcp.json mcp2.json - -# Manually merge server arrays in a text editor -# Copy merged file to primary location -cp merged.json ~/.mcp-gateway/mcp.json -``` - -### Combining Logs - -```bash -# Merge logs for the same server from different gateways -cat ~/.mcp-gateway-1/captures/my-server/*.jsonl \ - ~/.mcp-gateway-2/captures/my-server/*.jsonl \ - > combined.jsonl - -# Sort by timestamp -cat combined.jsonl | jq -s 'sort_by(.timestamp)[]' > sorted.jsonl -``` - -## Backup and Restore - -### Full Backup - -```bash -# Backup entire storage directory -tar -czf mcp-gateway-backup-$(date +%Y%m%d).tar.gz ~/.mcp-gateway -``` - -### Restore from Backup - -```bash -# Stop gateway -# Extract backup -tar -xzf mcp-gateway-backup-20250120.tar.gz -C ~/ - -# Start gateway -mcp-gateway -``` - -### Selective Backup - -```bash -# Backup registry only -cp ~/.mcp-gateway/mcp.json mcp-backup.json - -# Backup logs for specific server -tar -czf github-server-logs.tar.gz ~/.mcp-gateway/captures/github-server -``` - -## Security - -### File Permissions - -Protect sensitive data: - -```bash -# Restrict directory access -chmod 700 ~/.mcp-gateway - -# Restrict registry access -chmod 600 ~/.mcp-gateway/mcp.json - -# Restrict logs -chmod 600 ~/.mcp-gateway/captures/**/*.jsonl -``` - -### Encryption - -For sensitive environments: - -```bash -# Encrypt storage directory (macOS) -hdiutil create -size 100m -encryption -volname "MCP Gateway" \ - -fs HFS+J ~/mcp-gateway-encrypted.dmg - -# Mount and use -hdiutil attach ~/mcp-gateway-encrypted.dmg -mcp-gateway --storage-dir /Volumes/MCP\ Gateway -``` - -### Git Ignore - -If storage is in a project directory: - -```gitignore -# .gitignore -.mcp-gateway/ -*.jsonl -mcp.json -``` - -## Troubleshooting - -### Registry Corrupted - -**Symptoms:** Gateway won't start, JSON parse error - -**Solution:** -```bash -# Restore from backup -cp ~/.mcp-gateway/mcp.json.backup ~/.mcp-gateway/mcp.json - -# Or recreate empty registry -echo '{"version":"1.0","servers":[]}' > ~/.mcp-gateway/mcp.json -``` - -### Disk Full - -**Symptoms:** ENOSPC error, logs not being written - -**Solution:** -```bash -# Check disk space -df -h - -# Clean up old logs -find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +7 -delete - -# Or move storage to larger disk -mv ~/.mcp-gateway /larger-disk/.mcp-gateway -mcp-gateway --storage-dir /larger-disk/.mcp-gateway -``` - -### Permission Denied - -**Symptoms:** EACCES error - -**Solution:** -```bash -# Fix permissions -chmod -R u+rw ~/.mcp-gateway - -# Or use different directory -mcp-gateway --storage-dir ~/mcp-data -``` - -## Next Steps - -- [**Activity Logging**](/mcp-gateway/core-concepts/activity-logging) - Understanding captured logs -- [**CLI Options**](/mcp-gateway/features/cli-options) - Configure storage location -- [**Debugging**](/mcp-gateway/development/debugging) - Inspect storage diff --git a/src/content/docs/mcp-gateway/features/terminal-ui.md b/src/content/docs/mcp-gateway/features/terminal-ui.md deleted file mode 100644 index 4d36162..0000000 --- a/src/content/docs/mcp-gateway/features/terminal-ui.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -title: Terminal UI -description: Keyboard shortcuts and TUI features ---- - -The Terminal UI (TUI) provides a fast, keyboard-driven interface for managing MCP servers and viewing activity logs. - -## Keyboard Shortcuts - -### Global - -| Key | Action | -|-----|--------| -| `/` | Open command menu | -| `q` | Quit application | -| `ESC` | Go back / Close modal | -| `h` | Help & Setup Guide | - -### Navigation - -| Key | Action | -|-----|--------| -| `↑` `↓` | Navigate up/down in lists | -| `←` `→` | Navigate left/right (where applicable) | -| `Enter` | Select / View details | -| `Tab` | Move between input fields | - -### Views - -| Key | Action | -|-----|--------| -| `v` | View Activity Log | -| `m` | Manage Servers | -| `a` | Add New Server | -| `c` | Clear Activity Logs (view only) | - -## Command Menu - -Press `/` to open the command menu: - -``` -┌─ Command Menu ──────────────────┐ -│ │ -│ v View Activity Log │ -│ m Manage Servers │ -│ a Add New Server │ -│ c Clear Activity Logs │ -│ h Help & Setup Guide │ -│ q Quit │ -│ │ -└──────────────────────────────────┘ -``` - -Navigate with arrow keys and press `Enter` to select. - -## Activity Log View - -Press `v` to view the activity log. - -### Features - -- **Real-time updates**: See requests as they happen -- **Filtering**: Press `/` to filter by keyword -- **Details**: Press `Enter` to view full request/response -- **Auto-scroll**: Automatically scrolls to show newest entries - -### Layout - -``` -┌─ Activity Log ────────────────────────────────────┐ -│ Filter: [______________] │ -├───────────────────────────────────────────────────┤ -│ Time Server Method Duration │ -├───────────────────────────────────────────────────┤ -│ ● 15:30:45 github-server tools/list 45ms │ -│ ● 15:30:50 weather-server query 120ms │ -│ ● 15:30:55 github-server tools/call 89ms │ -│ ● 15:31:00 database-server query 234ms │ -│ │ -│ ↑↓ Navigate Enter: Details /: Filter ESC: Back │ -└────────────────────────────────────────────────────┘ -``` - -### Filtering - -1. Press `/` while in Activity Log -2. Type your search term -3. Press `Enter` to apply -4. Press `ESC` to clear filter - -**Example filters:** -- `github` - Show only github-server logs -- `tools/list` - Show only tools/list method calls -- `error` - Show only errors - -### Viewing Details - -1. Navigate to an entry with arrow keys -2. Press `Enter` to view details - -``` -┌─ Request Details ─────────────────────────────────┐ -│ │ -│ Time: 2025-01-20 15:30:45 │ -│ Server: github-server │ -│ Method: tools/list │ -│ Duration: 45ms │ -│ Status: Success │ -│ │ -│ Request: │ -│ { │ -│ "params": {} │ -│ } │ -│ │ -│ Response: │ -│ { │ -│ "tools": [ │ -│ { │ -│ "name": "create_issue", │ -│ "description": "Create a GitHub issue" │ -│ } │ -│ ] │ -│ } │ -│ │ -│ Press ESC to close │ -└───────────────────────────────────────────────────┘ -``` - -### Clearing the View - -Press `c` to clear the current view: -- Clears the display buffer -- Does **not** delete log files -- Useful for reducing clutter - -## Server Management View - -Press `m` to manage servers. - -### Features - -- View all configured servers -- See connection status -- Navigate to add/remove servers -- Monitor server health - -### Layout - -``` -┌─ Server Management ────────────────────────────────┐ -│ │ -│ Name URL Status │ -├────────────────────────────────────────────────────┤ -│ ● github-server http://localhost:3000 Connected │ -│ ○ weather-server http://localhost:4000 Disconn. │ -│ ● database-server http://localhost:5000 Connected │ -│ │ -│ ↑↓ Navigate a: Add d: Delete Enter: Details │ -└────────────────────────────────────────────────────┘ -``` - -### Status Indicators - -- `●` (green) - Connected -- `○` (gray) - Disconnected -- `×` (red) - Error - -### Actions - -- `a` - Add new server -- `d` - Delete selected server (with confirmation) -- `Enter` - View server details - -## Add Server Dialog - -Press `a` to add a new server. - -``` -┌─ Add MCP Server ──────────────────────┐ -│ │ -│ Name: │ -│ ┌────────────────────────────────────┐ │ -│ │ my-server │ │ -│ └────────────────────────────────────┘ │ -│ │ -│ URL: │ -│ ┌────────────────────────────────────┐ │ -│ │ http://localhost:3000/mcp │ │ -│ └────────────────────────────────────┘ │ -│ │ -│ [Cancel] [Add] │ -└────────────────────────────────────────┘ -``` - -### Input Validation - -- **Name**: Must be unique, alphanumeric with hyphens/underscores -- **URL**: Must be valid HTTP/HTTPS URL - -### Keyboard Navigation - -- `Tab` - Move between fields -- `Enter` - Submit (when on Add button) -- `ESC` - Cancel - -## Help View - -Press `h` to view help and setup information. - -``` -┌─ Help & Setup Guide ──────────────────────────────┐ -│ │ -│ Keyboard Shortcuts: │ -│ / - Command Menu │ -│ v - View Activity Log │ -│ m - Manage Servers │ -│ a - Add New Server │ -│ c - Clear Activity Logs │ -│ h - Help │ -│ q - Quit │ -│ │ -│ Getting Started: │ -│ 1. Press 'a' to add your first MCP server │ -│ 2. Enter server name and URL │ -│ 3. Press 'v' to view activity │ -│ │ -│ Web UI: http://localhost:3333/ui │ -│ │ -│ Press ESC to close │ -└────────────────────────────────────────────────────┘ -``` - -## Terminal Compatibility - -### Recommended Terminals - -**macOS:** -- iTerm2 (recommended) -- Alacritty -- Terminal.app - -**Linux:** -- Alacritty (recommended) -- kitty -- gnome-terminal -- konsole - -**Windows:** -- Windows Terminal (recommended) -- Alacritty - -### Requirements - -- ANSI escape code support -- UTF-8 encoding -- Minimum 80x24 characters -- Recommended 120x30+ for best experience - -### Troubleshooting Display Issues - -**Garbled text or overlapping elements:** - -1. Ensure terminal supports ANSI codes -2. Try resizing the terminal window -3. Check UTF-8 encoding is enabled -4. Update terminal emulator to latest version - -**Colors not displaying:** - -1. Check terminal color support -2. Enable 256-color mode -3. Try a different terminal emulator - -## Tips and Tricks - -### Quick Navigation - -- Use `/` to quickly jump to any command -- Use `v` → `/` to filter logs without opening the menu - -### Multiple Windows - -Run multiple instances in different terminals: - -```bash -# Terminal 1 -mcp-gateway --port 3333 --storage-dir ~/.gateway-1 - -# Terminal 2 -mcp-gateway --port 3334 --storage-dir ~/.gateway-2 -``` - -### Background Mode - -Run TUI in one terminal, use another for work: - -```bash -# Terminal 1: Gateway TUI -mcp-gateway - -# Terminal 2: Development work -cd my-project && npm run dev -``` - -## Next Steps - -- [**Web Interface**](/mcp-gateway/features/web-interface) - Explore the Web UI -- [**CLI Options**](/mcp-gateway/features/cli-options) - Configure the gateway -- [**Activity Logging**](/mcp-gateway/core-concepts/activity-logging) - Understand logging diff --git a/src/content/docs/mcp-gateway/features/web-interface.md b/src/content/docs/mcp-gateway/features/web-interface.md deleted file mode 100644 index 8ae3246..0000000 --- a/src/content/docs/mcp-gateway/features/web-interface.md +++ /dev/null @@ -1,360 +0,0 @@ ---- -title: Web Interface -description: Browser-based UI for managing MCP Gateway ---- - -The Web UI provides a visual, browser-based interface for managing servers and inspecting activity logs. - -## Accessing the Web UI - -### Default URL - -``` -http://localhost:3333/ui -``` - -### Custom Port - -If running with `--port`: - -```bash -mcp-gateway --port 8080 -# Access at: http://localhost:8080/ui -``` - -### Opening Automatically - -```bash -# macOS -open http://localhost:3333/ui - -# Linux -xdg-open http://localhost:3333/ui - -# Windows -start http://localhost:3333/ui -``` - -## Dashboard - -The main dashboard provides an overview of your MCP infrastructure. - -### Server Cards - -Each server is displayed as a card showing: -- **Server name** -- **URL** -- **Status** (Connected/Disconnected/Error) -- **Recent activity count** -- **Last request time** - -### Quick Actions - -- **Add Server**: Click to add a new MCP server -- **Refresh**: Reload server status -- **Settings**: Configure gateway settings - -### Activity Summary - -View recent activity across all servers: -- Total requests in last hour -- Error rate -- Average response time -- Active servers count - -## Server Management - -### Adding a Server - -1. Click "Add Server" button -2. Fill in the form: - ``` - Name: [my-server] - URL: [http://localhost:3000/mcp] - ``` -3. Click "Add" -4. Server appears in the dashboard - -### Viewing Server Details - -Click on a server card to view: -- Full server configuration -- Connection status history -- Server-specific activity log -- Performance metrics - -### Editing a Server - -1. Click on a server card -2. Click "Edit" button -3. Update name or URL -4. Click "Save" - -### Removing a Server - -1. Click on a server card -2. Click "Remove Server" -3. Confirm deletion - -**Note**: Removing a server does not delete its logs. - -## Activity Log Browser - -The activity log browser provides powerful tools for inspecting captured traffic. - -### Accessing Logs - -**All Servers:** -- Click "Activity" in the main navigation -- View combined logs from all servers - -**Single Server:** -- Click on a server card -- View server-specific logs - -### Log Entry Display - -Each entry shows: -- **Timestamp** -- **Server name** -- **Method** (e.g., tools/list, query) -- **Duration** (in milliseconds) -- **Status** (Success/Error) - -### Filtering - -Use filters to narrow down logs: - -**By Time:** -- Last hour -- Last 24 hours -- Last 7 days -- Custom range - -**By Server:** -- Select one or more servers - -**By Method:** -- tools/list -- tools/call -- resources/list -- Custom method - -**By Status:** -- Success only -- Errors only -- All - -### Search - -Full-text search across: -- Request parameters -- Response data -- Error messages - -``` -Search: [create_issue] -``` - -### Viewing Details - -Click on any log entry to see: - -``` -┌─────────────────────────────────────┐ -│ Request Details │ -├─────────────────────────────────────┤ -│ Time: 2025-01-20 15:30:45 │ -│ Server: github-server │ -│ Method: tools/call │ -│ Duration: 89ms │ -│ Status: Success │ -│ │ -│ Request: │ -│ { │ -│ "name": "create_issue", │ -│ "arguments": { │ -│ "title": "Bug report", │ -│ "body": "Description..." │ -│ } │ -│ } │ -│ │ -│ Response: │ -│ { │ -│ "content": [ │ -│ { │ -│ "type": "text", │ -│ "text": "Issue created: #42" │ -│ } │ -│ ] │ -│ } │ -└─────────────────────────────────────┘ -``` - -### Exporting Logs - -Export filtered logs: - -1. Apply desired filters -2. Click "Export" -3. Choose format: - - JSON - - CSV - - JSON Lines - -## Performance Monitoring - -### Server Health - -View server health metrics: -- Uptime -- Request count -- Error rate -- Average response time - -### Request Timeline - -Visual timeline of requests: -- Scatter plot of request times -- Color-coded by status -- Hover for details - -### Response Time Distribution - -Histogram showing: -- Response time ranges -- Request count per bucket -- Percentiles (p50, p95, p99) - -## Settings - -### Gateway Configuration - -View and configure: -- Port number -- Storage directory -- Log retention settings - -### UI Preferences - -Customize the Web UI: -- Theme (Light/Dark/Auto) -- Refresh interval -- Items per page -- Timezone - -## Real-Time Updates - -The Web UI updates in real-time: -- New log entries appear automatically -- Server status changes reflect immediately -- Activity counts update live - -No manual refresh needed! - -## Browser Compatibility - -Supported browsers: -- **Chrome** 90+ -- **Firefox** 88+ -- **Safari** 14+ -- **Edge** 90+ - -Recommended: Latest version of Chrome or Firefox - -## Mobile Support - -The Web UI is responsive and works on mobile devices: -- Phones: Basic server management and log viewing -- Tablets: Full feature set - -Recommended for mobile: -- Use landscape orientation -- Minimum screen width: 375px - -## Tips and Tricks - -### Keyboard Shortcuts - -| Key | Action | -|-----|--------| -| `/` | Focus search | -| `r` | Refresh servers | -| `a` | Add server | -| `ESC` | Close modal | - -### Quick Filters - -Save frequently used filter combinations: - -1. Apply filters -2. Click "Save Filter" -3. Name your filter preset -4. Access from "Saved Filters" menu - -### Bookmarking - -Bookmark URLs with filters: - -``` -http://localhost:3333/ui/activity?server=github&status=error -``` - -Direct link to filtered view! - -### Multi-Tab Workflow - -Open multiple tabs: -- Tab 1: Dashboard (overview) -- Tab 2: Server A logs -- Tab 3: Server B logs - -All tabs update in real-time. - -## Development Mode - -When running the gateway with Vite dev server: - -```bash -# Terminal 1: Gateway -mcp-gateway - -# Terminal 2: Vite dev server -cd packages/web && npm run dev -``` - -Access at `http://localhost:5173` for hot reload during development. - -## Troubleshooting - -### Stale Data - -If the UI shows outdated information: - -1. Hard refresh: `Cmd+Shift+R` (macOS) or `Ctrl+Shift+R` (Windows/Linux) -2. Clear browser cache -3. Check gateway is running -4. Restart the gateway - -### UI Not Loading - -**Symptoms:** 404 error at `/ui` - -**Solutions:** -1. Verify gateway is running -2. Check the correct port -3. Ensure public folder exists (development builds) - -### Slow Performance - -If the UI is slow: -1. Reduce refresh interval in settings -2. Apply filters to reduce log count -3. Clear old logs -4. Check browser console for errors - -## Next Steps - -- [**Terminal UI**](/mcp-gateway/features/terminal-ui) - Learn keyboard shortcuts -- [**CLI Options**](/mcp-gateway/features/cli-options) - Configure the gateway -- [**Activity Logging**](/mcp-gateway/core-concepts/activity-logging) - Understand logging diff --git a/src/content/docs/mcp-gateway/getting-started.md b/src/content/docs/mcp-gateway/getting-started.md deleted file mode 100644 index 1bd61e2..0000000 --- a/src/content/docs/mcp-gateway/getting-started.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: Getting Started -description: Install and set up MCP Gateway ---- - -Get up and running with MCP Gateway in minutes. - -## Installation - -### NPM - -```bash -npm install -g @fiberplane/mcp-gateway -``` - -### Bun - -```bash -bun add -g @fiberplane/mcp-gateway -``` - -### Platform Binaries - -Download platform-specific binaries from the [releases page](https://github.com/fiberplane/mcp-gateway/releases): - -- `mcp-gateway-darwin-arm64` - macOS Apple Silicon -- `mcp-gateway-darwin-x64` - macOS Intel -- `mcp-gateway-linux-x64` - Linux -- `mcp-gateway-windows-x64` - Windows - -## Quick Start - -### 1. Start the Gateway - -```bash -mcp-gateway -``` - -This starts the gateway with: -- **Terminal UI** in your current shell -- **API server** on port 3333 -- **Web UI** at `http://localhost:3333/ui` - -### 2. Add Your First MCP Server - -In the Terminal UI, press `a` to add a new server: - -``` -Name: my-server -URL: http://localhost:3000/mcp -``` - -Or use the Web UI at `http://localhost:3333/ui`. - -### 3. Test the Connection - -The gateway will automatically attempt to connect to your server. Check the status in: -- **TUI**: Press `m` to view server management -- **Web UI**: Navigate to the dashboard - -### 4. View Activity Logs - -See requests and responses in real-time: -- **TUI**: Press `v` to view activity log -- **Web UI**: Click on a server to see its logs - -## Basic Configuration - -### Custom Port - -```bash -mcp-gateway --port 8080 -``` - -### Custom Storage Directory - -```bash -mcp-gateway --storage-dir /custom/path -``` - -### Headless Mode - -Run without the Terminal UI (useful for Docker, systemd, or background processes): - -```bash -mcp-gateway --no-tui -``` - -Access the Web UI at `http://localhost:3333/ui` to manage servers. - -## Common Commands - -```bash -# Show help -mcp-gateway --help - -# Show version -mcp-gateway --version - -# Start with custom settings -mcp-gateway --port 8080 --storage-dir ~/.my-gateway -``` - -## Verifying Installation - -Check that the gateway is running: - -```bash -# Check API health -curl http://localhost:3333/api/health - -# Or visit in browser -open http://localhost:3333/ui -``` - -## Next Steps - -- [**Server Management**](/mcp-gateway/core-concepts/server-management) - Add and configure MCP servers -- [**Terminal UI**](/mcp-gateway/features/terminal-ui) - Learn keyboard shortcuts -- [**CLI Options**](/mcp-gateway/features/cli-options) - Explore all command-line options diff --git a/src/content/docs/mcp-gateway/getting-started.mdx b/src/content/docs/mcp-gateway/getting-started.mdx new file mode 100644 index 0000000..acd5927 --- /dev/null +++ b/src/content/docs/mcp-gateway/getting-started.mdx @@ -0,0 +1,115 @@ +--- +title: Getting Started +description: Install and set up MCP Gateway +--- + +import { Tabs, TabItem } from "@astrojs/starlight/components"; +import { Steps } from "@astrojs/starlight/components"; + +## Installation + +MCP Gateway is available for installation through JavaScript package managers such as npm, pnpm, or bun. + +{/* prettier-ignore */} + + + ```bash + npm install -g @fiberplane/mcp-gateway + ``` + + + ```bash + pnpm add -g @fiberplane/mcp-gateway + ``` + + + ```bash + bun add -g @fiberplane/mcp-gateway + ``` + + + +Alternatively, the mcp-gateway runs directly from its [repository](https://github.com/fiberplane/mcp-gateway) +More details [here](https://github.com/fiberplane/mcp-gateway?tab=readme-ov-file#alternatively-you-can-run-the-mcp-gateway-from-the-repo) + +### Quickstart + + + +1. **Start the Gateway**: + + ```bash + mcp-gateway + ``` + + - Web UI at `http://localhost:3333/ui` , using the authentication token provided in the terminal output + - API server at `http://localhost:3333/api` + +2. **Adding an MCP Server via the Web UI** + + - Go to **Manage Servers** in the right sidebar, then click **Add Server**. + ![Adding an MCP server via Web UI](/src/assets/adding-mcp-server.png) + + - Fill in the server details + ![Form to add an MCP server](/src/assets/add-mcp-server-form.png) + +3. **Connect MCP client** + + Connect the MCP client through the gateway. For example for Claude: + + ``` + claude mcp add --transport http "linear-mcp" \ + "http://localhost:3333/s/linear-mcp/mcp" + ``` + +4. **Viewing Activity Logs** + + View requests, responses, timing, and token usage in real-time via the Web UI + ![MCP server logs](/src/assets/mcp-server-logs.png) + + + +## Basic Configuration + +### Custom Port + +```bash +mcp-gateway --port 8080 +``` + +### Custom Storage Directory + +```bash +mcp-gateway --storage-dir /custom/path +``` + +## Common Commands + +```bash +# Show help +mcp-gateway --help + +# Show version +mcp-gateway --version + +# Start with custom settings +mcp-gateway --port 8080 --storage-dir ~/.my-gateway +``` + +## Verifying Installation + +The gateway runs locally and exposes a Web UI and API endpoints that require bearer token authentication. + +Web UI: Access the interface at http://localhost:3333/ui using the authentication token displayed in the terminal output. + +API endpoints: Requests to the gateway API require a bearer token for authentication. Example usage: + +``` +curl -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxx" http://localhost:3333/api/logs +``` + +## Next Steps + +- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Learn more about the Web UI features +- [**CLI**](/mcp-gateway/configuration/cli) - Explore all command-line options +- [**Proxy**](/mcp-gateway/concepts/proxy) - Learn how the proxy works diff --git a/src/content/docs/mcp-gateway/index.md b/src/content/docs/mcp-gateway/index.md index 3c55023..c57de4e 100644 --- a/src/content/docs/mcp-gateway/index.md +++ b/src/content/docs/mcp-gateway/index.md @@ -3,73 +3,96 @@ title: Overview description: Unified gateway for managing and debugging MCP servers --- -MCP Gateway is a unified HTTP proxy for managing, routing, and debugging multiple Model Context Protocol servers with ease. +MCP Gateway is a unified HTTP proxy for managing, routing, and debugging multiple Model Context Protocol (MCP) servers. ## What is MCP Gateway? -MCP Gateway provides a local development tool that acts as a proxy between your AI applications and multiple MCP servers. It combines a **Terminal UI (TUI)** and **Web UI** to help you: +MCP Gateway is a local development tool that proxies communication between AI applications and multiple MCP servers. MCP Gateway runs from a terminal command and exposes a Web UI for managing and interacting with MCP servers. The gateway provides capabilities for: -- Manage multiple MCP servers from a single interface -- Inspect and debug request/response traffic -- Monitor server activity in real-time -- Store and replay captured logs +- Managing multiple MCP servers from a single interface +- Inspecting and debugging request/response traffic +- Monitoring server activity in real-time +- Storing and replaying captured logs ## Key Features ### Multi-Server Management -Add, configure, and monitor multiple MCP servers from one place. Switch between servers seamlessly and manage their lifecycle. + +The gateway allows multiple MCP servers to be added, configured, and monitored from a single interface. Switching between servers and managing their lifecycle is supported seamlessly. ### Activity Logging -Capture all requests and responses flowing through the gateway. Inspect detailed logs, filter by server or time, and debug issues faster. -### Dual Interfaces -- **Terminal UI**: Keyboard-driven interface for power users -- **Web UI**: Browser-based dashboard for visual server management +The gateway captures all requests and responses passing through it. Logs can be filtered by server or time, providing detailed information to facilitate debugging + +### Interface + +The Gateway comes with a Web-UI with browser-based dashboard for visual server management ### Local Development -Run the gateway locally during development to test and debug MCP integrations before deploying to production. + +The gateway runs locally during development, supporting testing and debugging of MCP integrations before deployment to production. ## Use Cases ### Local MCP Development -Develop and test MCP servers locally with full request/response visibility. The gateway acts as an intermediary, logging all traffic for inspection. + +MCP Gateway supports local development and testing of MCP servers with complete visibility into request and response traffic. It operates as an intermediary, logging all communication for inspection. ### Multi-Server Coordination -Route requests to different MCP servers based on your needs. Manage complex setups with multiple specialized servers. + +The gateway facilitates routing requests to multiple MCP servers and managing complex setups with specialized servers efficiently. ### Request Debugging -Inspect the exact requests sent to MCP servers and responses received. Identify issues quickly with detailed logging. + +Captured requests and responses can be inspected in detail, aiding in the identification and resolution of issues. ### Activity Monitoring -Track server health, response times, and error rates. Monitor your MCP infrastructure in real-time. + +The gateway provides real-time monitoring of server health, response times, and error rates, offering full visibility into the MCP infrastructure. ## Architecture +The gateway operates in dual mode: it's both a proxy for MCP servers AND an MCP server itself. + ``` -┌─────────────┐ -│ AI Client │ -└──────┬──────┘ - │ - ▼ -┌─────────────────┐ -│ MCP Gateway │ -│ ┌──────────┐ │ -│ │ TUI │ │ -│ └──────────┘ │ -│ ┌──────────┐ │ -│ │ Web UI │ │ -│ └──────────┘ │ -│ ┌──────────┐ │ -│ │ Proxy │ │ -│ └──────────┘ │ -│ ┌──────────┐ │ -│ │ Storage │ │ -│ └──────────┘ │ -└────┬────┬───┬───┘ - │ │ │ - ▼ ▼ ▼ - MCP MCP MCP - Server1 2 3 +┌───────────────────────────────────────────────────────────────┐ +│ MCP Gateway │ +│ │ +│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────────┐ │ +│ │ Web UI │ │ Gateway MCP │ │ MCP Proxy Router │ │ +│ │ (React) │ │ Server │ │ (/s/{name}/mcp) │ │ +│ │ (/ui) │ │ (/gateway/ │ │ │ │ +│ │ │ │ mcp) │ │ - Traffic capture │ │ +│ └──────┬──────┘ │ │ │ - Request routing │ │ +│ │ │ Tools: │ └───────────┬───────────┘ │ +│ │ │ • add_server│ │ │ +│ │ │ • remove_ │ │ │ +│ │ │ server │ │ │ +│ │ │ • list_ │ │ │ +│ │ │ servers │ │ │ +│ │ │ • search_ │ │ │ +│ │ │ records │ │ │ +│ │ └──────┬───────┘ │ │ +│ └────────────────┼──────────────────────┘ │ +│ │ │ +│ ┌────────────────▼──────────────────┐ │ +│ │ REST API (/api) │ │ +│ │ (Powers Web UI) │ │ +│ └────────────────┬──────────────────┘ │ +│ │ │ +│ ┌────────────────▼──────────────────┐ │ +│ │ Storage & Log Management │ │ +│ │ (SQLite + mcp.json registry) │ │ +│ └────────────────┬──────────────────┘ │ +│ │ │ +└──────────────────────────┼────────────────────────────────────┘ + │ + ┌───────────┼───────────┐ + │ │ │ + ┌──────▼───┐ ┌────▼────┐ ┌───▼──────┐ + │ MCP │ │ MCP │ │ MCP │ + │ Server 1 │ │ Server 2│ │ Server N │ + └──────────┘ └─────────┘ └──────────┘ ``` ## Quick Example @@ -81,16 +104,11 @@ npm install -g @fiberplane/mcp-gateway # Start the gateway mcp-gateway -# Add a server (in TUI, press 'a') -# Name: my-server -# URL: http://localhost:3000/mcp - -# Access Web UI -open http://localhost:3333/ui +# To access the web interface, copy the Web UI URL with the authetication token from your terminal output: ``` +![Terminal Output after starting the gateway](/src/assets/terminal-output.png) + ## Next Steps - [**Getting Started**](/mcp-gateway/getting-started) - Install and configure MCP Gateway -- [**Server Management**](/mcp-gateway/core-concepts/server-management) - Learn to manage MCP servers -- [**Terminal UI**](/mcp-gateway/features/terminal-ui) - Master keyboard shortcuts and TUI features diff --git a/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md b/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md new file mode 100644 index 0000000..5712705 --- /dev/null +++ b/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md @@ -0,0 +1,89 @@ +--- +title: Gateway MCP Server +description: Manage the gateway using MCP tools +--- + +The gateway exposes its own MCP server with tools for programmatic control. Any MCP client (like Claude Desktop, Cursor, or custom clients) can connect and manage the gateway. + +## Endpoint + +``` +http://localhost:3333/gateway/mcp +``` + +Or the shorthand: + +``` +http://localhost:3333/g/mcp +``` + +:::note +This endpoint requires Bearer token authentication. Include the token in the `Authorization` header. +::: + +## Available Tools + +The gateway exposes these MCP tools for server management: + +### `add_server` + +Add a new MCP server to the gateway registry. + +**Parameters:** + +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------------- | +| `name` | string | Yes | Unique server identifier (alphanumeric, hyphens, underscores) | +| `url` | string | Yes | Full HTTP/HTTPS URL to the MCP server | +| `headers` | object | No | Custom HTTP headers for authentication | + +--- + +### `remove_server` + +Remove a server from the gateway registry. + +**Parameters:** + +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ---------------------------- | +| `name` | string | Yes | Name of the server to remove | + +--- + +### `list_servers` + +List all registered servers with optional filtering. + +**Parameters:** + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ------------------------------------------------------- | +| `filter` | enum | No | `"all"`, `"active"`, or `"inactive"` (default: `"all"`) | +| `format` | enum | No | `"concise"` or `"detailed"` (default: `"concise"`) | + +--- + +### `search_records` + +Search and analyze captured MCP traffic. + +**Parameters:** + +| Parameter | Type | Required | Description | +| ------------ | ------ | -------- | ----------------------------------------------- | +| `serverName` | string | No | Filter by server name | +| `sessionId` | string | No | Filter by session ID | +| `method` | string | No | Filter by JSON-RPC method (partial match) | +| `limit` | number | No | Max records to return (default: 100, max: 1000) | +| `order` | enum | No | `"asc"` or `"desc"` (default: `"desc"`) | + +## Using with MCP Clients + +Any MCP client that supports HTTP transport can connect to the gateway's MCP server. + +## Next Steps + +- [**REST API**](/mcp-gateway/interfaces/rest-api) - HTTP API reference +- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Visual management +- [**Proxy**](/mcp-gateway/concepts/proxy) - Route traffic through the gateway diff --git a/src/content/docs/mcp-gateway/interfaces/rest-api.md b/src/content/docs/mcp-gateway/interfaces/rest-api.md new file mode 100644 index 0000000..045cdd3 --- /dev/null +++ b/src/content/docs/mcp-gateway/interfaces/rest-api.md @@ -0,0 +1,278 @@ +--- +title: REST API +description: HTTP API reference for MCP Gateway +--- + +The MCP Gateway provides an HTTP API for programmatic access to server management, activity logs, and session information. This API is primarily used by the Web UI but is available for programmatic access. + +## Base URL + +``` +http://localhost:3333/api +``` + +Or your configured port: + +```bash +# If using custom port +http://localhost:8080/api +``` + +## Authentication + +All API endpoints require Bearer token authentication: + +```http +Authorization: Bearer YOUR_API_TOKEN +``` + +### Getting Your API Token + +The API token is **displayed in the console** when the gateway starts: + +![Token](/src/assets/terminal-output.png) + +## Endpoints + +### GET /api/logs + +Retrieve activity logs from all servers. + +**Query Parameters:** + +| Parameter | Type | Description | +| ------------ | ------ | ----------------------------------------- | +| `serverName` | string | Filter by server name | +| `method` | string | Filter by MCP method (e.g., `tools/list`) | +| `sessionId` | string | Filter by session ID | +| `limit` | number | Maximum number of entries (default: 100) | +| `before` | string | Cursor for pagination (oldest timestamp) | +| `after` | string | Cursor for pagination (newest timestamp) | + +**Example Request:** + +```bash +curl -H "Authorization: Bearer YOUR_TOKEN" \ + "http://localhost:3333/api/logs?serverName=linear-mcp&limit=2" +``` + +**Example Response:** + +```json +{ + "data": [ + { + "timestamp": "2025-12-02T13:30:47.543Z", + "method": "tools/call", + "id": "2", + "direction": "request", + "metadata": { + "serverName": "linear-mcp", + "sessionId": "d87bc227...", + "durationMs": 89, + "httpStatus": 200, + "userAgent": "claude-code/2.0.55", + "clientIp": "::1", + "inputTokens": 13, + "methodDetail": "list_issues(assignee: \"me\")" + }, + "request": { ... }, + "response": { ... } + } + ], + "pagination": { + "count": 2, + "limit": 2, + "hasMore": true, + "oldestTimestamp": "2025-12-02T13:11:22.216Z", + "newestTimestamp": "2025-12-02T13:30:47.543Z" + } +} +``` + +--- + +### GET /api/servers + +List all registered MCP servers. + +**Example Request:** + +```bash +curl -H "Authorization: Bearer YOUR_TOKEN" \ + http://localhost:3333/api/servers +``` + +**Example Response:** + +```json +{ + "servers": [ + { + "name": "linear-mcp", + "status": "online", + "url": "https://mcp.linear.app/mcp", + "health": "up", + "lastCheckTime": 1764686521450, + "lastHealthyTime": 1764686521450, + "responseTimeMs": 80 + } + ] +} +``` + +**Response Fields:** + +| Field | Type | Description | +| ----------------- | ------ | -------------------------------------------- | +| `name` | string | Server identifier | +| `url` | string | Server endpoint URL | +| `status` | string | Server status: `online` or `offline` | +| `health` | string | Health status: `up`, `down`, or `unknown` | +| `lastCheckTime` | number | Unix timestamp of last health check (ms) | +| `lastHealthyTime` | number | Unix timestamp of last successful check (ms) | +| `responseTimeMs` | number | Last response time in milliseconds | + +--- + +### POST /api/servers + +Add a new MCP server. + +**Request Body:** + +```json +{ + "name": "weather-api", + "url": "http://localhost:3001/mcp", + "headers": { + "Authorization": "Bearer token123" + } +} +``` + +**Example Request:** + +```bash +curl -X POST http://localhost:3333/api/servers \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -d '{"name": "test-server", "url": "http://localhost:3001/mcp"}' +``` + +--- + +### GET /api/sessions + +Retrieve active and recent MCP sessions. + +**Example Request:** + +```bash +curl -H "Authorization: Bearer YOUR_TOKEN" \ + http://localhost:3333/api/sessions +``` + +**Example Response:** + +```json +{ + "sessions": [ + { + "sessionId": "d87bc227931ab7d8...", + "serverName": "linear-mcp", + "startTime": "2025-12-02T13:11:22.034Z", + "endTime": "2025-12-02T13:30:47.543Z" + } + ] +} +``` + +**Special Values:** + +- `sessionId: "stateless"` - Indicates a stateless session (no session ID provided by client) + +--- + +### GET /api/clients + +List connected clients. + +**Example Request:** + +```bash +curl -H "Authorization: Bearer YOUR_TOKEN" \ + http://localhost:3333/api/clients +``` + +**Example Response:** + +```json +{ + "clients": [ + { + "clientName": "claude-code", + "clientVersion": "2.0.55" + } + ] +} +``` + +--- + +### POST /api/logs/clear + +Clear activity logs. + +**Query Parameters:** + +| Parameter | Type | Description | +| ------------ | ------ | ------------------------------------------------ | +| `serverName` | string | Clear only logs for specific server (optional) | +| `before` | string | Clear only logs before this timestamp (optional) | + +**Example Request:** + +```bash +# Clear all logs +curl -X POST \ + -H "Authorization: Bearer YOUR_TOKEN" \ + http://localhost:3333/api/logs/clear + +# Clear logs for specific server +curl -X POST \ + -H "Authorization: Bearer YOUR_TOKEN" \ + "http://localhost:3333/api/logs/clear?serverName=linear-mcp" +``` + +--- + +### GET /api/health + +Health check endpoint. + +**Example Request:** + +```bash +curl -H "Authorization: Bearer YOUR_TOKEN" \ + http://localhost:3333/api/health +``` + +--- + +## Error Responses + +All endpoints return standard HTTP error codes: + +| Status | Description | +| ------ | --------------------------------------- | +| `401` | Missing or invalid authentication token | +| `400` | Invalid query parameters | +| `404` | Resource not found | +| `500` | Internal server error | + +## Next Steps + +- [**Gateway MCP Server**](/mcp-gateway/interfaces/gateway-mcp-server) - MCP-based programmatic control +- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Visual server management +- [**Proxy**](/mcp-gateway/concepts/proxy) - Using the gateway as a proxy diff --git a/src/content/docs/mcp-gateway/interfaces/web-ui.md b/src/content/docs/mcp-gateway/interfaces/web-ui.md new file mode 100644 index 0000000..e530693 --- /dev/null +++ b/src/content/docs/mcp-gateway/interfaces/web-ui.md @@ -0,0 +1,91 @@ +--- +title: Web UI +description: Browser-based dashboard for managing MCP Gateway +--- + +The Web UI provides a visual, browser-based interface for managing servers and inspecting activity logs. + +## Accessing the Web UI + +### Default URL + +``` +http://localhost:3333/ui?token=YOUR_TOKEN +``` + +The token is displayed in the terminal when the gateway starts. Copy the full URL from the terminal output. + +### Custom Port + +If running with `--port`: + +```bash +mcp-gateway --port 8080 +# Access at: http://localhost:8080/ui?token=YOUR_TOKEN +``` + +## Features + +The Web UI provides: + +- **Activity Log** - View all captured MCP traffic with filtering +- **Server Management** - Add, edit, remove, and monitor servers +- **Health Status** - Real-time health checks for all servers +- **Export Logs** - Export captured traffic as JSON +- **Search & Filter** - Find specific requests by server, method, or content + +## Dashboard + +The main dashboard shows your registered MCP servers and their activity. + +### Manage Servers + +- **Add Server** - Register a new MCP server with the gateway +- **View Server Details** - Click on any server to see health information, gateway URL, and configuration +- **Edit Server** - Modify the origin URL of a registered server +- **Remove Server** - Delete a server from the registry + +### Logs + +View all logs across servers, or select a specific server to filter the activity log. Additional filters available: + +- **Token** +- **Client** +- **Duration** +- **Method** +- **Session** + +#### Viewing Log Details + +Click on any log entry to see the full request and response details including: + +- Timestamp +- Server name +- Method called +- Duration +- Request parameters +- Response data + +#### Exporting Logs + +The dashboard allows exporting selected logs as JSONL. + +### Popular MCP Servers + +We've collected some of the most popular MCP servers. These remote servers are available directly through the marketplace. + +## Real-Time Updates + +The Web UI updates in real-time: + +- New log entries appear automatically +- Server status changes reflect immediately +- Activity counts update live + +No manual refresh needed! + +## Next Steps + +- [**REST API**](/mcp-gateway/interfaces/rest-api) - Programmatic access +- [**Gateway MCP Server**](/mcp-gateway/interfaces/gateway-mcp-server) - MCP-based control +- [**CLI**](/mcp-gateway/configuration/cli) - Command-line options diff --git a/src/content/docs/mcp-gateway/troubleshooting.md b/src/content/docs/mcp-gateway/troubleshooting.md deleted file mode 100644 index f969de4..0000000 --- a/src/content/docs/mcp-gateway/troubleshooting.md +++ /dev/null @@ -1,469 +0,0 @@ ---- -title: Troubleshooting -description: Common issues and solutions ---- - -Solutions to common problems when using MCP Gateway. - -## Installation Issues - -### NPM Install Fails - -**Symptom:** `npm install -g @fiberplane/mcp-gateway` fails - -**Solutions:** -```bash -# Try with sudo (macOS/Linux) -sudo npm install -g @fiberplane/mcp-gateway - -# Or use npx (no install) -npx @fiberplane/mcp-gateway - -# Or use Bun instead -bun add -g @fiberplane/mcp-gateway -``` - -### Binary Not Found - -**Symptom:** `mcp-gateway: command not found` - -**Solutions:** -```bash -# Check npm global bin directory -npm config get prefix - -# Add to PATH (add to ~/.bashrc or ~/.zshrc) -export PATH="$PATH:$(npm config get prefix)/bin" - -# Or use npx -npx @fiberplane/mcp-gateway -``` - -## Startup Issues - -### Port Already in Use - -**Symptom:** `EADDRINUSE: address already in use :::3333` - -**Solutions:** -```bash -# Find process using port 3333 -lsof -i :3333 - -# Kill the process -kill -9 - -# Or use a different port -mcp-gateway --port 8080 -``` - -### Storage Directory Permission Denied - -**Symptom:** `EACCES: permission denied, mkdir '/var/lib/mcp-gateway'` - -**Solutions:** -```bash -# Create directory with proper permissions -sudo mkdir -p /var/lib/mcp-gateway -sudo chown $USER:$USER /var/lib/mcp-gateway - -# Or use user-writable directory -mcp-gateway --storage-dir ~/mcp-gateway -``` - -### Registry File Corrupted - -**Symptom:** `SyntaxError: Unexpected token in JSON` - -**Solutions:** -```bash -# Restore from backup -cp ~/.mcp-gateway/mcp.json.backup ~/.mcp-gateway/mcp.json - -# Or recreate empty registry -echo '{"version":"1.0","servers":[]}' > ~/.mcp-gateway/mcp.json - -# Restart gateway -mcp-gateway -``` - -## Connection Issues - -### Cannot Connect to MCP Server - -**Symptom:** "Failed to connect to server" in TUI/Web UI - -**Solutions:** - -1. **Verify server is running:** - ```bash - curl http://localhost:3000/mcp - ``` - -2. **Check server URL is correct:** - - Ensure protocol (http/https) - - Verify port number - - Check path (/mcp) - -3. **Test from gateway's perspective:** - ```bash - # From same machine as gateway - curl http://localhost:3000/mcp - ``` - -4. **Check for CORS issues:** - - MCP servers must allow gateway's origin - - Check server CORS configuration - -5. **Review server logs:** - - Look for connection errors - - Check for auth requirements - -### Server Shows Disconnected - -**Symptom:** Server status shows "Disconnected" in UI - -**Solutions:** - -1. **Check network connectivity:** - ```bash - ping - ``` - -2. **Verify server is still running:** - ```bash - curl - ``` - -3. **Check gateway logs:** - Press `v` in TUI or view Web UI logs for connection errors - -4. **Restart gateway:** - Sometimes a restart resolves transient issues - -### Timeout Errors - -**Symptom:** "Request timeout" errors - -**Solutions:** - -1. **Check server response time:** - ```bash - time curl http://localhost:3000/mcp - ``` - -2. **Increase timeout** (if configurable in future versions) - -3. **Check server performance:** - - High load? - - Resource constraints? - -## UI Issues - -### TUI Display Issues - -**Symptom:** Garbled text, overlapping elements, incorrect colors - -**Solutions:** - -1. **Check terminal compatibility:** - - Use iTerm2, Alacritty, or Windows Terminal - - Ensure ANSI escape code support - -2. **Resize terminal window:** - - Minimum 80x24 characters - - Recommended 120x30+ - -3. **Check UTF-8 encoding:** - ```bash - echo $LANG - # Should show UTF-8, e.g., en_US.UTF-8 - ``` - -4. **Try different terminal:** - ```bash - # macOS - open -a iTerm - - # Linux - alacritty - ``` - -5. **Update terminal emulator** to latest version - -### Web UI Shows 404 - -**Symptom:** Visiting `http://localhost:3333/ui` shows "404 Not Found" - -**Solutions:** - -1. **Verify gateway is running:** - ```bash - curl http://localhost:3333/api/health - ``` - -2. **Check correct port:** - ```bash - # If using custom port - curl http://localhost:8080/api/health - ``` - -3. **Rebuild Web UI** (development): - ```bash - cd packages/web - bun run build - cp -r public ../cli/public - ``` - -### Web UI Shows Stale Data - -**Symptom:** Web UI doesn't reflect recent changes - -**Solutions:** - -1. **Hard refresh browser:** - - macOS: `Cmd+Shift+R` - - Windows/Linux: `Ctrl+Shift+R` - -2. **Clear browser cache:** - - Chrome: Settings → Privacy → Clear browsing data - - Firefox: Preferences → Privacy → Clear Data - -3. **Check real-time updates:** - - Ensure WebSocket connection is active - - Check browser console for errors - -4. **Restart gateway:** - ```bash - # Stop and restart - mcp-gateway - ``` - -## Performance Issues - -### Slow Log Loading - -**Symptom:** Activity log takes long to load - -**Solutions:** - -1. **Apply filters to reduce data:** - - Filter by date range - - Filter by server - - Filter by method - -2. **Clean up old logs:** - ```bash - find ~/.mcp-gateway/captures -name "*.jsonl" -mtime +30 -delete - ``` - -3. **Check disk I/O:** - ```bash - iostat -x 1 - ``` - -4. **Move storage to faster disk** (SSD vs HDD) - -### High Memory Usage - -**Symptom:** Gateway consuming excessive RAM - -**Solutions:** - -1. **Check log buffer size:** - - Large buffers consume more memory - - Restart gateway to clear buffers - -2. **Reduce active servers:** - - Remove unused servers - - Distribute servers across multiple gateways - -3. **Monitor memory:** - ```bash - # macOS/Linux - ps aux | grep mcp-gateway - ``` - -### High CPU Usage - -**Symptom:** Gateway using high CPU - -**Solutions:** - -1. **Check request volume:** - - High traffic increases CPU usage - - Review server activity - -2. **Check for request loops:** - - Server calling itself via gateway? - - Review logs for patterns - -3. **Update to latest version:** - - Performance improvements in newer versions - -## Log Issues - -### Logs Not Being Captured - -**Symptom:** No log files in `~/.mcp-gateway/captures/` - -**Solutions:** - -1. **Check storage directory:** - ```bash - ls -la ~/.mcp-gateway/captures - ``` - -2. **Verify write permissions:** - ```bash - touch ~/.mcp-gateway/captures/test.txt - rm ~/.mcp-gateway/captures/test.txt - ``` - -3. **Check disk space:** - ```bash - df -h - ``` - -4. **Review gateway logs** for write errors - -### Corrupted Log Files - -**Symptom:** Cannot parse log files, invalid JSON - -**Solutions:** - -1. **Validate JSON Lines:** - ```bash - cat ~/.mcp-gateway/captures/server/2025-01-20.jsonl | jq '.' - ``` - -2. **Find corrupted lines:** - ```bash - cat file.jsonl | while read line; do - echo "$line" | jq '.' >/dev/null 2>&1 || echo "Bad: $line" - done - ``` - -3. **Remove corrupted entries:** - ```bash - # Backup first! - cp file.jsonl file.jsonl.backup - - # Filter valid JSON - cat file.jsonl | while read line; do - echo "$line" | jq '.' >/dev/null 2>&1 && echo "$line" - done > file.jsonl.clean - ``` - -## Server Management Issues - -### Cannot Add Server - -**Symptom:** Add server fails with validation error - -**Solutions:** - -1. **Check server name uniqueness:** - - Name must be unique across all servers - - Check `~/.mcp-gateway/mcp.json` for conflicts - -2. **Verify URL format:** - ``` - ✅ http://localhost:3000/mcp - ✅ https://api.example.com/mcp - ❌ localhost:3000 - ❌ http://localhost:3000 (missing /mcp path) - ``` - -3. **Check special characters:** - - Server name: alphanumeric, hyphens, underscores only - - No spaces, no special chars - -### Cannot Remove Server - -**Symptom:** Delete server fails or server reappears - -**Solutions:** - -1. **Manually edit registry:** - ```bash - nano ~/.mcp-gateway/mcp.json - # Remove server entry, save - ``` - -2. **Restart gateway:** - ```bash - mcp-gateway - ``` - -3. **Check file permissions:** - ```bash - ls -la ~/.mcp-gateway/mcp.json - chmod 644 ~/.mcp-gateway/mcp.json - ``` - -## Debug Techniques - -### Enable Debug Logging - -```bash -# Set DEBUG environment variable -DEBUG=* mcp-gateway -``` - -### Inspect Storage - -```bash -# View registry -cat ~/.mcp-gateway/mcp.json | jq '.' - -# List captures -ls -la ~/.mcp-gateway/captures/ - -# View recent logs -tail -f ~/.mcp-gateway/captures/my-server/$(date +%Y-%m-%d).jsonl -``` - -### Test MCP Server Connection - -```bash -# Test with curl -curl -X POST http://localhost:3000/mcp \ - -H "Content-Type: application/json" \ - -d '{"method":"tools/list","params":{}}' -``` - -### Check Gateway API - -```bash -# Health check -curl http://localhost:3333/api/health - -# List servers (if API supports) -curl http://localhost:3333/api/servers -``` - -## Getting Help - -If you've tried the above and still have issues: - -1. **Check GitHub Issues:** - https://github.com/fiberplane/mcp-gateway/issues - -2. **Create a Bug Report:** - - Include OS and version - - Gateway version (`mcp-gateway --version`) - - Steps to reproduce - - Error messages - - Relevant logs - -3. **Community Support:** - - Discussions tab on GitHub - - Fiberplane Discord/Slack - -## Next Steps - -- [**Development Debugging**](/mcp-gateway/development/debugging) - Advanced debugging -- [**CLI Options**](/mcp-gateway/features/cli-options) - Configuration options -- [**Storage & Registry**](/mcp-gateway/features/storage) - Understanding data storage diff --git a/src/content/docs/reference/example.md b/src/content/docs/reference/example.md deleted file mode 100644 index 1082841..0000000 --- a/src/content/docs/reference/example.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Example Reference -description: A reference page in my new Starlight docs site. ---- - -Reference pages are ideal for outlining how things work in terse and clear terms. -Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting. - -## Further reading - -- Read [about reference](https://diataxis.fr/reference) in the Diátaxis framework From d33de4fd0b296d075c49e5c585192dfb1bdb1b03 Mon Sep 17 00:00:00 2001 From: nlea Date: Thu, 4 Dec 2025 14:02:04 +0100 Subject: [PATCH 2/5] Restructure mcp-gateway docs: consolidate into reference folder --- astro.config.ts | 22 +- .../mcp-gateway/concepts/authentication.md | 80 ----- .../docs/mcp-gateway/concepts/proxy.md | 135 --------- .../docs/mcp-gateway/configuration/cli.md | 113 ------- .../docs/mcp-gateway/configuration/storage.md | 142 --------- src/content/docs/mcp-gateway/docs.md | 208 ------------- .../docs/mcp-gateway/getting-started.mdx | 43 +-- src/content/docs/mcp-gateway/index.md | 64 +--- .../interfaces/gateway-mcp-server.md | 89 ------ .../docs/mcp-gateway/interfaces/rest-api.md | 278 ------------------ .../docs/mcp-gateway/interfaces/web-ui.md | 91 ------ .../mcp-gateway/reference/authentication.md | 17 ++ src/content/docs/mcp-gateway/reference/cli.md | 26 ++ .../reference/gateway-mcp-server.md | 18 ++ .../docs/mcp-gateway/reference/proxy.md | 25 ++ .../docs/mcp-gateway/reference/rest-api.md | 63 ++++ .../docs/mcp-gateway/reference/storage.md | 51 ++++ .../docs/mcp-gateway/reference/web-ui.md | 16 + 18 files changed, 238 insertions(+), 1243 deletions(-) delete mode 100644 src/content/docs/mcp-gateway/concepts/authentication.md delete mode 100644 src/content/docs/mcp-gateway/concepts/proxy.md delete mode 100644 src/content/docs/mcp-gateway/configuration/cli.md delete mode 100644 src/content/docs/mcp-gateway/configuration/storage.md delete mode 100644 src/content/docs/mcp-gateway/docs.md delete mode 100644 src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md delete mode 100644 src/content/docs/mcp-gateway/interfaces/rest-api.md delete mode 100644 src/content/docs/mcp-gateway/interfaces/web-ui.md create mode 100644 src/content/docs/mcp-gateway/reference/authentication.md create mode 100644 src/content/docs/mcp-gateway/reference/cli.md create mode 100644 src/content/docs/mcp-gateway/reference/gateway-mcp-server.md create mode 100644 src/content/docs/mcp-gateway/reference/proxy.md create mode 100644 src/content/docs/mcp-gateway/reference/rest-api.md create mode 100644 src/content/docs/mcp-gateway/reference/storage.md create mode 100644 src/content/docs/mcp-gateway/reference/web-ui.md diff --git a/astro.config.ts b/astro.config.ts index 52bff77..bbf650b 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -143,29 +143,25 @@ export default defineConfig({ items: [ { label: "Overview", link: "/mcp-gateway" }, { label: "Getting Started", link: "/mcp-gateway/getting-started" }, - { label: "Authentication", link: "/mcp-gateway/authentication" }, { - label: "Interfaces", + label: "Reference", collapsed: false, items: [ + { label: "CLI", link: "/mcp-gateway/reference/cli" }, + { label: "Storage", link: "/mcp-gateway/reference/storage" }, { - label: "Web UI", - link: "/mcp-gateway/interfaces/web-ui", + label: "Authentication", + link: "/mcp-gateway/reference/authentication", }, + { label: "Proxy", link: "/mcp-gateway/reference/proxy" }, + { label: "REST API", link: "/mcp-gateway/reference/rest-api" }, { label: "Gateway MCP Server", - link: "/mcp-gateway/interfaces/gateway-mcp-server", - }, - { - label: "REST API", - link: "/mcp-gateway/interfaces/rest-api", + link: "/mcp-gateway/reference/gateway-mcp-server", }, + { label: "Web UI", link: "/mcp-gateway/reference/web-ui" }, ], }, - { label: "Proxy", link: "/mcp-gateway/proxy" }, - { label: "CLI", link: "/mcp-gateway/cli" }, - { label: "Storage", link: "/mcp-gateway/storage" }, - { label: "Troubleshooting", link: "/mcp-gateway/troubleshooting" }, ], }, ], diff --git a/src/content/docs/mcp-gateway/concepts/authentication.md b/src/content/docs/mcp-gateway/concepts/authentication.md deleted file mode 100644 index e4da178..0000000 --- a/src/content/docs/mcp-gateway/concepts/authentication.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: Authentication -description: How authentication works in MCP Gateway ---- - -MCP Gateway uses Bearer token authentication to protect sensitive endpoints while allowing proxy endpoints to remain open. - -## Token Generation - -When the gateway starts, it generates a random authentication token displayed in the terminal: - -``` -mcp-gateway v0.7.0 - -MCP Gateway server started at http://localhost:3333 -Web UI: http://localhost:3333/ui?token=HxWFRLBUMjeUWgwSZERD2p86EpWhL1zwASWIwcZ-97A - -``` - -**Important:** Copy this token for API access. The token regenerates on each gateway restart unless you set a custom token. - -## Custom Token - -Set a persistent token via environment variable: - -```bash -MCP_GATEWAY_TOKEN=my-secret-token mcp-gateway -``` - -## Protected Endpoints - -These endpoints require Bearer token authentication: - -| Endpoint | Description | -| -------------- | ------------------------------ | -| `/ui/*` | Web UI (token via query param) | -| `/api/*` | REST API | -| `/gateway/mcp` | Gateway MCP Server | -| `/g/mcp` | Gateway MCP Server (shorthand) | - -### Web UI Authentication - -The Web UI accepts the token as a query parameter: - -``` -http://localhost:3333/ui?token=YOUR_TOKEN -``` - -- Token is stored in browser session storage -- Subsequent navigation within `/ui/*` doesn't require the token -- Token expires when browser session ends - -### API Authentication - -Include the token in the `Authorization` header: - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/servers -``` - -### Gateway MCP Server Authentication - -The Gateway MCP Server uses the same Bearer token authentication. MCP clients pass the token in the `Authorization` header when connecting. - -## Unprotected Endpoints - -Proxy endpoints do **not** require authentication: - -| Endpoint | Description | -| ---------------------- | ------------------------------ | -| `/s/{server-name}/mcp` | Proxy to registered MCP server | - -This allows upstream MCP servers to handle their own authentication as needed. - -## Next Steps - -- [**Getting Started**](/mcp-gateway/getting-started) - Quick setup guide -- [**REST API**](/mcp-gateway/interfaces/rest-api) - API endpoint reference -- [**Proxy**](/mcp-gateway/concepts/proxy) - Using the gateway as a proxy diff --git a/src/content/docs/mcp-gateway/concepts/proxy.md b/src/content/docs/mcp-gateway/concepts/proxy.md deleted file mode 100644 index af49c12..0000000 --- a/src/content/docs/mcp-gateway/concepts/proxy.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Proxy -description: Using MCP Gateway as a proxy for MCP servers ---- - -The gateway proxies MCP requests to registered servers, enabling traffic capture and centralized management. This is the core functionality of MCP Gateway. - -## How It Works - -``` -Direct Connection (no capture): -MCP Client → http://localhost:3001/mcp → MCP Server - -Proxied Connection (with capture): -MCP Client → http://localhost:3333/s/weather/mcp → Gateway → MCP Server - ↓ - SQLite Storage -``` - -Routing traffic through the gateway: - -1. Requests are captured and logged to SQLite -2. Requests are proxied to the actual server -3. Responses are captured and returned to your client -4. All traffic is viewable in the Web UI - -## Proxy Endpoint Pattern - -Each registered server gets a proxy endpoint: - -``` -http://localhost:3333/s/{serverName}/mcp -``` - -**Example:** For a server named `weather-api`: - -``` -http://localhost:3333/s/weather-api/mcp -``` - -:::note -Proxy endpoints do **not** require authentication. This allows upstream MCP servers to handle their own auth. -::: - -## Registering Servers - -Before you can proxy to a server, you must register it with the gateway. - -### Via Web UI - -1. Open `http://localhost:3333/ui?token=YOUR_TOKEN` -2. Naviagte to "Server Management" -3. Click "Add Server" -4. Enter name and URL -5. Click "Add" - -### Via REST API - -```bash -curl -X POST http://localhost:3333/api/servers \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{"name": "weather-api", "url": "http://localhost:3001/mcp"}' -``` - -### Via Gateway MCP Server - -MCP clients connected to the Gateway MCP Server can use the `add_server` tool to register new servers programmatically. - -## Connecting MCP Clients - -### Claude Code - -```bash -claude mcp add --transport http "weather-api" \ - "http://localhost:3333/s/weather-api/mcp" -``` - -### Other HTTP-Based MCP Clients - -Point any MCP client that supports HTTP transport to: - -``` -http://localhost:3333/s/{server-name}/mcp -``` - -## Server with Authentication - -If your upstream MCP server requires authentication, include headers when registering: - -```bash -curl -X POST http://localhost:3333/api/servers \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_GATEWAY_TOKEN" \ - -d '{ - "name": "private-api", - "url": "https://api.example.com/mcp", - "headers": { - "Authorization": "Bearer SERVER_API_KEY" - } -``` - -The gateway will include these headers when proxying requests to the server. - -## Viewing Captured Traffic - -All proxied traffic is captured and viewable: - -### Web UI - -Navigate to `http://localhost:3333/ui?token=YOUR_TOKEN` to see: - -- Activity log with all requests/responses -- Filter by server, method, or time -- Request/response details -- Performance metrics - -### REST API - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - "http://localhost:3333/api/logs?serverName=weather-api" -``` - -### Gateway MCP Server - -MCP clients connected to the Gateway MCP Server can use the `search_records` tool to access logs. - -## Next Steps - -- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Visual traffic inspection -- [**REST API**](/mcp-gateway/interfaces/rest-api) - Programmatic log access -- [**Storage**](/mcp-gateway/configuration/storage) - Where captured data is stored - - diff --git a/src/content/docs/mcp-gateway/configuration/cli.md b/src/content/docs/mcp-gateway/configuration/cli.md deleted file mode 100644 index b24d259..0000000 --- a/src/content/docs/mcp-gateway/configuration/cli.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: CLI -description: Command-line options for MCP Gateway ---- - -Configure MCP Gateway behavior using command-line flags and environment variables. - -## Basic Usage - -```bash -mcp-gateway [options] -``` - -## Options - -### `--port ` - -Set the HTTP server port. - -```bash -mcp-gateway --port 8080 -``` - -**Default:** `3333` - -**Result:** - -- API: `http://localhost:8080/api` -- Web UI: `http://localhost:8080/ui` -- Proxy: `http://localhost:8080/s/{server}/mcp` - ---- - -### `--storage-dir ` - -Set custom storage directory for logs and registry. - -```bash -mcp-gateway --storage-dir /custom/path -``` - -**Default:** `~/.mcp-gateway` - -**Result:** - -- Registry: `/custom/path/mcp.json` -- Database: `/custom/path/gateway.db` - ---- - -### `--help` - -Display help information. - -```bash -mcp-gateway --help -``` - ---- - -### `--version` - -Display version information. - -```bash -mcp-gateway --version -``` - -## Environment Variables - -All CLI options have environment variable equivalents: - -| Environment Variable | CLI Flag | Default | -| ------------------------- | --------------- | ---------------- | -| `MCP_GATEWAY_PORT` | `--port` | `3333` | -| `MCP_GATEWAY_STORAGE_DIR` | `--storage-dir` | `~/.mcp-gateway` | -| `MCP_GATEWAY_TOKEN` | N/A | (auto-generated) | - -**Examples:** - -```bash -# Set port via environment -MCP_GATEWAY_PORT=8080 mcp-gateway - -# Set storage directory -MCP_GATEWAY_STORAGE_DIR=~/gateway mcp-gateway - -# Set custom auth token -MCP_GATEWAY_TOKEN=my-secret-token mcp-gateway -``` - -## Configuration Precedence - -Options are applied in this order (highest to lowest priority): - -1. Command-line flags -2. Environment variables -3. Default values - -**Example:** - -```bash -# Port will be 9000 (CLI flag wins) -MCP_GATEWAY_PORT=8080 mcp-gateway --port 9000 -``` - -## Next Steps - -- [**Storage**](/mcp-gateway/configuration/storage) - Understand data storage -- [**Authentication**](/mcp-gateway/concepts/authentication) - Token configuration -- [**Getting Started**](/mcp-gateway/getting-started) - Quick setup guide - - diff --git a/src/content/docs/mcp-gateway/configuration/storage.md b/src/content/docs/mcp-gateway/configuration/storage.md deleted file mode 100644 index e000c56..0000000 --- a/src/content/docs/mcp-gateway/configuration/storage.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -title: Storage -description: Data persistence and file organization ---- - -MCP Gateway stores server configuration and captured traffic locally using SQLite and JSON files. - -## Storage Location - -Files are stored under `~/.mcp-gateway/`: - -``` -~/.mcp-gateway/ -├── mcp.json # Server registry -├── logs.db # SQLite traffic logs -└── logs.db-* # SQLite files -``` - -### Default Directory - -``` -~/.mcp-gateway/ -``` - -### Custom Directory - -```bash -mcp-gateway --storage-dir /custom/path -``` - -Or via environment variable: - -```bash -MCP_GATEWAY_STORAGE_DIR=/custom/path mcp-gateway -``` - -## Directory Structure - -``` -~/.mcp-gateway/ -├── mcp.json # Server registry -└── gateway.db # SQLite database (captured traffic) -``` - -## Server Registry - -### File: `mcp.json` - -The registry stores server configurations in JSON format. - -### Format - -```json -{ - "servers": [ - { - "name": "github-server", - "url": "http://localhost:3000/mcp", - "headers": {} - }, - { - "name": "weather-api", - "url": "http://localhost:4000/mcp", - "headers": { - "Authorization": "Bearer token123" - } - } - ] -} -``` - -### Manual Editing - -You can manually edit `mcp.json`: - -```bash -# Edit registry -nano ~/.mcp-gateway/mcp.json - -# Restart gateway to apply changes -mcp-gateway -``` - -**Caution**: Invalid JSON will prevent the gateway from starting. - -### Backup - -```bash -# Backup registry -cp ~/.mcp-gateway/mcp.json ~/.mcp-gateway/mcp.json.backup - -# Restore from backup -cp ~/.mcp-gateway/mcp.json.backup ~/.mcp-gateway/mcp.json -``` - -## Captured Traffic (SQLite) - -### Database: `gateway.db` - -All captured MCP traffic is stored in a SQLite database for efficient querying and filtering. - -### Querying Directly - -You can query the database directly if needed: - -```bash -sqlite3 ~/.mcp-gateway/gateway.db - -# List tables -.tables - -# Query recent logs -SELECT * FROM logs ORDER BY timestamp DESC LIMIT 10; -``` - -### Data Retention - -By default, logs are kept indefinitely. Clean up via: - -**Web UI:** Use the "Clear Sessions" functionality - -**REST API:** - -```bash -curl -X POST \ - -H "Authorization: Bearer YOUR_TOKEN" \ - "http://localhost:3333/api/logs/clear?before=2025-01-01T00:00:00Z" -``` - -**Manual:** - -```bash -# Delete and recreate database -rm ~/.mcp-gateway/gateway.db -mcp-gateway -``` - -## Next Steps - -- [**CLI**](/mcp-gateway/configuration/cli) - Configure storage location -- [**Proxy**](/mcp-gateway/concepts/proxy) - How traffic is captured -- [**Web UI**](/mcp-gateway/interfaces/web-ui) - View captured traffic diff --git a/src/content/docs/mcp-gateway/docs.md b/src/content/docs/mcp-gateway/docs.md deleted file mode 100644 index 14424f4..0000000 --- a/src/content/docs/mcp-gateway/docs.md +++ /dev/null @@ -1,208 +0,0 @@ -## MCP Gateway — Technical Guide (Concise) - -Accurate, minimal docs for installing and operating MCP Gateway via a package manager. - ---- - -## Install - -Global: - -```bash -npm i -g @fiberplane/mcp-gateway -# or: yarn global add … | pnpm add -g … | bun add -g … -``` - -Ephemeral: - -```bash -npx mcp-gateway -# or: pnpm dlx @fiberplane/mcp-gateway | bunx @fiberplane/mcp-gateway -``` - ---- - -## Start - -```bash -mcp-gateway -``` - -Output includes port (default 3333) and Web UI URL with token: - -``` -Web UI: http://localhost:3333/ui?token= -``` - ---- - -## Endpoints - -- Web UI (token in query): `/ui?token=` -- REST API (Bearer token): `/api/*` -- Gateway MCP Server (Bearer token): `/gateway/mcp` -- Proxy (no auth; upstream handles auth): `/s/{serverName}/mcp` - -Auth token: - -```bash -export MCP_GATEWAY_TOKEN="my-secret-token" -mcp-gateway -``` - ---- - -## Getting Started - -- Add first server (Web UI): “Add Server” → name + URL → health check runs -- Proxy pattern: - ``` - http://localhost:3333/s/{serverName}/mcp - ``` - ---- - -## CLI - -```bash -mcp-gateway --port 8080 -mcp-gateway --storage-dir /custom/path -DEBUG=* mcp-gateway -mcp-gateway --help | --version -``` - -Env: - -- `MCP_GATEWAY_PORT` (default 3333) -- `MCP_GATEWAY_STORAGE` (default `~/.mcp-gateway`) -- `MCP_GATEWAY_TOKEN` (optional) -- `DEBUG` (`*`, `@fiberplane/*`) - ---- - -## Configuration - -Files under `~/.mcp-gateway/`: - -``` -~/.mcp-gateway/ -├── mcp.json # server registry -├── logs.db # SQLite logs -└── logs.db-* # SQLite files -``` - -HTTP server (mcp.json): - -```json -{ - "servers": [ - { - "name": "my-server", - "type": "http", - "url": "http://localhost:3000/mcp", - "enabled": true - } - ] -} -``` - -Stdio server (mcp.json): - -```json -{ - "servers": [ - { - "name": "memory", - "type": "stdio", - "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-memory"], - "sessionMode": "shared", - "timeout": 30000 - } - ] -} -``` - -Notes: - -- `sessionMode`: `"shared"` (default) or `"isolated"` (per `x-session-id`) -- Stdio servers are long-lived; restart via UI/API - ---- - -## REST API - -Base: - -``` -http://localhost:3333/api -``` - -Auth: - -```bash -curl -H "Authorization: Bearer " http://localhost:3333/api/servers -``` - -Common: - -- `GET /api/logs` -- `GET /api/servers` -- `POST /api/servers` -- `GET /api/health` - -Filtering and pagination: - -- Query params: `server`, `sessionId`, `method`, `limit` (max 1000), `order` (`asc|desc`) - -```bash -curl -H "Authorization: Bearer " \ - "http://localhost:3333/api/logs?server=my-server&sessionId=abc123&method=tools/list&limit=50&order=desc" -``` - ---- - -## Gateway MCP Server - -Endpoint: - -``` -http://localhost:3333/gateway/mcp -``` - -Tools: - -- `add_server`, `remove_server`, `list_servers`, `search_records` - Auth: Bearer token required. - ---- - -## Web UI - -- Activity Log (filter/search), Server management, Health, Export JSON -- Open: `http://localhost:3333/ui?token=` - ---- - -## Troubleshooting - -- Port in use: - ```bash - mcp-gateway --port 8080 - ``` -- Auth errors: - - Use full UI URL with `?token=…` or set `MCP_GATEWAY_TOKEN` -- Connectivity: - - Verify upstream URL, check UI health, inspect Activity Log -- Reset data: - ```bash - rm -rf ~/.mcp-gateway/ && mcp-gateway - ``` - ---- - -## FAQ - -- Logs location: `~/.mcp-gateway/logs.db` -- Proxy auth: upstream server handles its own auth -- Claude Desktop: no HTTP MCP support (can’t use proxy endpoints) diff --git a/src/content/docs/mcp-gateway/getting-started.mdx b/src/content/docs/mcp-gateway/getting-started.mdx index acd5927..d73783f 100644 --- a/src/content/docs/mcp-gateway/getting-started.mdx +++ b/src/content/docs/mcp-gateway/getting-started.mdx @@ -69,47 +69,6 @@ More details [here](https://github.com/fiberplane/mcp-gateway?tab=readme-ov-file -## Basic Configuration - -### Custom Port - -```bash -mcp-gateway --port 8080 -``` - -### Custom Storage Directory - -```bash -mcp-gateway --storage-dir /custom/path -``` - -## Common Commands - -```bash -# Show help -mcp-gateway --help - -# Show version -mcp-gateway --version - -# Start with custom settings -mcp-gateway --port 8080 --storage-dir ~/.my-gateway -``` - -## Verifying Installation - -The gateway runs locally and exposes a Web UI and API endpoints that require bearer token authentication. - -Web UI: Access the interface at http://localhost:3333/ui using the authentication token displayed in the terminal output. - -API endpoints: Requests to the gateway API require a bearer token for authentication. Example usage: - -``` -curl -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxx" http://localhost:3333/api/logs -``` - ## Next Steps -- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Learn more about the Web UI features -- [**CLI**](/mcp-gateway/configuration/cli) - Explore all command-line options -- [**Proxy**](/mcp-gateway/concepts/proxy) - Learn how the proxy works +- [**Reference**](/mcp-gateway/reference/cli) - CLI, storage, API, and all technical details diff --git a/src/content/docs/mcp-gateway/index.md b/src/content/docs/mcp-gateway/index.md index c57de4e..ba70f61 100644 --- a/src/content/docs/mcp-gateway/index.md +++ b/src/content/docs/mcp-gateway/index.md @@ -9,46 +9,10 @@ MCP Gateway is a unified HTTP proxy for managing, routing, and debugging multipl MCP Gateway is a local development tool that proxies communication between AI applications and multiple MCP servers. MCP Gateway runs from a terminal command and exposes a Web UI for managing and interacting with MCP servers. The gateway provides capabilities for: -- Managing multiple MCP servers from a single interface -- Inspecting and debugging request/response traffic -- Monitoring server activity in real-time -- Storing and replaying captured logs - -## Key Features - -### Multi-Server Management - -The gateway allows multiple MCP servers to be added, configured, and monitored from a single interface. Switching between servers and managing their lifecycle is supported seamlessly. - -### Activity Logging - -The gateway captures all requests and responses passing through it. Logs can be filtered by server or time, providing detailed information to facilitate debugging - -### Interface - -The Gateway comes with a Web-UI with browser-based dashboard for visual server management - -### Local Development - -The gateway runs locally during development, supporting testing and debugging of MCP integrations before deployment to production. - -## Use Cases - -### Local MCP Development - -MCP Gateway supports local development and testing of MCP servers with complete visibility into request and response traffic. It operates as an intermediary, logging all communication for inspection. - -### Multi-Server Coordination - -The gateway facilitates routing requests to multiple MCP servers and managing complex setups with specialized servers efficiently. - -### Request Debugging - -Captured requests and responses can be inspected in detail, aiding in the identification and resolution of issues. - -### Activity Monitoring - -The gateway provides real-time monitoring of server health, response times, and error rates, offering full visibility into the MCP infrastructure. +- **Multi-server management** from a single interface +- **Activity logging** of all requests and responses +- **Real-time monitoring** via a Web UI +- **Traffic capture** stored in SQLite for inspection ## Architecture @@ -95,20 +59,16 @@ The gateway operates in dual mode: it's both a proxy for MCP servers AND an MCP └──────────┘ └─────────┘ └──────────┘ ``` -## Quick Example - -```bash -# Install MCP Gateway -npm install -g @fiberplane/mcp-gateway - -# Start the gateway -mcp-gateway - -# To access the web interface, copy the Web UI URL with the authetication token from your terminal output: -``` +## Endpoints -![Terminal Output after starting the gateway](/src/assets/terminal-output.png) +| Endpoint | Auth | Description | +| --------------------- | ------------- | ----------------------------- | +| `/ui?token=` | Token (query) | Web UI dashboard | +| `/api/*` | Bearer token | REST API | +| `/gateway/mcp` | Bearer token | Gateway MCP Server | +| `/s/{serverName}/mcp` | None | Proxy (upstream handles auth) | ## Next Steps - [**Getting Started**](/mcp-gateway/getting-started) - Install and configure MCP Gateway +- [**Reference**](/mcp-gateway/reference/cli) - CLI, storage, and API reference diff --git a/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md b/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md deleted file mode 100644 index 5712705..0000000 --- a/src/content/docs/mcp-gateway/interfaces/gateway-mcp-server.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Gateway MCP Server -description: Manage the gateway using MCP tools ---- - -The gateway exposes its own MCP server with tools for programmatic control. Any MCP client (like Claude Desktop, Cursor, or custom clients) can connect and manage the gateway. - -## Endpoint - -``` -http://localhost:3333/gateway/mcp -``` - -Or the shorthand: - -``` -http://localhost:3333/g/mcp -``` - -:::note -This endpoint requires Bearer token authentication. Include the token in the `Authorization` header. -::: - -## Available Tools - -The gateway exposes these MCP tools for server management: - -### `add_server` - -Add a new MCP server to the gateway registry. - -**Parameters:** - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | ------------------------------------------------------------- | -| `name` | string | Yes | Unique server identifier (alphanumeric, hyphens, underscores) | -| `url` | string | Yes | Full HTTP/HTTPS URL to the MCP server | -| `headers` | object | No | Custom HTTP headers for authentication | - ---- - -### `remove_server` - -Remove a server from the gateway registry. - -**Parameters:** - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | ---------------------------- | -| `name` | string | Yes | Name of the server to remove | - ---- - -### `list_servers` - -List all registered servers with optional filtering. - -**Parameters:** - -| Parameter | Type | Required | Description | -| --------- | ---- | -------- | ------------------------------------------------------- | -| `filter` | enum | No | `"all"`, `"active"`, or `"inactive"` (default: `"all"`) | -| `format` | enum | No | `"concise"` or `"detailed"` (default: `"concise"`) | - ---- - -### `search_records` - -Search and analyze captured MCP traffic. - -**Parameters:** - -| Parameter | Type | Required | Description | -| ------------ | ------ | -------- | ----------------------------------------------- | -| `serverName` | string | No | Filter by server name | -| `sessionId` | string | No | Filter by session ID | -| `method` | string | No | Filter by JSON-RPC method (partial match) | -| `limit` | number | No | Max records to return (default: 100, max: 1000) | -| `order` | enum | No | `"asc"` or `"desc"` (default: `"desc"`) | - -## Using with MCP Clients - -Any MCP client that supports HTTP transport can connect to the gateway's MCP server. - -## Next Steps - -- [**REST API**](/mcp-gateway/interfaces/rest-api) - HTTP API reference -- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Visual management -- [**Proxy**](/mcp-gateway/concepts/proxy) - Route traffic through the gateway diff --git a/src/content/docs/mcp-gateway/interfaces/rest-api.md b/src/content/docs/mcp-gateway/interfaces/rest-api.md deleted file mode 100644 index 045cdd3..0000000 --- a/src/content/docs/mcp-gateway/interfaces/rest-api.md +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: REST API -description: HTTP API reference for MCP Gateway ---- - -The MCP Gateway provides an HTTP API for programmatic access to server management, activity logs, and session information. This API is primarily used by the Web UI but is available for programmatic access. - -## Base URL - -``` -http://localhost:3333/api -``` - -Or your configured port: - -```bash -# If using custom port -http://localhost:8080/api -``` - -## Authentication - -All API endpoints require Bearer token authentication: - -```http -Authorization: Bearer YOUR_API_TOKEN -``` - -### Getting Your API Token - -The API token is **displayed in the console** when the gateway starts: - -![Token](/src/assets/terminal-output.png) - -## Endpoints - -### GET /api/logs - -Retrieve activity logs from all servers. - -**Query Parameters:** - -| Parameter | Type | Description | -| ------------ | ------ | ----------------------------------------- | -| `serverName` | string | Filter by server name | -| `method` | string | Filter by MCP method (e.g., `tools/list`) | -| `sessionId` | string | Filter by session ID | -| `limit` | number | Maximum number of entries (default: 100) | -| `before` | string | Cursor for pagination (oldest timestamp) | -| `after` | string | Cursor for pagination (newest timestamp) | - -**Example Request:** - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - "http://localhost:3333/api/logs?serverName=linear-mcp&limit=2" -``` - -**Example Response:** - -```json -{ - "data": [ - { - "timestamp": "2025-12-02T13:30:47.543Z", - "method": "tools/call", - "id": "2", - "direction": "request", - "metadata": { - "serverName": "linear-mcp", - "sessionId": "d87bc227...", - "durationMs": 89, - "httpStatus": 200, - "userAgent": "claude-code/2.0.55", - "clientIp": "::1", - "inputTokens": 13, - "methodDetail": "list_issues(assignee: \"me\")" - }, - "request": { ... }, - "response": { ... } - } - ], - "pagination": { - "count": 2, - "limit": 2, - "hasMore": true, - "oldestTimestamp": "2025-12-02T13:11:22.216Z", - "newestTimestamp": "2025-12-02T13:30:47.543Z" - } -} -``` - ---- - -### GET /api/servers - -List all registered MCP servers. - -**Example Request:** - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/servers -``` - -**Example Response:** - -```json -{ - "servers": [ - { - "name": "linear-mcp", - "status": "online", - "url": "https://mcp.linear.app/mcp", - "health": "up", - "lastCheckTime": 1764686521450, - "lastHealthyTime": 1764686521450, - "responseTimeMs": 80 - } - ] -} -``` - -**Response Fields:** - -| Field | Type | Description | -| ----------------- | ------ | -------------------------------------------- | -| `name` | string | Server identifier | -| `url` | string | Server endpoint URL | -| `status` | string | Server status: `online` or `offline` | -| `health` | string | Health status: `up`, `down`, or `unknown` | -| `lastCheckTime` | number | Unix timestamp of last health check (ms) | -| `lastHealthyTime` | number | Unix timestamp of last successful check (ms) | -| `responseTimeMs` | number | Last response time in milliseconds | - ---- - -### POST /api/servers - -Add a new MCP server. - -**Request Body:** - -```json -{ - "name": "weather-api", - "url": "http://localhost:3001/mcp", - "headers": { - "Authorization": "Bearer token123" - } -} -``` - -**Example Request:** - -```bash -curl -X POST http://localhost:3333/api/servers \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -d '{"name": "test-server", "url": "http://localhost:3001/mcp"}' -``` - ---- - -### GET /api/sessions - -Retrieve active and recent MCP sessions. - -**Example Request:** - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/sessions -``` - -**Example Response:** - -```json -{ - "sessions": [ - { - "sessionId": "d87bc227931ab7d8...", - "serverName": "linear-mcp", - "startTime": "2025-12-02T13:11:22.034Z", - "endTime": "2025-12-02T13:30:47.543Z" - } - ] -} -``` - -**Special Values:** - -- `sessionId: "stateless"` - Indicates a stateless session (no session ID provided by client) - ---- - -### GET /api/clients - -List connected clients. - -**Example Request:** - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/clients -``` - -**Example Response:** - -```json -{ - "clients": [ - { - "clientName": "claude-code", - "clientVersion": "2.0.55" - } - ] -} -``` - ---- - -### POST /api/logs/clear - -Clear activity logs. - -**Query Parameters:** - -| Parameter | Type | Description | -| ------------ | ------ | ------------------------------------------------ | -| `serverName` | string | Clear only logs for specific server (optional) | -| `before` | string | Clear only logs before this timestamp (optional) | - -**Example Request:** - -```bash -# Clear all logs -curl -X POST \ - -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/logs/clear - -# Clear logs for specific server -curl -X POST \ - -H "Authorization: Bearer YOUR_TOKEN" \ - "http://localhost:3333/api/logs/clear?serverName=linear-mcp" -``` - ---- - -### GET /api/health - -Health check endpoint. - -**Example Request:** - -```bash -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3333/api/health -``` - ---- - -## Error Responses - -All endpoints return standard HTTP error codes: - -| Status | Description | -| ------ | --------------------------------------- | -| `401` | Missing or invalid authentication token | -| `400` | Invalid query parameters | -| `404` | Resource not found | -| `500` | Internal server error | - -## Next Steps - -- [**Gateway MCP Server**](/mcp-gateway/interfaces/gateway-mcp-server) - MCP-based programmatic control -- [**Web UI**](/mcp-gateway/interfaces/web-ui) - Visual server management -- [**Proxy**](/mcp-gateway/concepts/proxy) - Using the gateway as a proxy diff --git a/src/content/docs/mcp-gateway/interfaces/web-ui.md b/src/content/docs/mcp-gateway/interfaces/web-ui.md deleted file mode 100644 index e530693..0000000 --- a/src/content/docs/mcp-gateway/interfaces/web-ui.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Web UI -description: Browser-based dashboard for managing MCP Gateway ---- - -The Web UI provides a visual, browser-based interface for managing servers and inspecting activity logs. - -## Accessing the Web UI - -### Default URL - -``` -http://localhost:3333/ui?token=YOUR_TOKEN -``` - -The token is displayed in the terminal when the gateway starts. Copy the full URL from the terminal output. - -### Custom Port - -If running with `--port`: - -```bash -mcp-gateway --port 8080 -# Access at: http://localhost:8080/ui?token=YOUR_TOKEN -``` - -## Features - -The Web UI provides: - -- **Activity Log** - View all captured MCP traffic with filtering -- **Server Management** - Add, edit, remove, and monitor servers -- **Health Status** - Real-time health checks for all servers -- **Export Logs** - Export captured traffic as JSON -- **Search & Filter** - Find specific requests by server, method, or content - -## Dashboard - -The main dashboard shows your registered MCP servers and their activity. - -### Manage Servers - -- **Add Server** - Register a new MCP server with the gateway -- **View Server Details** - Click on any server to see health information, gateway URL, and configuration -- **Edit Server** - Modify the origin URL of a registered server -- **Remove Server** - Delete a server from the registry - -### Logs - -View all logs across servers, or select a specific server to filter the activity log. Additional filters available: - -- **Token** -- **Client** -- **Duration** -- **Method** -- **Session** - -#### Viewing Log Details - -Click on any log entry to see the full request and response details including: - -- Timestamp -- Server name -- Method called -- Duration -- Request parameters -- Response data - -#### Exporting Logs - -The dashboard allows exporting selected logs as JSONL. - -### Popular MCP Servers - -We've collected some of the most popular MCP servers. These remote servers are available directly through the marketplace. - -## Real-Time Updates - -The Web UI updates in real-time: - -- New log entries appear automatically -- Server status changes reflect immediately -- Activity counts update live - -No manual refresh needed! - -## Next Steps - -- [**REST API**](/mcp-gateway/interfaces/rest-api) - Programmatic access -- [**Gateway MCP Server**](/mcp-gateway/interfaces/gateway-mcp-server) - MCP-based control -- [**CLI**](/mcp-gateway/configuration/cli) - Command-line options diff --git a/src/content/docs/mcp-gateway/reference/authentication.md b/src/content/docs/mcp-gateway/reference/authentication.md new file mode 100644 index 0000000..849d15a --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/authentication.md @@ -0,0 +1,17 @@ +--- +title: Authentication +description: Token-based security +--- + +Bearer token required for `/ui/*`, `/api/*`, and `/gateway/mcp`. Proxy endpoints (`/s/{name}/mcp`) are unauthenticated—upstream handles its own auth. + +Token is auto-generated on startup (shown in terminal) or set via `MCP_GATEWAY_TOKEN`. + +```bash +# API authentication +curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3333/api/servers + +# Web UI (token in query string) +http://localhost:3333/ui?token=YOUR_TOKEN +``` + diff --git a/src/content/docs/mcp-gateway/reference/cli.md b/src/content/docs/mcp-gateway/reference/cli.md new file mode 100644 index 0000000..6a1e177 --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/cli.md @@ -0,0 +1,26 @@ +--- +title: CLI +description: Command-line options and environment variables +--- + +```bash +mcp-gateway [options] +``` + +| Flag | Environment Variable | Default | Description | +| --------------- | ------------------------- | ---------------- | ----------------- | +| `--port` | `MCP_GATEWAY_PORT` | `3333` | HTTP server port | +| `--storage-dir` | `MCP_GATEWAY_STORAGE_DIR` | `~/.mcp-gateway` | Storage directory | +| N/A | `MCP_GATEWAY_TOKEN` | (auto-generated) | Auth token | +| `--help` | | | Show help | +| `--version` | | | Show version | + +```bash +# Examples +mcp-gateway --port 8080 +MCP_GATEWAY_TOKEN=my-secret-token mcp-gateway +DEBUG=* mcp-gateway # Enable debug logging +``` + +CLI flags override environment variables. + diff --git a/src/content/docs/mcp-gateway/reference/gateway-mcp-server.md b/src/content/docs/mcp-gateway/reference/gateway-mcp-server.md new file mode 100644 index 0000000..3645cbb --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/gateway-mcp-server.md @@ -0,0 +1,18 @@ +--- +title: Gateway MCP Server +description: MCP tools for gateway control +--- + +Endpoint: `http://localhost:3333/gateway/mcp` (or `/g/mcp`) + +Requires Bearer token. Any MCP client can connect to manage the gateway programmatically. + +## Available Tools + +| Tool | Description | +| ---------------- | -------------------------------------------------------- | +| `add_server` | Add server (name, url, headers) | +| `remove_server` | Remove server by name | +| `list_servers` | List servers (filter: all/active/inactive) | +| `search_records` | Query logs (serverName, sessionId, method, limit, order) | + diff --git a/src/content/docs/mcp-gateway/reference/proxy.md b/src/content/docs/mcp-gateway/reference/proxy.md new file mode 100644 index 0000000..cbb39bf --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/proxy.md @@ -0,0 +1,25 @@ +--- +title: Proxy +description: Routing MCP traffic through the gateway +--- + +Route MCP clients through the gateway to capture traffic: + +``` +Direct: MCP Client → http://localhost:3001/mcp → MCP Server +Proxied: MCP Client → http://localhost:3333/s/my-server/mcp → Gateway → MCP Server + ↓ + SQLite Storage +``` + +Proxy URL pattern: `http://localhost:3333/s/{serverName}/mcp` + +Example (Claude Code): + +```bash +claude mcp add --transport http "my-server" \ + "http://localhost:3333/s/my-server/mcp" +``` + +Proxy endpoints do **not** require authentication—upstream servers handle their own auth. + diff --git a/src/content/docs/mcp-gateway/reference/rest-api.md b/src/content/docs/mcp-gateway/reference/rest-api.md new file mode 100644 index 0000000..55f6441 --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/rest-api.md @@ -0,0 +1,63 @@ +--- +title: REST API +description: HTTP API endpoints +--- + +Base: `http://localhost:3333/api` + +All endpoints require Bearer token authentication. + +## GET /api/servers + +List registered servers with health status. + +```bash +curl -H "Authorization: Bearer TOKEN" http://localhost:3333/api/servers +``` + +## POST /api/servers + +Add a server. + +```bash +curl -X POST http://localhost:3333/api/servers \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer TOKEN" \ + -d '{"name": "my-server", "url": "http://localhost:3001/mcp"}' +``` + +With auth headers for upstream: + +```json +{ + "name": "private-api", + "url": "https://api.example.com/mcp", + "headers": { "Authorization": "Bearer SERVER_KEY" } +} +``` + +## GET /api/logs + +Query parameters: `serverName`, `sessionId`, `method`, `limit` (default 100), `before`, `after` + +```bash +curl -H "Authorization: Bearer TOKEN" \ + "http://localhost:3333/api/logs?serverName=my-server&limit=50" +``` + +## POST /api/logs/clear + +Clear logs. Optional: `?serverName=...` or `?before=2025-01-01T00:00:00Z` + +## GET /api/sessions + +List active sessions. + +## GET /api/clients + +List connected clients. + +## GET /api/health + +Health check. + diff --git a/src/content/docs/mcp-gateway/reference/storage.md b/src/content/docs/mcp-gateway/reference/storage.md new file mode 100644 index 0000000..2fca792 --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/storage.md @@ -0,0 +1,51 @@ +--- +title: Storage +description: Data persistence and server registry format +--- + +Files stored under `~/.mcp-gateway/`: + +``` +~/.mcp-gateway/ +├── mcp.json # Server registry +├── logs.db # SQLite traffic logs +└── logs.db-* # SQLite files +``` + +## Server Registry (mcp.json) + +HTTP server: + +```json +{ + "servers": [ + { + "name": "my-server", + "type": "http", + "url": "http://localhost:3000/mcp", + "enabled": true + } + ] +} +``` + +Stdio server: + +```json +{ + "servers": [ + { + "name": "memory", + "type": "stdio", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-memory"], + "sessionMode": "shared", + "timeout": 30000 + } + ] +} +``` + +- `sessionMode`: `"shared"` (default) or `"isolated"` (per `x-session-id`) +- Stdio servers are long-lived; restart via UI/API + diff --git a/src/content/docs/mcp-gateway/reference/web-ui.md b/src/content/docs/mcp-gateway/reference/web-ui.md new file mode 100644 index 0000000..fad5ff1 --- /dev/null +++ b/src/content/docs/mcp-gateway/reference/web-ui.md @@ -0,0 +1,16 @@ +--- +title: Web UI +description: Browser-based dashboard +--- + +Access: `http://localhost:3333/ui?token=YOUR_TOKEN` + +## Features + +- **Activity Log** — view/filter captured MCP traffic +- **Server Management** — add, edit, remove servers +- **Health Status** — real-time health checks +- **Export** — download logs as JSONL + +Updates in real-time; no manual refresh needed. + From a7ce2a65e7184df46045de9bc61a873d5f069145 Mon Sep 17 00:00:00 2001 From: nlea Date: Thu, 4 Dec 2025 14:11:53 +0100 Subject: [PATCH 3/5] docs(mcp-gateway): reorganize reference documentation - Consolidate all reference content into single reference.md page - Move individual reference files from reference/ to references/ --- astro.config.ts | 14 +- src/content/docs/mcp-gateway/reference.md | 199 ++++++++++++++++++ .../authentication.md | 1 - .../{reference => references}/cli.md | 1 - .../gateway-mcp-server.md | 1 - .../{reference => references}/proxy.md | 1 - .../{reference => references}/rest-api.md | 1 - .../{reference => references}/storage.md | 1 - .../{reference => references}/web-ui.md | 1 - 9 files changed, 206 insertions(+), 14 deletions(-) create mode 100644 src/content/docs/mcp-gateway/reference.md rename src/content/docs/mcp-gateway/{reference => references}/authentication.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/cli.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/gateway-mcp-server.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/proxy.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/rest-api.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/storage.md (99%) rename src/content/docs/mcp-gateway/{reference => references}/web-ui.md (99%) diff --git a/astro.config.ts b/astro.config.ts index bbf650b..c0ce139 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -147,19 +147,19 @@ export default defineConfig({ label: "Reference", collapsed: false, items: [ - { label: "CLI", link: "/mcp-gateway/reference/cli" }, - { label: "Storage", link: "/mcp-gateway/reference/storage" }, + { label: "CLI", link: "/mcp-gateway/reference#cli" }, + { label: "Storage", link: "/mcp-gateway/reference#storage" }, { label: "Authentication", - link: "/mcp-gateway/reference/authentication", + link: "/mcp-gateway/reference#authentication", }, - { label: "Proxy", link: "/mcp-gateway/reference/proxy" }, - { label: "REST API", link: "/mcp-gateway/reference/rest-api" }, + { label: "Proxy", link: "/mcp-gateway/reference#proxy" }, + { label: "REST API", link: "/mcp-gateway/reference#rest-api" }, { label: "Gateway MCP Server", - link: "/mcp-gateway/reference/gateway-mcp-server", + link: "/mcp-gateway/reference#gateway-mcp-server", }, - { label: "Web UI", link: "/mcp-gateway/reference/web-ui" }, + { label: "Web UI", link: "/mcp-gateway/reference#web-ui" }, ], }, ], diff --git a/src/content/docs/mcp-gateway/reference.md b/src/content/docs/mcp-gateway/reference.md new file mode 100644 index 0000000..1c57194 --- /dev/null +++ b/src/content/docs/mcp-gateway/reference.md @@ -0,0 +1,199 @@ +--- +title: Reference +description: technical references +--- + +## CLI + +```bash +mcp-gateway [options] +``` + +| Flag | Environment Variable | Default | Description | +| --------------- | ------------------------- | ---------------- | ----------------- | +| `--port` | `MCP_GATEWAY_PORT` | `3333` | HTTP server port | +| `--storage-dir` | `MCP_GATEWAY_STORAGE_DIR` | `~/.mcp-gateway` | Storage directory | +| N/A | `MCP_GATEWAY_TOKEN` | (auto-generated) | Auth token | +| `--help` | | | Show help | +| `--version` | | | Show version | + +```bash +# Examples +mcp-gateway --port 8080 +MCP_GATEWAY_TOKEN=my-secret-token mcp-gateway +DEBUG=* mcp-gateway # Enable debug logging +``` + +CLI flags override environment variables. + +## Authentication + +Bearer token required for `/ui/*`, `/api/*`, and `/gateway/mcp`. Proxy endpoints (`/s/{name}/mcp`) are unauthenticated—upstream handles its own auth. + +Token is auto-generated on startup (shown in terminal) or set via `MCP_GATEWAY_TOKEN`. + +```bash +# API authentication +curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3333/api/servers + +# Web UI (token in query string) +http://localhost:3333/ui?token=YOUR_TOKEN +``` + +## Proxy + +Route MCP clients through the gateway to capture traffic: + +``` +Direct: MCP Client → http://localhost:3001/mcp → MCP Server +Proxied: MCP Client → http://localhost:3333/s/my-server/mcp → Gateway → MCP Server + ↓ + SQLite Storage +``` + +Proxy URL pattern: `http://localhost:3333/s/{serverName}/mcp` + +Example (Claude Code): + +```bash +claude mcp add --transport http "my-server" \ + "http://localhost:3333/s/my-server/mcp" +``` + +Proxy endpoints do **not** require authentication—upstream servers handle their own auth. + +## Storage + +Files stored under `~/.mcp-gateway/`: + +``` +~/.mcp-gateway/ +├── mcp.json # Server registry +├── logs.db # SQLite traffic logs +└── logs.db-* # SQLite files +``` + +### Server Registry (mcp.json) + +HTTP server: + +```json +{ + "servers": [ + { + "name": "my-server", + "type": "http", + "url": "http://localhost:3000/mcp", + "enabled": true + } + ] +} +``` + +Stdio server: + +```json +{ + "servers": [ + { + "name": "memory", + "type": "stdio", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-memory"], + "sessionMode": "shared", + "timeout": 30000 + } + ] +} +``` + +- `sessionMode`: `"shared"` (default) or `"isolated"` (per `x-session-id`) +- Stdio servers are long-lived; restart via UI/API + +## Web UI + +Access: `http://localhost:3333/ui?token=YOUR_TOKEN` + +### Features + +- **Activity Log** — view/filter captured MCP traffic +- **Server Management** — add, edit, remove servers +- **Health Status** — real-time health checks +- **Export** — download logs as JSONL + +Updates in real-time; no manual refresh needed. + +## REST API + +Base: `http://localhost:3333/api` + +All endpoints require Bearer token authentication. + +### GET /api/servers + +List registered servers with health status. + +```bash +curl -H "Authorization: Bearer TOKEN" http://localhost:3333/api/servers +``` + +### POST /api/servers + +Add a server. + +```bash +curl -X POST http://localhost:3333/api/servers \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer TOKEN" \ + -d '{"name": "my-server", "url": "http://localhost:3001/mcp"}' +``` + +With auth headers for upstream: + +```json +{ + "name": "private-api", + "url": "https://api.example.com/mcp", + "headers": { "Authorization": "Bearer SERVER_KEY" } +} +``` + +### GET /api/logs + +Query parameters: `serverName`, `sessionId`, `method`, `limit` (default 100), `before`, `after` + +```bash +curl -H "Authorization: Bearer TOKEN" \ + "http://localhost:3333/api/logs?serverName=my-server&limit=50" +``` + +### POST /api/logs/clear + +Clear logs. Optional: `?serverName=...` or `?before=2025-01-01T00:00:00Z` + +### GET /api/sessions + +List active sessions. + +### GET /api/clients + +List connected clients. + +### GET /api/health + +Health check. + +## Gateway MCP server + +Endpoint: `http://localhost:3333/gateway/mcp` (or `/g/mcp`) + +Requires Bearer token. Any MCP client can connect to manage the gateway programmatically. + +### Available Tools + +| Tool | Description | +| ---------------- | -------------------------------------------------------- | +| `add_server` | Add server (name, url, headers) | +| `remove_server` | Remove server by name | +| `list_servers` | List servers (filter: all/active/inactive) | +| `search_records` | Query logs (serverName, sessionId, method, limit, order) | diff --git a/src/content/docs/mcp-gateway/reference/authentication.md b/src/content/docs/mcp-gateway/references/authentication.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/authentication.md rename to src/content/docs/mcp-gateway/references/authentication.md index 849d15a..2bf5e68 100644 --- a/src/content/docs/mcp-gateway/reference/authentication.md +++ b/src/content/docs/mcp-gateway/references/authentication.md @@ -14,4 +14,3 @@ curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3333/api/servers # Web UI (token in query string) http://localhost:3333/ui?token=YOUR_TOKEN ``` - diff --git a/src/content/docs/mcp-gateway/reference/cli.md b/src/content/docs/mcp-gateway/references/cli.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/cli.md rename to src/content/docs/mcp-gateway/references/cli.md index 6a1e177..79fbf64 100644 --- a/src/content/docs/mcp-gateway/reference/cli.md +++ b/src/content/docs/mcp-gateway/references/cli.md @@ -23,4 +23,3 @@ DEBUG=* mcp-gateway # Enable debug logging ``` CLI flags override environment variables. - diff --git a/src/content/docs/mcp-gateway/reference/gateway-mcp-server.md b/src/content/docs/mcp-gateway/references/gateway-mcp-server.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/gateway-mcp-server.md rename to src/content/docs/mcp-gateway/references/gateway-mcp-server.md index 3645cbb..d78726d 100644 --- a/src/content/docs/mcp-gateway/reference/gateway-mcp-server.md +++ b/src/content/docs/mcp-gateway/references/gateway-mcp-server.md @@ -15,4 +15,3 @@ Requires Bearer token. Any MCP client can connect to manage the gateway programm | `remove_server` | Remove server by name | | `list_servers` | List servers (filter: all/active/inactive) | | `search_records` | Query logs (serverName, sessionId, method, limit, order) | - diff --git a/src/content/docs/mcp-gateway/reference/proxy.md b/src/content/docs/mcp-gateway/references/proxy.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/proxy.md rename to src/content/docs/mcp-gateway/references/proxy.md index cbb39bf..3fc20fe 100644 --- a/src/content/docs/mcp-gateway/reference/proxy.md +++ b/src/content/docs/mcp-gateway/references/proxy.md @@ -22,4 +22,3 @@ claude mcp add --transport http "my-server" \ ``` Proxy endpoints do **not** require authentication—upstream servers handle their own auth. - diff --git a/src/content/docs/mcp-gateway/reference/rest-api.md b/src/content/docs/mcp-gateway/references/rest-api.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/rest-api.md rename to src/content/docs/mcp-gateway/references/rest-api.md index 55f6441..3003d7c 100644 --- a/src/content/docs/mcp-gateway/reference/rest-api.md +++ b/src/content/docs/mcp-gateway/references/rest-api.md @@ -60,4 +60,3 @@ List connected clients. ## GET /api/health Health check. - diff --git a/src/content/docs/mcp-gateway/reference/storage.md b/src/content/docs/mcp-gateway/references/storage.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/storage.md rename to src/content/docs/mcp-gateway/references/storage.md index 2fca792..097e1c3 100644 --- a/src/content/docs/mcp-gateway/reference/storage.md +++ b/src/content/docs/mcp-gateway/references/storage.md @@ -48,4 +48,3 @@ Stdio server: - `sessionMode`: `"shared"` (default) or `"isolated"` (per `x-session-id`) - Stdio servers are long-lived; restart via UI/API - diff --git a/src/content/docs/mcp-gateway/reference/web-ui.md b/src/content/docs/mcp-gateway/references/web-ui.md similarity index 99% rename from src/content/docs/mcp-gateway/reference/web-ui.md rename to src/content/docs/mcp-gateway/references/web-ui.md index fad5ff1..2b12d82 100644 --- a/src/content/docs/mcp-gateway/reference/web-ui.md +++ b/src/content/docs/mcp-gateway/references/web-ui.md @@ -13,4 +13,3 @@ Access: `http://localhost:3333/ui?token=YOUR_TOKEN` - **Export** — download logs as JSONL Updates in real-time; no manual refresh needed. - From f95ffaa0868efba6dda688a0f26febd88c75b903 Mon Sep 17 00:00:00 2001 From: Nlea <36015705+Nlea@users.noreply.github.com> Date: Thu, 4 Dec 2025 16:11:16 +0100 Subject: [PATCH 4/5] Update src/content/docs/mcp-gateway/getting-started.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/content/docs/mcp-gateway/getting-started.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/mcp-gateway/getting-started.mdx b/src/content/docs/mcp-gateway/getting-started.mdx index d73783f..659715c 100644 --- a/src/content/docs/mcp-gateway/getting-started.mdx +++ b/src/content/docs/mcp-gateway/getting-started.mdx @@ -71,4 +71,4 @@ More details [here](https://github.com/fiberplane/mcp-gateway?tab=readme-ov-file ## Next Steps -- [**Reference**](/mcp-gateway/reference/cli) - CLI, storage, API, and all technical details +- [**Reference**](/mcp-gateway/reference#cli) - CLI, storage, API, and all technical details From 4e16b25a490f6e29d75299c8eca01733c1a73359 Mon Sep 17 00:00:00 2001 From: nlea Date: Thu, 4 Dec 2025 16:16:33 +0100 Subject: [PATCH 5/5] minor fixes --- src/content/docs/mcp-gateway/index.md | 4 ++-- src/content/docs/mcp-gateway/reference.md | 4 ++-- src/content/docs/mcp-gateway/references/proxy.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/docs/mcp-gateway/index.md b/src/content/docs/mcp-gateway/index.md index ba70f61..dd90d34 100644 --- a/src/content/docs/mcp-gateway/index.md +++ b/src/content/docs/mcp-gateway/index.md @@ -18,7 +18,7 @@ MCP Gateway is a local development tool that proxies communication between AI ap The gateway operates in dual mode: it's both a proxy for MCP servers AND an MCP server itself. -``` +```text ┌───────────────────────────────────────────────────────────────┐ │ MCP Gateway │ │ │ @@ -71,4 +71,4 @@ The gateway operates in dual mode: it's both a proxy for MCP servers AND an MCP ## Next Steps - [**Getting Started**](/mcp-gateway/getting-started) - Install and configure MCP Gateway -- [**Reference**](/mcp-gateway/reference/cli) - CLI, storage, and API reference +- [**Reference**](/mcp-gateway/reference#cli) - CLI, storage, and API reference diff --git a/src/content/docs/mcp-gateway/reference.md b/src/content/docs/mcp-gateway/reference.md index 1c57194..fe6f6e0 100644 --- a/src/content/docs/mcp-gateway/reference.md +++ b/src/content/docs/mcp-gateway/reference.md @@ -44,7 +44,7 @@ http://localhost:3333/ui?token=YOUR_TOKEN Route MCP clients through the gateway to capture traffic: -``` +```text Direct: MCP Client → http://localhost:3001/mcp → MCP Server Proxied: MCP Client → http://localhost:3333/s/my-server/mcp → Gateway → MCP Server ↓ @@ -66,7 +66,7 @@ Proxy endpoints do **not** require authentication—upstream servers handle thei Files stored under `~/.mcp-gateway/`: -``` +```text ~/.mcp-gateway/ ├── mcp.json # Server registry ├── logs.db # SQLite traffic logs diff --git a/src/content/docs/mcp-gateway/references/proxy.md b/src/content/docs/mcp-gateway/references/proxy.md index 3fc20fe..dff911b 100644 --- a/src/content/docs/mcp-gateway/references/proxy.md +++ b/src/content/docs/mcp-gateway/references/proxy.md @@ -5,7 +5,7 @@ description: Routing MCP traffic through the gateway Route MCP clients through the gateway to capture traffic: -``` +```text Direct: MCP Client → http://localhost:3001/mcp → MCP Server Proxied: MCP Client → http://localhost:3333/s/my-server/mcp → Gateway → MCP Server ↓