Lesson 2 - Step 4 of 5

JSON Request/Response

Handle JSON data in your HTTP server.

Parsing JSON Requests

MCP uses JSON for all messages. Here's how to parse incoming JSON:

python
import json
from http.server import HTTPServer, BaseHTTPRequestHandler


class JSONHandler(BaseHTTPRequestHandler):

    def do_POST(self):
        # Read the body
        content_length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(content_length)

        # Parse JSON
        try:
            data = json.loads(body.decode("utf-8"))
        except json.JSONDecodeError as e:
            self.send_response(400)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            error = {"error": f"Invalid JSON: {e}"}
            self.wfile.write(json.dumps(error).encode())
            return

        # Now `data` is a Python dict
        print(f"Received: {data}")

        # Send JSON response
        response = {"status": "ok", "received": data}
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps(response).encode())

Test It

bash
# Send valid JSON
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "age": 30}'

# Response:
# {"status": "ok", "received": {"name": "Alice", "age": 30}}

# Send invalid JSON
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -d 'not json'

# Response:
# {"error": "Invalid JSON: ..."}

Helper Methods

Let's create reusable helper methods for JSON handling:

python
class JSONHandler(BaseHTTPRequestHandler):

    def read_json(self):
        """Read and parse JSON from request body."""
        content_length = int(self.headers.get("Content-Length", 0))
        if content_length == 0:
            return None
        body = self.rfile.read(content_length)
        return json.loads(body.decode("utf-8"))

    def send_json(self, data, status=200):
        """Send a JSON response."""
        body = json.dumps(data).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def send_error_json(self, status, message):
        """Send a JSON error response."""
        self.send_json({"error": message}, status)

    def do_POST(self):
        try:
            data = self.read_json()
        except json.JSONDecodeError as e:
            self.send_error_json(400, f"Invalid JSON: {e}")
            return

        # Process data...
        self.send_json({"status": "ok", "data": data})

Validating JSON Structure

Check that required fields are present:

python
def do_POST(self):
    try:
        data = self.read_json()
    except json.JSONDecodeError:
        self.send_error_json(400, "Invalid JSON")
        return

    if data is None:
        self.send_error_json(400, "Empty body")
        return

    if not isinstance(data, dict):
        self.send_error_json(400, "Expected JSON object")
        return

    # Check required fields
    required = ["jsonrpc", "method"]
    missing = [f for f in required if f not in data]
    if missing:
        self.send_error_json(400, f"Missing fields: {missing}")
        return

    # Process valid request
    self.send_json({"status": "ok"})
Preparing for MCP

This validation pattern is exactly what you'll need for MCP. Every MCP message must have jsonrpc and method fields.