From 0d1ace8e5787ff5e9705ba323aed2f21237e9679 Mon Sep 17 00:00:00 2001 From: haranishi <223786623+haranishi@users.noreply.github.com> Date: Mon, 12 Oct 2026 06:52:24 +0900 Subject: [PATCH] docs(http): document curl session lifecycle (#1052) --- Server/README.md | 4 + website/docs/guides/http-client-sessions.md | 93 +++++++++++++++++++++ website/docs/guides/troubleshooting.md | 10 +++ website/sidebars.js | 1 + 4 files changed, 108 insertions(+) create mode 100644 website/docs/guides/http-client-sessions.md diff --git a/Server/README.md b/Server/README.md index adc1cd60d5..e952527c84 100644 --- a/Server/README.md +++ b/Server/README.md @@ -29,6 +29,10 @@ Install and run directly from PyPI using `uvx`. uvx --from mcpforunityserver mcp-for-unity --transport http --http-url http://localhost:8080 ``` +To connect with curl or a custom HTTP client, follow the +[HTTP client session guide](https://coplaydev.github.io/unity-mcp/guides/http-client-sessions) +to initialize and reuse the required session headers. + **MCP Client Configuration (HTTP):** ```json diff --git a/website/docs/guides/http-client-sessions.md b/website/docs/guides/http-client-sessions.md new file mode 100644 index 0000000000..c0352a003d --- /dev/null +++ b/website/docs/guides/http-client-sessions.md @@ -0,0 +1,93 @@ +--- +id: http-client-sessions +slug: /guides/http-client-sessions +title: HTTP Client Sessions +sidebar_label: HTTP Client Sessions +description: Initialize a Streamable HTTP session and reuse its headers with curl or other HTTP clients. +--- + +# HTTP Client Sessions + +A local server in HTTP mode accepts MCP JSON-RPC requests at `/mcp`. Its +initialization response includes `MCP-Session-Id`. Save that value and send it +with every later request, together with the negotiated `MCP-Protocol-Version`. +HTTP connections can close between requests; the session state remains on the server. + +The [Streamable HTTP specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management) +defines these headers. After initialization, send +[`notifications/initialized`](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization) +without an `id`, then make tool or resource requests. + +## Try it with curl + +Start the server in HTTP mode first. This Bash example needs curl, awk, and +Python 3; use Bash on macOS/Linux or Git Bash/WSL on Windows. Set `MCP_URL` if your +server uses a different port. Each curl invocation opens a separate connection. +The example accepts protocol `2025-11-25` and stops if a different version is negotiated. + +```bash +set -eu +MCP_URL=${MCP_URL:-http://127.0.0.1:8080/mcp} +headers_file=$(mktemp) +reply_file=$(mktemp) +trap 'rm -f "$headers_file" "$reply_file"' EXIT + +curl --fail --silent --show-error --max-time 15 \ + --dump-header "$headers_file" --output "$reply_file" \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json, text/event-stream' \ + --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl-example","version":"1.0.0"}}}' \ + "$MCP_URL" + +session_id=$(awk 'tolower($1)=="mcp-session-id:" {gsub("\r", "", $2); print $2}' "$headers_file") +[ -n "$session_id" ] || { echo 'No MCP-Session-Id returned' >&2; exit 1; } +protocol_version=$(python3 - "$reply_file" <<'PYTHON' +import json, sys +from pathlib import Path +text = Path(sys.argv[1]).read_text(encoding="utf-8") +try: + reply = json.loads(text) +except json.JSONDecodeError: + reply = next(json.loads(line[5:].strip()) for line in text.splitlines() + if line.startswith("data:") and line[5:].strip()) +print(reply["result"]["protocolVersion"]) +PYTHON +) +[ "$protocol_version" = '2025-11-25' ] || { echo 'Unsupported negotiated protocol version' >&2; exit 1; } + +mcp_post() { + curl --fail --silent --show-error --max-time 15 \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json, text/event-stream' \ + --header "MCP-Session-Id: $session_id" \ + --header "MCP-Protocol-Version: $protocol_version" \ + --data "$1" "$MCP_URL" +} + +mcp_post '{"jsonrpc":"2.0","method":"notifications/initialized"}' +mcp_post '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' +mcp_post '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"mcpforunity://instances"}}' + +curl --fail --silent --show-error --max-time 15 --request DELETE \ + --header "MCP-Session-Id: $session_id" \ + --header "MCP-Protocol-Version: $protocol_version" "$MCP_URL" +``` + +The initialized notification returns HTTP `202` with an empty body. Request +responses can contain JSON or SSE messages (`data: {...}`); parse the response's +content type. These calls do not need a separate, long-lived GET/SSE connection. +An empty instance list means the HTTP session works but no Unity Editor is connected. +For tool calls, use the names and argument schemas returned by `tools/list` and +choose an Editor as described in [Multi-Instance Routing](/guides/multi-instance). + +## Recover from session errors + +- **400, Missing session ID:** include the returned `MCP-Session-Id` on the notification and every later request. +- **400, unsupported protocol version:** send the version negotiated in `InitializeResult`. +- **404, session no longer exists:** initialize again without the old session header, then send a new initialized notification. + +## Local commands without an MCP session + +The [CLI](/guides/cli) sends local Editor commands through `/api/command` without +an MCP session. Those CLI routes are disabled in +[remote-hosted mode](/guides/remote-server-auth). diff --git a/website/docs/guides/troubleshooting.md b/website/docs/guides/troubleshooting.md index 07e53f905a..d8b1cdfdf6 100644 --- a/website/docs/guides/troubleshooting.md +++ b/website/docs/guides/troubleshooting.md @@ -203,6 +203,16 @@ If a read fails with an unknown-server error, list resources first and use the k --- +## HTTP: "Bad Request: Missing session ID" + +After `initialize`, send the response's `MCP-Session-Id` header on every later +request, including `notifications/initialized`. Include the negotiated +`MCP-Protocol-Version` too. The +[HTTP client session guide](/guides/http-client-sessions) provides a complete +curl example and session recovery steps. + +--- + ## "No Unity Instances Found" :::tip When in doubt, restart your client diff --git a/website/sidebars.js b/website/sidebars.js index 843fab4711..cd331d8fd9 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -27,6 +27,7 @@ const sidebars = { 'guides/claude-code-cli', 'guides/client-configurators', 'guides/multi-instance', + 'guides/http-client-sessions', 'guides/tool-groups', 'guides/cli', 'guides/cli-examples',