@@ -1,5 +1,6 @@
|
|||||||
(ns tbd.mcp.routes-test
|
(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]
|
[muuntaja.core :as m]
|
||||||
[tbd.todo.schema :as todo-schema]
|
[tbd.todo.schema :as todo-schema]
|
||||||
[malli.core :as malli]
|
[malli.core :as malli]
|
||||||
@@ -24,9 +25,25 @@
|
|||||||
:refresh-expires-at expires-at :created-at 1})
|
:refresh-expires-at expires-at :created-at 1})
|
||||||
token))
|
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
|
(defn- rpc
|
||||||
"POST a JSON-RPC message (as data) to /mcp with `token` as the bearer token, optionally within
|
"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] (rpc app token message nil))
|
||||||
([app token message sid]
|
([app token message sid]
|
||||||
(let [body (m/encode "application/json" message)
|
(let [body (m/encode "application/json" message)
|
||||||
@@ -38,7 +55,7 @@
|
|||||||
sid (assoc "mcp-session-id" sid))
|
sid (assoc "mcp-session-id" sid))
|
||||||
:body (ByteArrayInputStream. (.readAllBytes ^java.io.InputStream body))})]
|
:body (ByteArrayInputStream. (.readAllBytes ^java.io.InputStream body))})]
|
||||||
(cond-> resp
|
(cond-> resp
|
||||||
(string? (:body resp)) (update :body #(m/decode "application/json" %))))))
|
(some? (:body resp)) (assoc :body (decode-body resp))))))
|
||||||
|
|
||||||
(defn- initialize
|
(defn- initialize
|
||||||
"Runs the MCP handshake; returns the session id."
|
"Runs the MCP handshake; returns the session id."
|
||||||
|
|||||||
Reference in New Issue
Block a user