Skip to content

Commit 0892905

Browse files
Slim/0.0.14 (#195)
* make resource scraping optional * Remove images/json calls * Check whether it's a poci at tool call time
1 parent 784f534 commit 0892905

File tree

8 files changed

+95
-75
lines changed

8 files changed

+95
-75
lines changed

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.13"
23+
VERSION="0.0.14"
2424
docker buildx build \
2525
--builder hydrobuild \
2626
--platform linux/amd64,linux/arm64 \

src/docker.clj

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,10 @@
185185
{:HostConfig
186186
(merge
187187
{:Binds
188-
(concat ["docker-lsp:/docker-lsp"
189-
"/var/run/docker.sock:/var/run/docker.sock"]
190-
(when host-dir [(format "%s:/project:rw" host-dir)])
191-
(when thread-id [(format "%s:/thread:rw" thread-id)])
192-
(or volumes mounts))}
188+
(concat
189+
(when host-dir [(format "%s:/project:rw" host-dir)])
190+
(when thread-id [(format "%s:/thread:rw" thread-id)])
191+
(or volumes mounts))}
193192
(when network_mode
194193
{:NetworkMode network_mode})
195194
(when ports
@@ -227,9 +226,9 @@
227226
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
228227
:throw false}))
229228

230-
(defn inspect-image [{:keys [Id]}]
229+
(defn inspect-image [{:keys [Name Id]}]
231230
(curl/get
232-
(format "http://localhost/images/%s/json" Id)
231+
(format "http://localhost/images/%s/json" (or Name Id))
233232
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
234233
:throw false}))
235234

@@ -339,12 +338,9 @@
339338

340339
(defn has-image? [image]
341340
(let [[_ digest] (re-find #".*@(.*)" image)]
342-
(some
343-
(fn [{:keys [RepoTags Id]}]
344-
(or
345-
(some #(= % image) RepoTags)
346-
(and digest (= digest Id))))
347-
(images {}))))
341+
(try
342+
(image-inspect (if digest {:Id digest} {:Name image}))
343+
(catch Throwable _))))
348344

349345
(defn check-then-pull [container-definition]
350346
(when (not (has-image? (:image container-definition)))
@@ -375,9 +371,7 @@
375371
(check-then-pull container-definition)
376372
(let [{:keys [Entrypoint Cmd Env]}
377373
(->
378-
(image-inspect
379-
(-> (images {"reference" [(:image container-definition)]})
380-
first))
374+
(image-inspect {:Name (:image container-definition)})
381375
:Config)
382376
real-entrypoint (string/join " " (concat
383377
(or (:entrypoint container-definition) Entrypoint)
@@ -554,9 +548,9 @@
554548
stdout (PipedOutputStream.)
555549
stdout-reader (io/reader (PipedInputStream. stdout))]
556550
(async/go-loop []
557-
(when-let [line (.readLine stdout-reader)]
558-
(async/put! c {:stdout line})
559-
(recur)))
551+
(when-let [line (.readLine stdout-reader)]
552+
(async/put! c {:stdout line})
553+
(recur)))
560554
(loop [offset 0]
561555
(let [result (.read ^SocketChannel in header-buf)]
562556
(cond

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.50
3+
TAG?=0.2.56
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.13
3+
image: mcp/docker:0.0.14
44
ports:
55
- 8811:8811
66
volumes:

src/jsonrpc/logger.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
`(when *logger*
5555
(-debug *logger* ~fmeta ~@args))))
5656

57-
(defn trace [x]
58-
(info "trace " x)
59-
x)
57+
(defn trace
58+
([x] (info "trace " x) x)
59+
([s x] (info (format "%s %s" s x)) x))
6060

6161
(defn log! [level args fmeta]
6262
(timbre/log! level :p args {:?line (:line fmeta)

src/jsonrpc/server.clj

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@
201201
(async/into [])
202202
(async/<!!))]
203203
(merge
204-
{:resourceTemplates resource-templates}
205-
(when (= 100 (count resource-templates))
206-
{:nextCursor nextCursor}))))
204+
{:resourceTemplates resource-templates}
205+
(when (= 100 (count resource-templates))
206+
{:nextCursor nextCursor}))))
207207

208208
(defmethod lsp.server/receive-request "resources/subscribe" [_ _ params]
209209
(logger/info "resources/subscribe" params)
@@ -261,51 +261,69 @@
261261
(mapcat (comp :content :result))
262262
(into []))))
263263

264+
(defn get-functions [db*]
265+
(->> @db* :mcp.prompts/registry vals (mapcat :functions)))
266+
267+
(defn poci? [{:keys [db*] :as components} params]
268+
(not
269+
(= :mcp
270+
(-> (filter #(= (-> params :name) (-> % :function :name)) (get-functions db*))
271+
first
272+
:function
273+
:container
274+
:type))))
275+
276+
(defn make-tool-calls [{:keys [db* server-id] :as components} params {:keys [thread-id] :as opts}]
277+
;; TODO non-mcp tool calls are maps of content, role tool_call_id
278+
;; we turn them into one text message and respond to the jsonrpc request here
279+
;; for mcp tool calls the response will already be valid content
280+
;; so we can concat it and just return the result (or error)
281+
;; tool-outputs are :content, :role, :tool_call_id
282+
;; (MCP doesn't care about :role or :tool_call_id - these are client concerns)
283+
(let [tool-outputs (->>
284+
(tools/make-tool-calls
285+
0
286+
(partial
287+
tools/function-handler
288+
(merge
289+
{:functions (get-functions db*)
290+
:host-dir (-> @db* :host-dir)
291+
:server-id server-id}
292+
(when thread-id {:thread-id thread-id})))
293+
;; tool calls are functions, which are arguments,name maps, and ids
294+
;; mcp tool call params are also maps of name, and arguments
295+
[{:function (update
296+
params :arguments
297+
(fn [arguments]
298+
(logger/trace
299+
(-> arguments
300+
(merge
301+
(db/parameter-values (:name params))
302+
(select-keys (-> @db* :servers (get server-id)) [:roots]))
303+
(json/generate-string)))))
304+
;; TODO there's no id here like in regular agent tool calling loops
305+
;; MCP clients do this on their side (using just the response id)
306+
:id "1"}])
307+
(async/reduce conj [])
308+
(async/<!!))]
309+
;; TODO with mcp, tool-calls with errors are still jsonrpc results
310+
;; protocol errors are jsonrpc errors, with a code and a message
311+
;; TODO if result is ::method-not-found, we'll get a protocol error
312+
;; responding with a map containing an :error key will also generate a protocol error
313+
{:content (create-tool-outputs tool-outputs)
314+
:is-error false}))
315+
264316
(defn mcp-tool-calls
265317
" params
266318
db* - uses mcp.prompts/registry and host-dir
267319
params - tools/call mcp params"
268320
[{:keys [db* server-id] :as components} params]
269-
(volumes/with-volume
270-
(fn [thread-id]
271-
;; TODO non-mcp tool calls are maps of content, role tool_call_id
272-
;; we turn them into one text message and respond to the jsonrpc request here
273-
;; for mcp tool calls the response will already be valid content
274-
;; so we can concat it and just return the result (or error)
275-
;; tool-outputs are :content, :role, :tool_call_id
276-
;; (MCP doesn't care about :role or :tool_call_id - these are client concerns)
277-
(let [tool-outputs (->>
278-
(tools/make-tool-calls
279-
0
280-
(partial
281-
tools/function-handler
282-
{:functions (->> @db* :mcp.prompts/registry vals (mapcat :functions))
283-
:host-dir (-> @db* :host-dir)
284-
:server-id server-id
285-
:thread-id thread-id})
286-
;; tool calls are functions, which are arguments,name maps, and ids
287-
;; mcp tool call params are also maps of name, and arguments
288-
[{:function (update
289-
params :arguments
290-
(fn [arguments]
291-
(logger/trace
292-
(-> arguments
293-
(merge
294-
(db/parameter-values (:name params))
295-
(select-keys (-> @db* :servers (get server-id)) [:roots]))
296-
(json/generate-string)))))
297-
:id "1"}])
298-
(async/reduce conj [])
299-
(async/<!!))]
300-
;; TODO with mcp, tool-calls with errors are still jsonrpc results
301-
;; protocol errors are jsonrpc errors, with a code and a message
302-
;; TODO if result is ::method-not-found, we'll get a protocol error
303-
;; responding with a map containing an :error key will also generate a protocol error
304-
{:content
305-
(concat
306-
(create-tool-outputs tool-outputs)
307-
(volumes/pick-up-mcp-resources thread-id (partial update-resources components)))
308-
:is-error false}))))
321+
(if (poci? components params)
322+
(volumes/with-volume
323+
(fn [thread-id]
324+
(let [response (make-tool-calls components params {:thread-id thread-id})]
325+
(update response :content concat (volumes/pick-up-mcp-resources thread-id (partial update-resources components))))))
326+
(make-tool-calls components params {})))
309327

310328
(defmethod lsp.server/receive-request "tools/call" [_ components params]
311329
(logger/info "tools/call")

src/mcp/client.clj

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -305,15 +305,9 @@
305305
(recur)))
306306
;; ------------------------------
307307

308-
(defn inspect-image [container-definition]
309-
(:Id
310-
(docker/image-inspect
311-
(-> (docker/images {"reference" [(:image container-definition)]})
312-
first))))
313-
314308
(defn add-digest [container-definition]
315309
(docker/check-then-pull container-definition)
316-
(assoc container-definition :digest (inspect-image container-definition)))
310+
(assoc container-definition :digest (:Id (docker/image-inspect {:Name (:image container-definition)}))))
317311

318312
(def cached-mcp-get-tools
319313
(fn [container-definition]

test/mcp/client_t.clj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,20 @@
253253
:workdir "/usr/local/app" }}]
254254
:local-get-tools -get-tools})
255255

256+
(get-mcp-tools-from-prompt
257+
{:mcp [{:container
258+
{:image "mcp/webflow:latest"
259+
:workdir "/app"
260+
:secrets {:webflow.token "WEBFLOW_TOKEN"} }}]
261+
:local-get-tools -get-tools})
262+
263+
(get-mcp-tools-from-prompt
264+
{:mcp [{:container
265+
{:image "mcp/azure:latest"
266+
:workdir "/app"
267+
:command ["server" "start"] }}]
268+
:local-get-tools -get-tools})
269+
256270
(docker/run-container
257271
(docker/inject-secret-transform
258272
{:image "mcp/time:latest"

0 commit comments

Comments
 (0)