Skip to content

Commit ea80da7

Browse files
Slim/mcptests (#84)
* add mcp tests * Add github-mcp-server * response to resource template requests
1 parent ea73701 commit ea80da7

File tree

18 files changed

+433
-375
lines changed

18 files changed

+433
-375
lines changed

dev/catalog.clj

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
[clojure.pprint :refer [pprint]]
88
[clojure.string :as string]
99
[flatland.ordered.map :refer [ordered-map]]
10-
git
10+
[git]
1111
[markdown :as markdown-parser]
1212
[mcp.client :as client]
1313
[medley.core :as medley]
14-
prompts
15-
repl))
14+
[prompts]
15+
[repl]))
1616

1717
(defn mcp-metadata-cache [f]
1818
(edn/read-string
@@ -29,7 +29,7 @@
2929
(println t))))
3030

3131
(defn f->prompt [f]
32-
(try (prompts/get-prompts {:prompts f}) (catch Throwable t (println t) {})))
32+
(try (prompts/read-prompts {:prompts f}) (catch Throwable t (println t) {})))
3333

3434
(defn tile-metadata [m]
3535
{:tools (->> (:functions m)
@@ -57,6 +57,18 @@
5757
(map #(into [] %))
5858
(into {}))})))))
5959

60+
(defn secrets [prompt]
61+
(cond
62+
(-> prompt :metadata :mcp)
63+
(->> (-> prompt :metadata :mcp)
64+
(map (fn [m] m))
65+
(into []))
66+
(-> prompt :functions)
67+
(->> (-> prompt :functions)
68+
(map (fn [m] (select-keys (:function m) [:container :secrets :source])))
69+
(into []))
70+
:else []))
71+
6072
(comment
6173
;; setup stdout logger
6274
(repl/setup-stdout-logger)
@@ -66,33 +78,54 @@
6678
(count (:registry catalog))
6779
(string/join "," (->> (:registry catalog) keys (map name)))
6880

69-
;; raw github urls to for the slim/cleanup branch
81+
(def prompt-ref-strings
82+
(->> catalog
83+
:registry
84+
vals
85+
(map :ref)))
86+
87+
;; raw github urls (map to other branches if checking a merge)
7088
(def prompt-refs
7189
(->> catalog
7290
:registry
7391
vals
7492
(map :ref)
75-
(map #(git/parse-github-ref %))
76-
(map #(assoc % :ref "slim/cleanup"))
93+
(map (fn [ref-string] (assoc (git/parse-github-ref ref-string) :ref-string ref-string)))
94+
#_(map #(assoc % :ref "slim/cleanup"))
7795
#_(map #(format "https://raw.githubusercontent.com/%s/%s/refs/heads/%s/%s" (:owner %) (:repo %) (or (:ref %) "main") (:path %)))))
7896

7997
;; current git ref files
8098
(def local-prompt-files
8199
(->> prompt-refs
82-
(map git/ref-map->prompt-file)))
83-
84-
;; parse all of the current git prompts
85-
(with-redefs [client/get-mcp-tools-from-prompt (constantly [])]
86-
(def all-prompt-files (map (fn [[k v]] [k (f->prompt v)]) local-prompt-files)))
87-
88-
(pprint (->> all-prompt-files
89-
(map (fn [[k v]] [k (dissoc v :mcp/resources)]))
90-
(into {})))
91-
(spit "crap.json" (json/generate-string
92-
(->> all-prompt-files
93-
(map (fn [[k v]] [k (dissoc v :mcp/resources :mcp/prompt-registry)]))
94-
(into {}))
95-
{:pretty true}))
100+
(map (fn [k] {:ref k
101+
:file (git/ref-map->prompt-file k)}))))
102+
103+
;; parse all of the current git prompts
104+
(def local-prompt-files-parsed
105+
(map (fn [m] (-> m (assoc :prompt (f->prompt (:file m))))) local-prompt-files))
106+
107+
;; make sure prompts are present - should be empty
108+
(->> local-prompt-files-parsed
109+
(filter (complement #(seq (:prompt %)))))
110+
111+
;; extract secrets, source and container image info
112+
(def container-summary
113+
(->> local-prompt-files-parsed
114+
(map (fn [m] [(-> m :ref :ref-string) (secrets (:prompt m))]))
115+
(into {})))
116+
117+
;; secret summary
118+
(->> container-summary
119+
vals
120+
(mapcat #(->> % (map (comp :secrets :container))))
121+
(filter seq))
122+
123+
;; summary
124+
(->> container-summary
125+
(mapcat (fn [[k v]] (->> v (map (fn [m]
126+
{:image (-> m :container :image)
127+
:source (-> m :source :url)
128+
:ref k}))))))
96129

97130
(def all-images
98131
(->>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM ghcr.io/github/github-mcp-server as github
2+
3+
FROM debian:bookworm-slim
4+
5+
WORKDIR /server
6+
7+
COPY --from=github /server/github-mcp-server .
8+
9+
ENTRYPOINT ["/server/github-mcp-server", "stdio"]
10+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
```sh
3+
docker buildx build \
4+
--builder hydrobuild \
5+
--platform linux/amd64,linux/arm64 \
6+
--tag mcp/github-mcp-server:latest \
7+
--file Dockerfile \
8+
--push .
9+
docker pull mcp/github-mcp-server:latest
10+
```
11+
12+

namespaces.dot

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
digraph G {
2+
// Graph settings
3+
rankdir=LR; // Left to right layout
4+
node [shape=box, style=filled, fillcolor=lightblue, fontname="Arial"];
5+
edge [fontname="Arial", fontsize=10];
6+
7+
// Main node
8+
"jsonrpc.server" [fillcolor=lightgreen];
9+
10+
// Connected nodes
11+
"jsonrpc.db";
12+
"tools";
13+
"volumes";
14+
"mcp.client";
15+
"git";
16+
"docker";
17+
"interpolate";
18+
"prompts";
19+
"markdown";
20+
21+
// Connections from jsonrpc.server to other nodes
22+
"jsonrpc.server" -> "jsonrpc.db";
23+
"jsonrpc.server" -> "tools";
24+
"jsonrpc.server" -> "volumes";
25+
"jsonrpc.server" -> "mcp.client";
26+
"jsonrpc.server" -> "git";
27+
"jsonrpc.server" -> "docker";
28+
29+
"git" -> "docker";
30+
"markdown" -> "docker";
31+
32+
// tools
33+
"tools" -> "mcp.client";
34+
"tools" -> "interpolate";
35+
"tools" -> "docker";
36+
"tools" -> "git";
37+
38+
// Additional connections from mcp.client
39+
"mcp.client" -> "docker";
40+
"mcp.client" -> "interpolate";
41+
42+
// Additional connections from jsonrpc.db
43+
"jsonrpc.db" -> "git";
44+
"jsonrpc.db" -> "prompts";
45+
46+
// Additional connections from prompts
47+
"prompts" -> "mcp.client";
48+
"prompts" -> "markdown";
49+
}

prompts/catalog.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,4 +478,11 @@ registry:
478478
description: comma separated list of reply to email addresses
479479
secrets:
480480
- {name: resend.api_key}
481+
GitHub MCP Server:
482+
description: |
483+
Provides seamless integration with GitHub APIs, enabling advanced automation and interaction capabilities for developers and tools.
484+
ref: github:docker/labs-ai-tools-for-devs?path=prompts/mcp/github-official.md
485+
icon: https://cdn.jsdelivr.net/npm/simple-icons@v7/icons/github.svg
486+
secrets:
487+
- {name: github.personal_access_token}
481488

prompts/chrome.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ tools:
3030
- "-n1"
3131
- "-H=Host: localhost:9222"
3232
- '{{endpoint|safe}}'
33+
source:
34+
url: https://github.com/docker/labs-ai-tools-for-devs/tree/main/functions/hub
3335
- name: curl
3436
description: Run a curl command to get the websocket url and make sure that Chrome's websocket server is running. ALWAYS USE THIS TOOL FIRST. MAKE SURE TO USE THE CORRECT HOST HEADER AND ENDPOINT.
3537
parameters:

prompts/examples/mcp-sqlite.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ tools:
4747
- *db
4848
- "SELECT name from sqlite_master WHERE type='table'"
4949
volumes: *mounts
50+
source: *sqlite-source
5051
- name: describe-table
5152
description: Get the schema information for a specific table
5253
parameters:

prompts/mcp/github-official.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
mcp:
3+
- container:
4+
image: mcp/github-mcp-server:latest
5+
secrets:
6+
github.personal_access_token: GITHUB_PERSONAL_ACCESS_TOKEN
7+
source:
8+
url: https://github.com/docker/labs-ai-tools-for-devs/tree/main/functions/github-mcp-server
9+
---
10+

src/docker.clj

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
(ns docker
2+
"run-container runs containers with a few flavors
3+
- run with stdin content
4+
- run a container but don't wait for it to stop
5+
- run in the background but wait for one message on stdout and then stop
6+
- simply run function without stdin
7+
8+
attach-socket - to running container
9+
write-stdin -
10+
read-loop - input: attached socket output: channel messages
11+
write-to-stdin -input: attached socket, string
12+
inject-secret-transform - transform container entrypoint for secrets
13+
14+
run-streaming-function-with-no-stdin - runs continuously
15+
and read stdout to a callback (used in watcher)"
216
(:require
317
[babashka.curl :as curl]
418
[babashka.fs :as fs]
@@ -129,10 +143,6 @@
129143
[(format "%s/%s" (:port container) (:protocol container)) [{:HostPort (:port host)}]])
130144
(into {})))
131145

132-
(comment
133-
(port-bindings ["9222:9222"])
134-
(exposed-ports ["9222:9222"]))
135-
136146
;; check for 201
137147
;; entrypoint is an array of strings
138148
;; env is a map
@@ -290,10 +300,6 @@
290300
image
291301
(str image ":latest"))))
292302

293-
(comment
294-
(add-latest "vonwig/go-linguist")
295-
(add-latest "blah/what:tag"))
296-
297303
(defn -pull [m]
298304
(pull (merge m
299305
{:image (add-latest (:image m))}
@@ -336,12 +342,6 @@
336342
[s])
337343
(string/join " ; ")))
338344

339-
(comment
340-
(injected-entrypoint {:a "A"} ["BLAH=whatever"] "my command")
341-
(injected-entrypoint nil nil "my command")
342-
(injected-entrypoint {:a "A"} nil "my command")
343-
(injected-entrypoint nil nil nil))
344-
345345
(defn inject-secret-transform [container-definition]
346346
(check-then-pull container-definition)
347347
(let [{:keys [Entrypoint Cmd Env]}
@@ -627,12 +627,9 @@
627627
(delete x))
628628
(async/go-loop
629629
[block (async/<! c)]
630-
(logger/info "background socket read loop " block)
631630
(cond
632631
(#{:stopped :timeout} block)
633-
(do
634-
(logger/info "socket read loop " block)
635-
(async/put! output-channel block))
632+
(async/put! output-channel block)
636633
(nil? block)
637634
(async/put! output-channel :closed)
638635
:else
@@ -645,7 +642,10 @@
645642
:write (fn [s] (write-to-stdin socket-channel s)))))
646643

647644
(defn finish-call
648-
"This is a blocking call that waits for the container to finish and then returns the output and exit code."
645+
"Waits (blocking) for call to container to finish, retrieves stdout logs
646+
params
647+
running container
648+
returns ::container-response"
649649
[{:keys [timeout] :or {timeout 10000} :as x}]
650650
;; close stdin socket
651651
(.close ^SocketChannel (:socket x))
@@ -708,7 +708,9 @@
708708
- deletes the container"
709709
[m]
710710
(let [x (docker/function-call-with-stdin
711-
(assoc m :content (or (-> m :stdin :content) (slurp (-> m :stdin :file)))))]
711+
(assoc m :content (or
712+
(-> m :stdin :content)
713+
(slurp (-> m :stdin :file)))))]
712714
(async/<!! (async/thread
713715
(Thread/sleep 10)
714716
(docker/finish-call x)))))
@@ -717,7 +719,7 @@
717719
" params ::container-definition
718720
returns ::container-response"
719721
[m]
720-
;; (schema/validate :schema/container-definition)
722+
;; (schema/validate :schema/tool-container)
721723
(cond
722724
(-> m :stdin)
723725
(run-with-stdin-content m)
@@ -728,19 +730,6 @@
728730
:else
729731
(run-function m)))
730732

731-
(comment
732-
(repl/setup-stdout-logger)
733-
(run-container
734-
{:image "vonwig/gdrive:latest"
735-
:background-callback true
736-
:workdir "/app"
737-
:ports ["3000:3000"]
738-
:volumes ["mcp-gdrive:/gdrive-server"]
739-
:environment {"GDRIVE_CREDENTIALS_PATH" "/gdrive-server/credentials.json"
740-
"GDRIVE_OAUTH_PATH" "/secret/google.gcp-oauth.keys.json"}
741-
:secrets {:google.gcp-oauth.keys.json "GDRIVE"}
742-
:command ["auth"]}))
743-
744733
(defn get-login-info-from-desktop-backend
745734
"returns token or nil if not logged in or backend.sock is not available"
746735
[]

src/jsonrpc/db.clj

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -140,23 +140,3 @@
140140
(vals)
141141
(map (fn [m] (assoc m :type :dynamic)))))
142142

143-
(comment
144-
(repl/setup-stdout-logger)
145-
(println @db*)
146-
(-> @db* :mcp.prompts/registry (get "github-issues"))
147-
(update-prompt {} "github-issues" (slurp "prompts/examples/github_issues.md"))
148-
; in /$HOME/registry.yaml
149-
(git/collect-unique-cache-dirs
150-
(git-cache-refs
151-
(registry-refs prompts.core/registry)))
152-
153-
; prompts will come from prompts-cache
154-
; /prompts or $HOME/.prompts-cache
155-
(git/hashch {:owner "docker" :repo "labs-ai-tools-for-devs" :ref "slim/config"})
156-
(add-refs (registry-refs prompts.core/registry))
157-
(-> @db*
158-
:mcp.prompts/registry
159-
vals
160-
pprint)
161-
(parameter-values "read_file"))
162-

0 commit comments

Comments
 (0)