Skip to content

Latest commit

 

History

History
327 lines (255 loc) · 7.75 KB

File metadata and controls

327 lines (255 loc) · 7.75 KB

HTTP Usage Guide - StreamableHTTP Transport

The Etherscan MCP Server uses the modern StreamableHTTP transport as specified in the MCP protocol. This provides session-based communication with SSE streaming support.

Server Endpoints

Endpoint Method Purpose
/health GET Health check - returns server status
/mcp POST Initialize session or send requests
/mcp GET Establish SSE stream for session
/mcp DELETE Terminate session

Starting the Server

npm start
# or
npm run dev

Server starts on http://localhost:3000 by default.

MCP Protocol Flow

1. Initialize Session

First request must be an initialize method without a session ID:

curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": { "tools": {} },
      "clientInfo": {
        "name": "my-client",
        "version": "1.0.0"
      }
    }
  }'

Response Headers:

  • mcp-session-id: Your session identifier (e.g., a4e1e210-ede0-4e7a-a7c4-8335faafe814)

Response Body: SSE format with initialization result

2. List Tools

Send requests with the session ID header:

curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: a4e1e210-ede0-4e7a-a7c4-8335faafe814" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {}
  }'

Response: SSE format with tools list

3. Call a Tool

curl -X POST http://localhost:3000/mcp \
  -H "Content-Type": application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: a4e1e210-ede0-4e7a-a7c4-8335faafe814" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "etherscan_gas_oracle",
      "arguments": {
        "chainid": "1"
      }
    }
  }'

4. Establish SSE Stream

For real-time notifications and events:

curl -N -X GET http://localhost:3000/mcp \
  -H "mcp-session-id: a4e1e210-ede0-4e7a-a7c4-8335faafe814" \
  -H "Accept: text/event-stream"

This keeps the connection open and streams events.

5. Terminate Session

When done:

curl -X DELETE http://localhost:3000/mcp \
  -H "mcp-session-id: a4e1e210-ede0-4e7a-a7c4-8335faafe814"

Response Format

All responses use Server-Sent Events (SSE) format:

event: message
data: {"jsonrpc":"2.0","id":1,"result":{...}}

To parse SSE responses:

  1. Look for lines starting with data:
  2. Extract the JSON after data:
  3. Parse as JSON-RPC response

Health Check

Simple JSON response (not SSE):

curl http://localhost:3000/health

Response:

{
  "status": "ok",
  "tools": 65,
  "transport": "streamable-http",
  "protocol": "MCP",
  "sessions": 1
}

Required Headers

For POST requests:

  • Content-Type: application/json
  • Accept: application/json, text/event-stream (both required!)
  • mcp-session-id: <session-id> (except for initialization)

For GET requests:

  • mcp-session-id: <session-id>
  • Accept: text/event-stream

Session Management

  • Sessions are created on first initialize request
  • Session IDs are generated server-side (UUID format)
  • Sessions persist until explicitly terminated or server restart
  • Each session maintains its own transport state

Example: Complete Flow

# 1. Initialize
RESPONSE=$(curl -i -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}')

# 2. Extract session ID
SESSION_ID=$(echo "$RESPONSE" | grep -i "mcp-session-id:" | cut -d ' ' -f 2 | tr -d '\r')

echo "Session ID: $SESSION_ID"

# 3. List tools
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

# 4. Call tool
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"etherscan_gas_oracle","arguments":{"chainid":"1"}}}'

# 5. Terminate
curl -X DELETE http://localhost:3000/mcp \
  -H "mcp-session-id: $SESSION_ID"

Using with JavaScript/Node.js

// 1. Initialize session
const initResponse = await fetch('http://localhost:3000/mcp', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json, text/event-stream'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'initialize',
    params: {
      protocolVersion: '2024-11-05',
      capabilities: { tools: {} },
      clientInfo: { name: 'my-app', version: '1.0.0' }
    }
  })
});

const sessionId = initResponse.headers.get('mcp-session-id');
console.log('Session:', sessionId);

// 2. Parse SSE response
const initText = await initResponse.text();
const initData = parseSSE(initText); // Extract JSON from SSE format

// 3. List tools
const toolsResponse = await fetch('http://localhost:3000/mcp', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json, text/event-stream',
    'mcp-session-id': sessionId
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 2,
    method: 'tools/list',
    params: {}
  })
});

const toolsText = await toolsResponse.text();
const toolsData = parseSSE(toolsText);
console.log('Tools:', toolsData.result.tools.length);

// Helper to parse SSE
function parseSSE(sseText) {
  const lines = sseText.split('\n');
  for (const line of lines) {
    if (line.startsWith('data: ')) {
      return JSON.parse(line.substring(6));
    }
  }
  return null;
}

Error Handling

400 Bad Request

  • Missing or invalid session ID
  • Session not found
  • Invalid request format

406 Not Acceptable

  • Missing required Accept headers
  • Must accept both application/json and text/event-stream

500 Internal Server Error

  • Server-side error
  • Check Etherscan API key
  • Check server logs

Testing

Run the included test:

node test-full-mcp.mjs

This tests:

  • Session initialization
  • Tools listing
  • Tool execution
  • SSE streaming
  • Session management

Differences from Old SSE Transport

Old (deprecated) New (StreamableHTTP)
Single endpoint /sse Session-based /mcp
No session management Explicit session IDs
Protocol 2024-11-05 Current protocol
Single transport Per-session transports

Production Considerations

  1. Session Cleanup: Implement session timeout/cleanup
  2. Rate Limiting: Add per-session rate limits
  3. Authentication: Add auth middleware if needed
  4. CORS: Configure for web clients
  5. Monitoring: Track active sessions
  6. Load Balancing: Sessions are server-local, use sticky sessions

Troubleshooting

"Invalid or missing session ID"

→ Initialize a session first via POST without session ID

"Not Acceptable" error

→ Include both Accept types: application/json, text/event-stream

Can't parse response

→ Response is SSE format, parse data: lines

Session not found

→ Session may have expired or server restarted

Resources