Skip to content

Commit acaa90a

Browse files
0.0.13 (#174)
* fix issue with empty Cmd list in container definition causing Image Cmd args to be skipped * mcp socket read loop refactored to reader * webflow needs tool descriptions to be optional - change validation
1 parent cd55679 commit acaa90a

File tree

12 files changed

+124
-66
lines changed

12 files changed

+124
-66
lines changed

dev/catalog.clj

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,14 @@
7575
(generate-updated-catalog)
7676
;; parse catalog
7777
(def catalog (yaml/parse-string (slurp "prompts/catalog.yaml")))
78-
(count (:registry catalog))
78+
(spit "servers.edn" (pr-str (into [] (map name (keys (:registry catalog))))))
7979
(string/join "," (->> (:registry catalog) keys (map name)))
8080

81+
(->> (-> catalog :registry vals)
82+
(map :config )
83+
(filter seq)
84+
count)
85+
8186
(def prompt-ref-strings
8287
(->> catalog
8388
:registry
@@ -90,20 +95,26 @@
9095
:registry
9196
vals
9297
(map :ref)
93-
(map (fn [ref-string] (assoc (git/parse-github-ref ref-string) :ref-string ref-string)))
94-
#_(map #(assoc % :ref "slim/cleanup"))
95-
#_(map #(format "https://raw.githubusercontent.com/%s/%s/refs/heads/%s/%s" (:owner %) (:repo %) (or (:ref %) "main") (:path %)))))
98+
(map (fn [ref-string] (assoc (git/parse-github-ref ref-string) :ref-string ref-string)))))
9699

97100
;; current git ref files
98101
(def local-prompt-files
99102
(->> prompt-refs
100103
(map (fn [k] {:ref k
101-
:file (git/ref-map->prompt-file k)}))))
104+
:file (if (not (:owner k))
105+
(fs/file (:path k))
106+
(git/ref-map->prompt-file k))}))))
107+
108+
(f->prompt (fs/file "prompts/mcp/notion.md") )
109+
(f->prompt (fs/file "prompts/mcp/multiversx-mx.md") )
110+
(f->prompt (fs/file "prompts/mcp/elasticsearch.md") )
102111

103112
;; parse all of the current git prompts
104113
(def local-prompt-files-parsed
105114
(map (fn [m] (-> m (assoc :prompt (f->prompt (:file m))))) local-prompt-files))
106115

116+
(filter #(= "github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/mcp/elasticsearch.md" (-> % :ref :ref-string)) local-prompt-files-parsed)
117+
107118
;; make sure prompts are present - should be empty
108119
(->> local-prompt-files-parsed
109120
(filter (complement #(seq (:prompt %)))))
@@ -115,10 +126,17 @@
115126
(into {})))
116127

117128
;; secret summary
118-
(->> container-summary
119-
vals
120-
(mapcat #(->> % (map (comp :secrets :container))))
121-
(filter seq))
129+
(def secrets
130+
(->> container-summary
131+
vals
132+
(mapcat #(->> % (map (comp :secrets :container))))
133+
(filter seq)))
134+
135+
(->> secrets
136+
(mapcat keys)
137+
(map name)
138+
(string/join ",")
139+
)
122140

123141
;; summary
124142
(->> container-summary

prompts/mcp/notion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mcp:
55
secrets:
66
notion.internal_integration_token: INTERNAL_INTEGRATION_TOKEN
77
environment:
8-
OPENAPI_MCP_HEADERS: ""{\"Authorization\": \"Bearer $INTERNAL_INTEGRATION_TOKEN\", \"Notion-Version\": \"2022-06-28\"}""
8+
OPENAPI_MCP_HEADERS: "\"{\\\"Authorization\\\": \\\"Bearer $INTERNAL_INTEGRATION_TOKEN\\\", \\\"Notion-Version\\\": \\\"2022-06-28\\\"}\""
99
source:
1010
url: https://github.com/makenotion/notion-mcp-server/tree/main
1111
---

runbook.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ docker pull mcp/docker:prerelease
2020

2121
```sh
2222
# docker:command=build-release
23-
VERSION="0.0.12"
23+
VERSION="0.0.13"
2424
docker buildx build \
2525
--builder hydrobuild \
2626
--platform linux/amd64,linux/arm64 \

src/docker.clj

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
[babashka.fs :as fs]
1919
[cheshire.core :as json]
2020
[clojure.core.async :as async]
21+
[clojure.java.io :as io]
2122
[clojure.string :as string]
2223
[creds]
2324
jsonrpc
@@ -27,6 +28,7 @@
2728
schema
2829
shutdown)
2930
(:import
31+
[java.io PipedInputStream PipedOutputStream]
3032
[java.net UnixDomainSocketAddress]
3133
[java.nio ByteBuffer]
3234
[java.nio.channels SocketChannel]
@@ -100,6 +102,12 @@
100102
:password pat
101103
:serveraddress "https://index.docker.io/v1/"}})))
102104

105+
(defn list-containers [m]
106+
(curl/get
107+
"http://localhost/containers/json"
108+
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
109+
:throw false}))
110+
103111
(defn list-images [m]
104112
(curl/get
105113
"http://localhost/images/json"
@@ -153,8 +161,11 @@
153161
;; Tty wraps the process in a pseudo terminal
154162
;; StdinOnce closes the stdin after the first client detaches
155163
;; OpenStdin just opens stdin
156-
(defn create-container [{:keys [image entrypoint workdir command host-dir environment thread-id opts mounts volumes ports network_mode secrets]
157-
:or {opts {:Tty true}}}]
164+
(defn create-container [{:keys [image entrypoint workdir command host-dir
165+
environment thread-id opts mounts volumes
166+
ports network_mode secrets labels]
167+
:or {opts {:Tty true}}
168+
:as m}]
158169
(let [payload (json/generate-string
159170
(merge
160171
{:Image image}
@@ -163,10 +174,14 @@
163174
{:Env (->> environment
164175
(map (fn [[k v]] (format "%s=%s" (name k) v)))
165176
(into []))})
166-
{:Labels (->> secrets
167-
keys
168-
(map (fn [secret-key] (let [s (name secret-key)] [(format "x-secret:%s" s) (string/trim (format "/secret/%s" s))])))
169-
(into {}))}
177+
{:Labels (->> (concat
178+
(->> secrets
179+
keys
180+
(map (fn [secret-key]
181+
(let [s (name secret-key)]
182+
[(format "x-secret:%s" s) (string/trim (format "/secret/%s" s))]))))
183+
(seq labels))
184+
(into {}))}
170185
{:HostConfig
171186
(merge
172187
{:Binds
@@ -185,7 +200,9 @@
185200
(when command {:Cmd command})))
186201
ascii-payload (String. (.getBytes payload "ASCII"))]
187202
(curl/post
188-
"http://localhost/containers/create"
203+
(format
204+
"http://localhost/containers/create%s"
205+
(if (:name m) (format "?name=%s" (:name m)) ""))
189206
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
190207
:throw false
191208
:body ascii-payload
@@ -293,6 +310,7 @@
293310
(def get-archive (comp (status? 200 "container->archive") container->archive))
294311
(def pull (comp (status? 200 "pull-image") pull-image))
295312
(def images (comp ->json list-images))
313+
(def containers (comp ->json (status? 200 "list-containers") list-containers))
296314

297315
(defn add-latest [image]
298316
(let [[_ tag] (re-find #".*(:.*)$" image)]
@@ -478,7 +496,8 @@
478496
(.flip ^ByteBuffer buf)
479497
(while (.hasRemaining buf)
480498
(.write client buf))
481-
(catch Throwable _
499+
(catch Throwable ex
500+
(logger/error "write-stdin error " ex)
482501
client))
483502
client))
484503

@@ -531,41 +550,53 @@
531550
c - channel to write multiplexed stdout stderr blocks"
532551
[in c]
533552
(try
534-
(let [header-buf (ByteBuffer/allocate 8)]
553+
(let [header-buf (ByteBuffer/allocate 8)
554+
stdout (PipedOutputStream.)
555+
stdout-reader (io/reader (PipedInputStream. stdout))]
556+
(async/go-loop []
557+
(when-let [line (.readLine stdout-reader)]
558+
(async/put! c {:stdout line})
559+
(recur)))
535560
(loop [offset 0]
536561
(let [result (.read ^SocketChannel in header-buf)]
537562
(cond
538563
;;;;;;;;;;
539564
(= -1 result)
540-
(async/close! c)
565+
(do
566+
(.close stdout)
567+
(async/close! c))
541568

542569
;;;;;;;;;;
543570
(= 8 (+ offset result))
544-
(do
545-
(let [size (.getInt (ByteBuffer/wrap (Arrays/copyOfRange ^bytes (.array ^ByteBuffer header-buf) 4 8)))
546-
stream-type (case (int (nth (.array ^ByteBuffer header-buf) 0))
547-
0 :stdin
548-
1 :stdout
549-
2 :stderr)
550-
buf (ByteBuffer/allocate size)]
551-
(.clear ^ByteBuffer header-buf)
552-
(loop [offset 0]
553-
(let [result (.read ^SocketChannel in buf)]
554-
(cond
571+
572+
(let [size (.getInt (ByteBuffer/wrap (Arrays/copyOfRange ^bytes (.array ^ByteBuffer header-buf) 4 8)))
573+
stream-type (case (int (nth (.array ^ByteBuffer header-buf) 0))
574+
0 :stdin
575+
1 :stdout
576+
2 :stderr)
577+
buf (ByteBuffer/allocate size)]
578+
(.clear ^ByteBuffer header-buf)
579+
(loop [offset 0]
580+
(let [result (.read ^SocketChannel in buf)]
581+
(cond
555582
;;;;;;;;;;
556-
(= -1 result)
557-
(async/close! c)
583+
(= -1 result)
584+
(async/close! c)
558585

559586
;;;;;;;;;;
560-
(= size (+ offset result))
561-
(async/put! c {stream-type (String. ^bytes (.array buf))})
587+
(= size (+ offset result))
588+
(if (= stream-type :stdout)
589+
(do
590+
(.write stdout ^bytes (.array buf))
591+
(.flush stdout))
592+
(async/put! c {stream-type (String. ^bytes (.array buf))}))
562593

563594
;;;;;;;;;;
564-
:else
565-
(recur (+ offset result)))))
595+
:else
596+
(recur (+ offset result)))))
566597

567-
(.clear ^ByteBuffer buf)
568-
(recur 0)))
598+
(.clear ^ByteBuffer buf)
599+
(recur 0))
569600

570601
;;;;;;;;;;
571602
:else

src/extension/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# IMAGE?=docker/labs-ai-tools-for-devs
22
IMAGE?=docker/labs-ai-tools-for-devs
3-
TAG?=0.2.41
3+
TAG?=0.2.50
44

55
BUILDER=buildx-multi-arch
66

src/extension/docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
mcp_docker:
3-
image: mcp/docker:0.0.12
3+
image: mcp/docker:0.0.13
44
ports:
55
- 8811:8811
66
volumes:

src/git.clj

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535
m))
3636

3737
(defn parse-github-ref [ref]
38-
(some-> ref
39-
split-opts
40-
parse-ref
41-
add-attributes))
38+
(if-let [[_ path] (and ref (re-find #"file://(.*)" ref))]
39+
{:path path}
40+
(some-> ref
41+
split-opts
42+
parse-ref
43+
add-attributes)))
4244

4345
(defn hashch
4446
"returns #uuid"

src/interpolate.clj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@
5555
(cond-> (merge
5656
(:container definition)
5757
(dissoc defaults :functions)
58-
{:command (interpolate-coll
59-
(-> definition :container :command)
60-
arg-context)}
58+
(when (-> definition :container :command)
59+
{:command (interpolate-coll
60+
(-> definition :container :command)
61+
arg-context)})
6162
(when (-> definition :container :entrypoint)
6263
{:entrypoint (->> (-> definition :container :entrypoint)
6364
(map (fn [s] (first (interpolate arg-context s))))

src/jsonrpc/prompt_change_events.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
(let [{x :container}
6565
(docker/run-streaming-function-with-no-stdin
6666
{:image "vonwig/inotifywait:latest"
67+
:labels {"com.docker.desktop.service" "true"}
6768
:volumes ["docker-prompts:/prompts"]
6869
:command ["-e" "create" "-e" "modify" "-e" "delete" "-q" "-m" "/prompts"]}
6970
(fn [line]

src/mcp/client.clj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
socket-channel (docker/attach-socket (:Id x))
4747
c (async/chan 10)
4848
dead-channel (async/chan)]
49-
5049
(docker/start x)
5150

5251
;; process the output-stream of the container
@@ -93,9 +92,7 @@
9392

9493
;; non-stdout message - show to user
9594
:else
96-
(do
97-
(logger/info "socket read loop " (:stderr block))
98-
(recur)))))
95+
(recur))))
9996

10097
;; add a function to send a jsonrpc request
10198
(assoc x

0 commit comments

Comments
 (0)