diff --git a/test/tbd/mcp/routes_test.clj b/test/tbd/mcp/routes_test.clj index 48e58a9..d7ca93b 100644 --- a/test/tbd/mcp/routes_test.clj +++ b/test/tbd/mcp/routes_test.clj @@ -1,5 +1,6 @@ (ns tbd.mcp.routes-test - (:require [clojure.test :refer [deftest is testing]] + (:require [clojure.string :as str] + [clojure.test :refer [deftest is testing]] [muuntaja.core :as m] [tbd.todo.schema :as todo-schema] [malli.core :as malli] @@ -24,9 +25,25 @@ :refresh-expires-at expires-at :created-at 1}) token)) +(defn- decode-body + "The JSON-RPC message in a response body. plumcp answers a POST either with plain JSON or, when + it decides to stream (which one is a matter of timing, so a slow CI runner sees the other), as + Server-Sent Events: a seq of chunks whose `data:` lines hold the message. Clients accept both, + so the tests must too." + [{:keys [body headers]}] + (cond + (string? body) (m/decode "application/json" body) + (and (some? body) (str/starts-with? (str (get headers "Content-Type")) "text/event-stream")) + (let [data (->> (str/split-lines (if (instance? java.io.InputStream body) (slurp body) (apply str body))) + (keep #(when (str/starts-with? % "data:") (str/trim (subs % 5)))) + (str/join "\n"))] + (m/decode "application/json" data)) + :else body)) + (defn- rpc "POST a JSON-RPC message (as data) to /mcp with `token` as the bearer token, optionally within - the MCP session `sid`. Returns the response with its JSON body decoded (nil when there is none)." + the MCP session `sid`. Returns the response with its body decoded, whether plain JSON or an event + stream (nil when there is none)." ([app token message] (rpc app token message nil)) ([app token message sid] (let [body (m/encode "application/json" message) @@ -38,7 +55,7 @@ sid (assoc "mcp-session-id" sid)) :body (ByteArrayInputStream. (.readAllBytes ^java.io.InputStream body))})] (cond-> resp - (string? (:body resp)) (update :body #(m/decode "application/json" %)))))) + (some? (:body resp)) (assoc :body (decode-body resp)))))) (defn- initialize "Runs the MCP handshake; returns the session id."