init MCP server
This commit is contained in:
parent
fff03fa0d5
commit
8ea0eee299
11 changed files with 253 additions and 21 deletions
9
src/cli/config.clj
Normal file
9
src/cli/config.clj
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
(ns cli.config
|
||||
(:require
|
||||
[babashka.fs :as fs]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(def config
|
||||
(let [project-root (str/join "/" (drop-last 3 (fs/components *file*)))
|
||||
config-file-path (format "/%s/config.edn" project-root)]
|
||||
(read-string (slurp config-file-path))))
|
||||
23
src/cli/create.clj
Normal file
23
src/cli/create.clj
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(ns cli.create
|
||||
(:require
|
||||
[com.travisshears.gum-utils :as utils]
|
||||
[clojure.string :as str]
|
||||
[cli.config :refer [config]]
|
||||
[babashka.http-client :as http]
|
||||
[cheshire.core :as json]
|
||||
[babashka.process :refer [shell]]))
|
||||
|
||||
(defn create-snippet [{:keys [title slug markdown tags]}]
|
||||
(http/post (str (:backend-host config) "/api/snippet")
|
||||
{:headers {:content-type "application/json"}
|
||||
:body (json/encode {:title title :slug slug :markdown markdown :tags tags})}))
|
||||
|
||||
(defn run []
|
||||
(let [title (utils/prompt-for "title")
|
||||
slug (utils/prompt-for "slug")
|
||||
tags (utils/prompt-for-many "tags")
|
||||
markdown (utils/prompt-for-long-form "markdown")]
|
||||
(println (format "Created post with title: %s and slug %s" title slug))
|
||||
(println tags)
|
||||
(println markdown)
|
||||
(create-snippet {:title title :slug slug :markdown markdown :tags tags})))
|
||||
18
src/cli/delete.clj
Normal file
18
src/cli/delete.clj
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
(ns cli.delete
|
||||
(:require
|
||||
[com.travisshears.gum-utils :as utils]
|
||||
[cli.config :refer [config]]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[babashka.http-client :as http]
|
||||
[cheshire.core :as json]))
|
||||
|
||||
(defn fetch-snippets []
|
||||
(let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
|
||||
(json/parse-string (:body res) true)))
|
||||
|
||||
(defn delete-snippet [id]
|
||||
(http/delete (str (:backend-host config) "/api/snippet") {:query-params {"id" id}}))
|
||||
|
||||
(defn run []
|
||||
(let [selected-snippet (utils/select (map #(hash-map :value (:slug %) :item %) (fetch-snippets)))]
|
||||
(delete-snippet (:id selected-snippet))))
|
||||
51
src/cli/edit.clj
Normal file
51
src/cli/edit.clj
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
(ns cli.edit
|
||||
(:require
|
||||
[babashka.http-client :as http]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[cli.config :refer [config]]
|
||||
[cli.view :as view]
|
||||
[cheshire.core :as json]
|
||||
[com.travisshears.gum-utils :as utils]))
|
||||
|
||||
(defn fetch-snippets []
|
||||
(let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
|
||||
(json/parse-string (:body res) true)))
|
||||
|
||||
(defn prompt-for-edit-type []
|
||||
(utils/select (map #(hash-map :value (name %) :item %) '(:title
|
||||
:markdown
|
||||
:slug
|
||||
:remove-tag
|
||||
:add-tags
|
||||
:done))))
|
||||
|
||||
(defn send-patch [id patch]
|
||||
(http/patch (str (:backend-host config) "/api/snippet")
|
||||
{:query-params {:id id}
|
||||
:headers {:content-type "application/json"}
|
||||
:body (json/encode patch)}))
|
||||
|
||||
(defn edit
|
||||
([snippet]
|
||||
(edit snippet {}))
|
||||
([snippet changes]
|
||||
(case (prompt-for-edit-type)
|
||||
:title (let [new-title (utils/prompt-for "title" :prefill (:title snippet))]
|
||||
(edit (assoc snippet :title new-title) (assoc changes :title new-title)))
|
||||
:slug (let [new-slug (utils/prompt-for "slug" :prefill (:slug snippet))]
|
||||
(edit (assoc snippet :slug new-slug) (assoc changes :slug new-slug)))
|
||||
:remove-tag (let [tag-to-remove (utils/select (map #(hash-map :value % :item %) (:tags snippet)))
|
||||
tags (remove #(= % tag-to-remove) (:tags snippet))]
|
||||
(edit (assoc snippet :tags tags) (assoc changes :tags tags)))
|
||||
:add-tags (let [new-tags (utils/prompt-for-many "tags")
|
||||
tags (concat new-tags (:tags snippet))]
|
||||
(edit (assoc snippet :tags tags) (assoc changes :tags tags)))
|
||||
:markdown (let [new-markdown (utils/prompt-for-long-form "markdown" :prefill (:markdown snippet))]
|
||||
(edit (assoc snippet :markdown new-markdown) (assoc changes :markdown new-markdown)))
|
||||
:done changes)))
|
||||
|
||||
(defn run []
|
||||
(let [snippet-to-edit (utils/select (map #(hash-map :value (:slug %) :item %) (fetch-snippets)))]
|
||||
(send-patch (:id snippet-to-edit) (edit snippet-to-edit))
|
||||
(println "Snippet updated successfully")
|
||||
(view/view (view/fetch-snippet (:id snippet-to-edit)))))
|
||||
20
src/cli/main.clj
Normal file
20
src/cli/main.clj
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
(ns cli.main
|
||||
(:require
|
||||
[cli.create :as create]
|
||||
[cli.edit :as edit]
|
||||
[cli.delete :as delete]
|
||||
[com.travisshears.gum-utils :as utils]
|
||||
[cli.view :as view]))
|
||||
|
||||
(defn color-test []
|
||||
(doseq [color (range 0 255)]
|
||||
(utils/color-print (str "COLOR --- " color) (str color))))
|
||||
|
||||
(defn -main [& args]
|
||||
(case (first args)
|
||||
"create" (create/run)
|
||||
"delete" (delete/run)
|
||||
"edit" (edit/run)
|
||||
"view" (view/run)
|
||||
"color-test" (color-test)
|
||||
(println "Missing command. Try create, edit, or delete.")))
|
||||
76
src/cli/mcp.clj
Normal file
76
src/cli/mcp.clj
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
(ns cli.mcp
|
||||
(:require
|
||||
[cli.view :as view]
|
||||
[cheshire.core :as json]))
|
||||
|
||||
;; Tool definitions
|
||||
(def available-tools
|
||||
[{:name "list_snippets"
|
||||
:description "List all available code snippets"
|
||||
:inputSchema {:type "object"
|
||||
:properties {}
|
||||
:required []}}])
|
||||
|
||||
;; Tool implementations
|
||||
(defn list-snippets-impl []
|
||||
(try
|
||||
(let [snippets (view/fetch-snippets)]
|
||||
{:success true
|
||||
:snippets (map #(select-keys % [:id :title :slug :tags]) snippets)})
|
||||
(catch Exception e
|
||||
{:success false
|
||||
:error (.getMessage e)})))
|
||||
|
||||
;; Handle tools/list request
|
||||
(defn handle-tools-list [id]
|
||||
{:jsonrpc "2.0"
|
||||
:id id
|
||||
:result {:tools available-tools}})
|
||||
|
||||
;; Handle tools/call request
|
||||
(defn handle-tools-call [id tool-name tool-input]
|
||||
{:jsonrpc "2.0"
|
||||
:id id
|
||||
:result (case tool-name
|
||||
"list_snippets" (list-snippets-impl)
|
||||
{:error (str "Unknown tool: " tool-name)})})
|
||||
|
||||
;; Handle initialize request
|
||||
(defn handle-initialize [id]
|
||||
{:jsonrpc "2.0"
|
||||
:id id
|
||||
:result {:protocolVersion "2024-11-05"
|
||||
:capabilities {:tools {:listChanged true}
|
||||
:resources {:listChanged true}
|
||||
:prompts {:listChanged true}}
|
||||
:serverInfo {:name "snippets-server"
|
||||
:version "1.0.0"}}})
|
||||
|
||||
;; Main request dispatcher
|
||||
(defn handle-request [request]
|
||||
(let [method (:method request)
|
||||
id (:id request)
|
||||
params (:params request)]
|
||||
(case method
|
||||
"initialize" (handle-initialize id)
|
||||
"tools/list" (handle-tools-list id)
|
||||
"tools/call" (handle-tools-call id (:name params) (:arguments params))
|
||||
{:jsonrpc "2.0"
|
||||
:id id
|
||||
:error {:code -32601
|
||||
:message (str "Method not found: " method)}})))
|
||||
|
||||
(defn -main [& args]
|
||||
;; Read JSON-RPC requests from stdin and process them
|
||||
(loop []
|
||||
(let [line (try (read-line) (catch Exception _))]
|
||||
(when line
|
||||
(try
|
||||
(let [request (json/parse-string line true)
|
||||
response (handle-request request)]
|
||||
(println (json/encode response)))
|
||||
(catch Exception e
|
||||
(println (json/encode {:jsonrpc "2.0"
|
||||
:error {:code -32700
|
||||
:message "Parse error"}}))))
|
||||
(recur)))))
|
||||
27
src/cli/view.clj
Normal file
27
src/cli/view.clj
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
(ns cli.view
|
||||
(:require
|
||||
[babashka.http-client :as http]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[cli.config :refer [config]]
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[com.travisshears.gum-utils :as utils]))
|
||||
|
||||
(defn fetch-snippets []
|
||||
(let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
|
||||
(json/parse-string (:body res) true)))
|
||||
|
||||
(defn fetch-snippet [id]
|
||||
(let [res (http/get (str (:backend-host config) "/api/snippet") {:query-params {"id" id}})]
|
||||
(json/parse-string (:body res) true)))
|
||||
|
||||
(defn view [snippet]
|
||||
(utils/color-print (str "title: " (:title snippet)) "4")
|
||||
(utils/color-print (str "slug: " (:slug snippet)) "4")
|
||||
(utils/color-print (str "tags: " (str/join ", " (:tags snippet))) "4")
|
||||
(utils/color-print "markdown: " "4")
|
||||
(utils/print-markdown (:markdown snippet)))
|
||||
|
||||
(defn run []
|
||||
(let [snippet-to-view (utils/select (map #(hash-map :value (:slug %) :item %) (fetch-snippets)))]
|
||||
(view (fetch-snippet (:id snippet-to-view)))))
|
||||
Loading…
Add table
Add a link
Reference in a new issue