01 — HTTP Gateway
Prerequisite: None You will need: A running Streamable HTTP MCP server (test server provided below) Time: 5 minutes Adds: Single remote MCP server behind Hangar as control plane
The Problem
You have one MCP server today. Tomorrow you'll have five. You need a control plane before that happens. Right now, Claude Desktop connects directly to your MCP server — no visibility, no lifecycle management, no single point of configuration. When you add the second server, you're managing two configs. By the fifth, it's chaos.
Prerequisites
You need a running MCP server to point Hangar at. This repo ships a test
server in examples/provider_math/ that runs on Streamable HTTP.
# Build the test MCP server (requires Docker)
docker build -t mcp-math:latest examples/provider_math/
# Start it on port 8080
docker run -d --name mcp-math -p 8080:8080 mcp-math:latest
Verify it is running:
curl -s http://localhost:8080/mcp -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
-H "Content-Type: application/json" | head -c 80
You should see a JSON-RPC response. Keep the container running.
The Config
# config.yaml — Recipe 01: HTTP Gateway
mcp_servers:
my-mcp:
mode: remote
endpoint: http://localhost:8080/mcp
description: "My remote MCP server"
http:
connect_timeout: 10.0
read_timeout: 30.0
Save this as ~/.config/mcp-hangar/config.yaml or pass it with --config.
Try It
-
Test Hangar with the config (using stdin/stdout)
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' | \ mcp-hangar --config ~/.config/mcp-hangar/config.yaml serve{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{...},"serverInfo":{"name":"mcp-registry","version":"1.25.0"}}}Hangar responds to MCP initialize. Press Ctrl+C to stop.
-
Check MCP server status (create test script)
cat > /tmp/test-hangar.sh << 'EOF' #!/bin/bash ( echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' sleep 0.5 echo '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}' sleep 0.5 echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"hangar_status","arguments":{}},"id":2}' sleep 2 ) | mcp-hangar --config ~/.config/mcp-hangar/config.yaml serve 2>/dev/null | grep '"id":2' EOF chmod +x /tmp/test-hangar.sh /tmp/test-hangar.sh{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"...\"id\": \"my-mcp\", \"indicator\": \"[COLD]\", \"state\": \"cold\"..."}]}}MCP Server shows COLD state (not started yet).
-
List tools to trigger cold start
cat > /tmp/test-list.sh << 'EOF' #!/bin/bash ( echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' sleep 0.5 echo '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}' sleep 0.5 echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"hangar_list","arguments":{}},"id":2}' sleep 5 ) | mcp-hangar --config ~/.config/mcp-hangar/config.yaml serve 2>/dev/null | grep '"id":2' EOF chmod +x /tmp/test-list.sh /tmp/test-list.sh{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"...\"mcp_server\": \"my-mcp\", \"state\": \"ready\", \"mode\": \"remote\", \"tools_count\": 2..."}]}}MCP Server transitioned to READY and discovered tools.
-
Configure Claude Desktop
Add to
~/Library/Application Support/Claude/claude_desktop_config.json:{ "mcpServers": { "hangar": { "command": "mcp-hangar", "args": ["serve", "--config", "~/.config/mcp-hangar/config.yaml"] } } }
What Just Happened
Hangar loaded your MCP server configuration and started in stdio mode (JSON-RPC over stdin/stdout). When you sent the initialize handshake, Hangar responded with its capabilities. On the first hangar_list call, Hangar performed a cold start: it connected to the remote MCP server (examples/provider_math in this recipe), sent MCP initialize + tools/list to discover available tools, and registered them in its internal registry.
The test MCP server doesn't know Hangar exists — it sees standard MCP JSON-RPC requests. This is a transparent proxy pattern. Hangar adds nothing yet: no health checks, no circuit breaker, no authentication. That's the point — recipe 01 is the baseline.
Cleanup
When you are done with this recipe (or before starting recipe 02), stop the test container:
docker rm -f mcp-math
Key Config Reference
| Key | Type | Default | Description |
|---|---|---|---|
mode | string | — | MCP Server mode. Use remote for HTTP/SSE MCP servers |
endpoint | string | — | Full URL of the remote MCP server (including path) |
description | string | "" | Human-readable description shown in status |
http.connect_timeout | float | 10.0 | TCP connection timeout in seconds |
http.read_timeout | float | 30.0 | Response read timeout in seconds |
What's Next
Your MCP server is proxied — but what happens when it goes down? Right now, Hangar sends requests into the void and forwards the error. You need visibility into MCP server health before failures surprise you.