Skip to content

Commit c5091d3

Browse files
committed
Rename eca_list_directory to eca_directory_tree tool for better overview of project files/dirs.
1 parent 5325e9c commit c5091d3

File tree

6 files changed

+143
-11
lines changed

6 files changed

+143
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ target/
1515
.calva
1616
/*.jar
1717
eca.old
18+
.clojure-mcp/
1819

1920
/.classpath
2021
/.project

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Rename `eca_list_directory` to `eca_directory_tree` tool for better overview of project files/dirs.
6+
57
## 0.15.2
68

79
- Improve `eca_edit_file` tool for better usage from LLM.

src/eca/features/tools/filesystem.clj

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,17 @@
221221
:required ["path"]}
222222
:handler #'read-file}
223223
"eca_write_file"
224-
{:description (str "Create a new file with new content. To edit existing files use eca_edit_file. "
224+
{:description (str "Create a new file or completely overwrite an existing file with new content. "
225+
"This tool will automatically create any necessary parent directories if they don't exist. "
226+
"Use this tool when you want to create a new file from scratch or completely replace "
227+
"the entire content of an existing file. For partial edits or content replacement within "
228+
"existing files, use eca_edit_file instead. "
225229
"**Only works within the directories: $workspaceRoots.**")
226230
:parameters {:type "object"
227231
:properties {"path" {:type "string"
228-
:description "The absolute path to the new file"}
232+
:description "The absolute path to the file to create or overwrite"}
229233
"content" {:type "string"
230-
:description "The content of the new file"}}
234+
:description "The complete content to write to the file"}}
231235
:required ["path" "content"]}
232236
:handler #'write-file}
233237
"eca_edit_file"

test/eca/features/tools/filesystem_test.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
(:import
1212
[java.io ByteArrayInputStream]))
1313

14-
(deftest list-directory-test
14+
(deftest directory-tree-test
1515
(testing "Invalid path"
1616
(is (match?
1717
{:error true
1818
:contents [{:type :text
1919
:text (str (h/file-path "/foo/qux") " is not a valid path")}]}
2020
(with-redefs [fs/canonicalize (constantly (h/file-path "/foo/qux"))
2121
fs/exists? (constantly false)]
22-
((get-in f.tools.filesystem/definitions ["eca_list_directory" :handler])
22+
((get-in f.tools.filesystem/definitions ["eca_directory_tree" :handler])
2323
{"path" (h/file-path "/foo/qux")}
2424
{:db {:workspace-folders [{:uri (h/file-uri "file:///foo/bar/baz") :name "foo"}]}})))))
2525
(testing "Unallowed dir"
@@ -31,7 +31,7 @@
3131
(h/file-path "/foo/bar/baz"))}]}
3232
(with-redefs [fs/canonicalize (constantly (h/file-path "/foo/qux"))
3333
fs/exists? (constantly true)]
34-
((get-in f.tools.filesystem/definitions ["eca_list_directory" :handler])
34+
((get-in f.tools.filesystem/definitions ["eca_directory_tree" :handler])
3535
{"path" (h/file-path "/foo/qux")}
3636
{:db {:workspace-folders [{:uri (h/file-uri "file:///foo/bar/baz") :name "foo"}]}})))))
3737
(testing "allowed dir"
@@ -48,7 +48,7 @@
4848
(fs/path (h/file-path "/foo/bar/baz/qux"))])
4949
fs/directory? (fn [path] (not (string/ends-with? (str path) ".clj")))
5050
fs/canonicalize (constantly (h/file-path "/foo/bar/baz"))]
51-
((get-in f.tools.filesystem/definitions ["eca_list_directory" :handler])
51+
((get-in f.tools.filesystem/definitions ["eca_directory_tree" :handler])
5252
{"path" (h/file-path "/foo/bar/baz")}
5353
{:db {:workspace-folders [{:uri (h/file-uri "file:///foo/bar/baz") :name "foo"}]}}))))))
5454

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
(ns eca.features.tools.mcp-test
2+
(:require
3+
[clojure.test :refer [deftest is testing]]
4+
[eca.features.tools.mcp :as mcp]))
5+
6+
(deftest all-tools-test
7+
(testing "empty db"
8+
(is (= []
9+
(mcp/all-tools {}))))
10+
11+
(testing "db with no mcp-clients"
12+
(is (= []
13+
(mcp/all-tools {:some-other-key "value"}))))
14+
15+
(testing "db with empty mcp-clients"
16+
(is (= []
17+
(mcp/all-tools {:mcp-clients {}}))))
18+
19+
(testing "db with mcp-clients but no tools"
20+
(is (= []
21+
(mcp/all-tools {:mcp-clients {"server1" {}}}))))
22+
23+
(testing "db with single server with tools"
24+
(let [tools [{:name "tool1" :description "desc1"}
25+
{:name "tool2" :description "desc2"}]]
26+
(is (= tools
27+
(mcp/all-tools {:mcp-clients {"server1" {:tools tools}}})))))
28+
29+
(testing "db with multiple servers with tools"
30+
(let [tools1 [{:name "tool1" :description "desc1"}]
31+
tools2 [{:name "tool2" :description "desc2"}
32+
{:name "tool3" :description "desc3"}]]
33+
(is (= (concat tools1 tools2)
34+
(mcp/all-tools {:mcp-clients {"server1" {:tools tools1}
35+
"server2" {:tools tools2}}}))))))
36+
37+
(deftest all-prompts-test
38+
(testing "empty db"
39+
(is (= []
40+
(mcp/all-prompts {}))))
41+
42+
(testing "db with no mcp-clients"
43+
(is (= []
44+
(mcp/all-prompts {:some-other-key "value"}))))
45+
46+
(testing "db with empty mcp-clients"
47+
(is (= []
48+
(mcp/all-prompts {:mcp-clients {}}))))
49+
50+
(testing "db with mcp-clients but no prompts"
51+
(is (= []
52+
(mcp/all-prompts {:mcp-clients {"server1" {}}}))))
53+
54+
(testing "db with single server with prompts"
55+
(let [prompts [{:name "prompt1" :description "desc1"}
56+
{:name "prompt2" :description "desc2"}]
57+
expected (mapv #(assoc % :server "server1") prompts)]
58+
(is (= expected
59+
(mcp/all-prompts {:mcp-clients {"server1" {:prompts prompts}}})))))
60+
61+
(testing "db with multiple servers with prompts"
62+
(let [prompts1 [{:name "prompt1" :description "desc1"}]
63+
prompts2 [{:name "prompt2" :description "desc2"}
64+
{:name "prompt3" :description "desc3"}]
65+
expected (concat
66+
(mapv #(assoc % :server "server1") prompts1)
67+
(mapv #(assoc % :server "server2") prompts2))]
68+
(is (= expected
69+
(mcp/all-prompts {:mcp-clients {"server1" {:prompts prompts1}
70+
"server2" {:prompts prompts2}}}))))))
71+
72+
(deftest all-resources-test
73+
(testing "empty db"
74+
(is (= []
75+
(mcp/all-resources {}))))
76+
77+
(testing "db with no mcp-clients"
78+
(is (= []
79+
(mcp/all-resources {:some-other-key "value"}))))
80+
81+
(testing "db with empty mcp-clients"
82+
(is (= []
83+
(mcp/all-resources {:mcp-clients {}}))))
84+
85+
(testing "db with mcp-clients but no resources"
86+
(is (= []
87+
(mcp/all-resources {:mcp-clients {"server1" {}}}))))
88+
89+
(testing "db with single server with resources"
90+
(let [resources [{:uri "file://test1" :name "resource1"}
91+
{:uri "file://test2" :name "resource2"}]
92+
expected (mapv #(assoc % :server "server1") resources)]
93+
(is (= expected
94+
(mcp/all-resources {:mcp-clients {"server1" {:resources resources}}})))))
95+
96+
(testing "db with multiple servers with resources"
97+
(let [resources1 [{:uri "file://test1" :name "resource1"}]
98+
resources2 [{:uri "file://test2" :name "resource2"}
99+
{:uri "file://test3" :name "resource3"}]
100+
expected (concat
101+
(mapv #(assoc % :server "server1") resources1)
102+
(mapv #(assoc % :server "server2") resources2))]
103+
(is (= expected
104+
(mcp/all-resources {:mcp-clients {"server1" {:resources resources1}
105+
"server2" {:resources resources2}}}))))))
106+
107+
(deftest shutdown!-test
108+
(testing "shutdown with no clients"
109+
(let [db* (atom {})]
110+
(mcp/shutdown! db*)
111+
(is (= {:mcp-clients {}} @db*))))
112+
113+
(testing "shutdown with empty mcp-clients"
114+
(let [db* (atom {:mcp-clients {}})]
115+
(mcp/shutdown! db*)
116+
(is (= {:mcp-clients {}} @db*))))
117+
118+
(testing "shutdown preserves other db data"
119+
(let [db* (atom {:mcp-clients {}
120+
:workspace-folders []
121+
:other-key "value"})]
122+
(mcp/shutdown! db*)
123+
(is (= {:mcp-clients {}
124+
:workspace-folders []
125+
:other-key "value"} @db*)))))

test/eca/features/tools_test.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,22 @@
2323
{}))))
2424
(testing "Include enabled native tools"
2525
(is (match?
26-
(m/embeds [{:name "eca_list_directory"
26+
(m/embeds [{:name "eca_directory_tree"
2727
:description string?
2828
:parameters some?
2929
:origin :native}])
3030
(f.tools/all-tools {} {:nativeTools {:filesystem {:enabled true}}}))))
3131
(testing "Do not include disabled native tools"
3232
(is (match?
33-
(m/embeds [(m/mismatch {:name "eca_list_directory"})])
33+
(m/embeds [(m/mismatch {:name "eca_directory_tree"})])
3434
(f.tools/all-tools {} {:nativeTools {:filesystem {:enabled false}}}))))
3535
(testing "Replace special vars description"
3636
(is (match?
37-
(m/embeds [{:name "eca_list_directory"
37+
(m/embeds [{:name "eca_directory_tree"
3838
:description (format "Only in %s" (h/file-path "/path/to/project/foo"))
3939
:parameters some?
4040
:origin :native}])
41-
(with-redefs [f.tools.filesystem/definitions {"eca_list_directory" {:description "Only in $workspaceRoots"
41+
(with-redefs [f.tools.filesystem/definitions {"eca_directory_tree" {:description "Only in $workspaceRoots"
4242
:parameters {}}}]
4343
(f.tools/all-tools {:workspace-folders [{:name "foo" :uri (h/file-uri "file:///path/to/project/foo")}]}
4444
{:nativeTools {:filesystem {:enabled true}}}))))))

0 commit comments

Comments
 (0)