src/client.bend
ezmcp@0.1.0.0 · 77 lines · 12 definitions
1
2
3import Base
4import emerging-ezjson@1.2.0.0/main.bend as Json
5import emerging-ezjson@1.2.0.0/src/value.bend as Value
6import emerging-ezhttp@0.21.0.0/src/http.bend as Http
7import ezmcp@0.1.0.0/src/rpc.bend as Rpc
8import ezmcp@0.1.0.0/src/server.bend as Server
9import ezmcp@0.1.0.0/src/sse.bend as Sse
10
11
12
13def init.params(name: String, version: String) -> Value.Json:
14 Json.obj([("protocolVersion", Json.str(Server.latest())),
15 ("capabilities", Json.obj([])),
16 ("clientInfo", Json.obj([("name", Json.str(name)),
17 ("version", Json.str(version))]))])
18
19
20def initialize(id: Value.Json, name: String, version: String) -> Value.Json:
21 Rpc.request(id, "initialize", init.params(name, version))
22
23
24def initialized() -> Value.Json:
25 Rpc.notice("notifications/initialized", Json.obj([]))
26
27
28def tools(id: Value.Json) -> Value.Json:
29 Rpc.request(id, "tools/list", Json.obj([]))
30
31
32def call(id: Value.Json, name: String, args: Value.Json) -> Value.Json:
33 Rpc.request(id, "tools/call",
34 Json.obj([("name", Json.str(name)), ("arguments", args)]))
35
36
37
38def headers(+version: String) -> List<&2, Http.Header>:
39 Bool.pick(List<&2, Http.Header>, String.is_empty(version),
40 [Http.H{"Content-Type", "application/json"},
41 Http.H{"Accept", "application/json, text/event-stream"}],
42 [Http.H{"Content-Type", "application/json"},
43 Http.H{"Accept", "application/json, text/event-stream"},
44 Http.H{"MCP-Protocol-Version", version}])
45
46
47def is.sse(+ctype: String) -> Bool:
48 String.starts_with(String.to_lower(String.trim(ctype)), "text/event-stream")
49
50
51def body(sse: Bool, +text: String) -> String:
52 match sse:
53 case True{}:
54 Sse.last(text)
55 case False{}:
56 text
57
58def took.ok(+ctype: String, text: String, ok: Bool, +status: U32) -> Rpc.Reply:
59 match ok:
60 case True{}:
61 Rpc.read(body(is.sse(ctype), text))
62 case False{}:
63 Rpc.Unread{"HTTP " ++ U32.show(status) ++ ": " ++ text}
64
65
66
67def took(+status: U32, ctype: String, text: String) -> Rpc.Reply:
68 took.ok(ctype, text, U32.is_eq(status, 200), status)
69
70
71def accepted(+status: U32) -> Bool:
72 Bool.and(U32.is_ge(status, 200), U32.is_lt(status, 300))
73
74
75def version(result: Value.Json) -> String:
76 Maybe.default(&2, String, Json.as_str(Json.get(result, "protocolVersion")),
77 "")