Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/davidbuenov/dbv-mcp-server/llms.txt

Use this file to discover all available pages before exploring further.

Every interaction with the Unreal Engine 5.8 MCP server follows a fixed three-step lifecycle. The session ID returned during initialization must be threaded through every subsequent request.
1

Initialize the session

Send a POST request to http://localhost:8000/mcp with the initialize payload. No session header is required or expected at this stage.Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": { "name": "MyMCPClient", "version": "1.0" }
  }
}
Response headers (excerpt)
HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: a9cfa12a4424071de4b2709bfaff390e
Response body
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "resources": {},
      "tools": { "listChanged": true }
    },
    "serverInfo": { "name": "", "title": "", "version": "" }
  }
}
Capture the Mcp-Session-Id header value. Every request from this point on must include it. If you omit it the server returns 400 Bad Request. If your session expires the server returns 404 Not Found — re-run this step to get a new ID.
2

Confirm initialization

Send a fire-and-forget notifications/initialized notification. This tells the server that the client has processed the initialize response and is ready to call tools.Request headers
POST http://localhost:8000/mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: a9cfa12a4424071de4b2709bfaff390e
Request body
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
Response
HTTP/1.1 202 Accepted
This is a JSON-RPC notification — it has no id field. The server acknowledges it with 202 Accepted and produces no response body. Clients must not wait for a JSON-RPC result from this message.
3

List available tools and call them

List tools

Use tools/list to enumerate every tool exposed by the server (or by the proxy, which flattens all toolset tools into a single list).
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}
The proxy intercepts this request and returns the three native management tools plus all flattened toolset tools in a single result.tools array.

Call a tool (streaming)

Tool calls use tools/call and return a text/event-stream response. The server writes one or more SSE data: lines before closing the connection.
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "list_toolsets",
    "arguments": {}
  }
}
The following self-contained Python script performs the full handshake and reads the streamed result using only the standard library:
import socket
import json
import time

def read_until_eof_or_timeout(sock, timeout=5.0):
    sock.settimeout(timeout)
    data = b""
    while True:
        try:
            chunk = sock.recv(4096)
            if not chunk:
                break
            data += chunk
            if b"\r\n\r\n" in chunk or b"\n\n" in chunk:
                if b"data:" in data:
                    break
        except socket.timeout:
            break
    return data

def parse_http_response(raw_data):
    parts = raw_data.split(b"\r\n\r\n", 1)
    headers_part = parts[0].decode("utf-8")
    body_part = parts[1] if len(parts) > 1 else b""
    headers_lines = headers_part.split("\r\n")
    status_line = headers_lines[0]
    headers = {}
    for line in headers_lines[1:]:
        if ":" in line:
            k, v = line.split(":", 1)
            headers[k.strip().lower()] = v.strip()
    return status_line, headers, body_part

def send_post(url_path, body_dict, headers_dict=None):
    body_bytes = json.dumps(body_dict).encode("utf-8")
    req = f"POST {url_path} HTTP/1.1\r\n"
    req += "Host: localhost:8000\r\n"
    req += f"Content-Length: {len(body_bytes)}\r\n"
    req += "Content-Type: application/json\r\n"
    if headers_dict:
        for k, v in headers_dict.items():
            req += f"{k}: {v}\r\n"
    req += "\r\n"

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(5.0)
    sock.connect(("127.0.0.1", 8000))
    sock.sendall(req.encode("utf-8") + body_bytes)

    raw_resp = read_until_eof_or_timeout(sock)
    sock.close()
    return parse_http_response(raw_resp)

def execute_streamed_tool(session_id, tool_name, arguments=None):
    if arguments is None:
        arguments = {}
    body_dict = {
        "jsonrpc": "2.0",
        "id": 2,
        "method": "tools/call",
        "params": {"name": tool_name, "arguments": arguments},
    }
    body_bytes = json.dumps(body_dict).encode("utf-8")

    req = "POST /mcp HTTP/1.1\r\n"
    req += "Host: localhost:8000\r\n"
    req += f"Content-Length: {len(body_bytes)}\r\n"
    req += "Content-Type: application/json\r\n"
    req += "Accept: application/json, text/event-stream\r\n"
    req += f"Mcp-Session-Id: {session_id}\r\n"
    req += "\r\n"

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10.0)
    sock.connect(("127.0.0.1", 8000))
    sock.sendall(req.encode("utf-8") + body_bytes)

    raw_resp = read_until_eof_or_timeout(sock, timeout=10.0)
    sock.close()

    status, headers, body = parse_http_response(raw_resp)

    for line in body.decode("utf-8", errors="replace").split("\n"):
        if line.startswith("data:"):
            return json.loads(line[5:].strip())
    return None

if __name__ == "__main__":
    # Step 1 — Initialize
    print("Initializing...")
    status, headers, body = send_post("/mcp", {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "initialize",
        "params": {
            "protocolVersion": "2024-11-05",
            "capabilities": {},
            "clientInfo": {"name": "DemoClient", "version": "1.0"},
        },
    })
    session_id = headers.get("mcp-session-id")
    if not session_id:
        print("Initialization failed — no session ID in response.")
        exit(1)
    print(f"Session established: {session_id}")

    # Step 2 — Confirm
    send_post(
        "/mcp",
        {"jsonrpc": "2.0", "method": "notifications/initialized"},
        {"Mcp-Session-Id": session_id},
    )

    # Step 3 — Call a tool
    print("\nCalling list_toolsets...")
    result = execute_streamed_tool(session_id, "list_toolsets")
    print(json.dumps(result, indent=2))
The execute_streamed_tool function handles the SSE framing: it reads bytes until the socket closes or times out, then finds the data: line and parses it as JSON.

Lifecycle State Diagram

Client                                    Unreal MCP Server (:8000)
  │                                               │
  │──── POST /mcp  {initialize} ────────────────▶│
  │◀─── 200 OK  Mcp-Session-Id: <id> ────────────│
  │                                               │
  │──── POST /mcp  {notifications/initialized} ──▶│  (Mcp-Session-Id required)
  │◀─── 202 Accepted ────────────────────────────│
  │                                               │
  │──── POST /mcp  {tools/list} ────────────────▶│  (Mcp-Session-Id required)
  │◀─── 200 OK  {result:{tools:[...]}} ──────────│
  │                                               │
  │──── POST /mcp  {tools/call} ────────────────▶│  (Mcp-Session-Id required)
  │◀─── 200 OK  Content-Type: text/event-stream ─│
  │     (streaming)  data: {jsonrpc result} ──────│
  │                                               │

Build docs developers (and LLMs) love