Add MCP server to AST tool
Integrates the MCP server functionality into the AST tool binary. This allows the tool to act as a server for LLM integration, enabling communication over stdio. The server can list available bindings and execute scripts.
This commit is contained in:
Generated
+235
@@ -468,6 +468,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@@ -660,6 +666,7 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
@@ -849,6 +856,40 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
|
||||
dependencies = [
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@@ -906,6 +947,12 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "ecolor"
|
||||
version = "0.33.3"
|
||||
@@ -1236,12 +1283,48 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.32"
|
||||
@@ -1272,6 +1355,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
@@ -1284,9 +1373,13 @@ version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
@@ -1631,6 +1724,12 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.1.0"
|
||||
@@ -1918,6 +2017,9 @@ dependencies = [
|
||||
"fastrand",
|
||||
"insta",
|
||||
"regex",
|
||||
"rmcp",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2379,6 +2481,12 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pastey"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
@@ -2598,6 +2706,26 @@ dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
@@ -2633,6 +2761,41 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "rmcp"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba6b9d2f0efe2258b23767f1f9e0054cfbcac9c2d6f81a031214143096d7864f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64",
|
||||
"chrono",
|
||||
"futures",
|
||||
"pastey",
|
||||
"pin-project-lite",
|
||||
"rmcp-macros",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmcp-macros"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9d95d7ed26ad8306352b0d5f05b593222b272790564589790d210aa15caa9e"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -2686,6 +2849,32 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dyn-clone",
|
||||
"ref-cast",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
@@ -2747,6 +2936,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
@@ -3058,6 +3258,41 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
|
||||
@@ -10,6 +10,9 @@ clap = { version = "4.5", features = ["derive"] }
|
||||
chrono = "0.4"
|
||||
regex = "1.10"
|
||||
fastrand = "2.3"
|
||||
rmcp = { version = "1.2", features = ["server", "transport-io"] }
|
||||
tokio = { version = "1", features = ["rt", "io-std", "macros"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.39", features = ["yaml"] }
|
||||
|
||||
+122
-2
@@ -147,11 +147,11 @@ The Myc runtime environment provides a collection of built-in functions and macr
|
||||
(do
|
||||
;; Create a series with a typed layout (Struct-of-Arrays under the hood)
|
||||
(def my_ticks (series {:price :float :volume :int :msg :text}))
|
||||
|
||||
|
||||
(push my_ticks {:price 10.5 :volume 100 :msg "A"})
|
||||
(push my_ticks {:price 11.2 :volume 200 :msg "B"})
|
||||
(push my_ticks {:price 15.5 :volume 300 :msg "C"})
|
||||
|
||||
|
||||
;; Extract the price series specifically
|
||||
(def prices (.price my_ticks))
|
||||
|
||||
@@ -159,3 +159,123 @@ The Myc runtime environment provides a collection of built-in functions and macr
|
||||
(+ (prices 0) (prices 1)) ;; Output: 26.7
|
||||
)
|
||||
```
|
||||
|
||||
## 8. Common Mistakes & Pitfalls
|
||||
|
||||
This section is especially relevant for LLMs generating Myc code.
|
||||
|
||||
### Wrong keywords from other Lisps
|
||||
|
||||
| Wrong (Clojure/Scheme) | Correct Myc |
|
||||
|---|---|
|
||||
| `(let [x 1] ...)` | `(do (def x 1) ...)` |
|
||||
| `(begin ...)` | `(do ...)` |
|
||||
| `(lambda [x] ...)` | `(fn [x] ...)` |
|
||||
| `(define x 1)` | `(def x 1)` |
|
||||
| `(set! x 2)` | `(assign x 2)` |
|
||||
| `(cond ...)` | nested `(if ...)` |
|
||||
| `(not= a b)` | `(<> a b)` |
|
||||
|
||||
### Series indexing is reversed
|
||||
|
||||
Index `0` is the **most recently pushed** item, not the oldest. This is the opposite of normal array indexing:
|
||||
|
||||
```clojure
|
||||
(push s {:v 1})
|
||||
(push s {:v 2})
|
||||
(push s {:v 3})
|
||||
;; ((.v s) 0) => 3 (newest)
|
||||
;; ((.v s) 1) => 2
|
||||
;; ((.v s) 2) => 1 (oldest)
|
||||
```
|
||||
|
||||
### Record keys must be keywords, not strings
|
||||
|
||||
```clojure
|
||||
;; WRONG:
|
||||
{"price" 10.5}
|
||||
|
||||
;; CORRECT:
|
||||
{:price 10.5}
|
||||
```
|
||||
|
||||
### `again` is only valid inside `fn`
|
||||
|
||||
`(again ...)` jumps back to the enclosing `fn`. Using it outside a function is a compile error.
|
||||
|
||||
```clojure
|
||||
;; WRONG — top-level again:
|
||||
(again 1 2)
|
||||
|
||||
;; CORRECT — inside fn:
|
||||
(fn [n] (if (= n 0) "done" (again (- n 1))))
|
||||
```
|
||||
|
||||
### `check_syntax` accepts only a single expression
|
||||
|
||||
The `check_syntax` tool uses the single-expression compiler pass. Wrap multiple expressions in `(do ...)`:
|
||||
|
||||
```clojure
|
||||
;; WRONG:
|
||||
(def x 1) (+ x 2)
|
||||
|
||||
;; CORRECT:
|
||||
(do (def x 1) (+ x 2))
|
||||
```
|
||||
|
||||
### Field accessors are functions, not property syntax
|
||||
|
||||
```clojure
|
||||
;; WRONG — not valid syntax:
|
||||
user.name
|
||||
|
||||
;; CORRECT — field accessor called as a function:
|
||||
(.name user)
|
||||
|
||||
;; Also correct — extract accessor first, then call:
|
||||
(def get-name .name)
|
||||
(get-name user)
|
||||
```
|
||||
|
||||
**Recursive Function with Tail-Call Optimization:**
|
||||
```clojure
|
||||
(do
|
||||
;; Factorial using explicit TCO via (again ...) — like Clojure's recur
|
||||
(def factorial
|
||||
(fn [n acc]
|
||||
(if (= n 0)
|
||||
acc
|
||||
(again (- n 1) (* acc n)))))
|
||||
|
||||
(factorial 10 1) ;; Output: 3628800
|
||||
)
|
||||
```
|
||||
|
||||
**Macro Definition:**
|
||||
```clojure
|
||||
(do
|
||||
;; Define a macro that inverts a condition
|
||||
(macro unless [c body]
|
||||
`(if ~c ... ~body))
|
||||
|
||||
(unless false "executed") ;; Output: "executed"
|
||||
)
|
||||
```
|
||||
|
||||
**Series with while Loop:**
|
||||
```clojure
|
||||
(do
|
||||
(def ticks (series {:price :float}))
|
||||
(def i 0)
|
||||
|
||||
;; Push 5 prices into the series
|
||||
(while (< i 5)
|
||||
(do
|
||||
(push ticks {:price (* i 1.5)})
|
||||
(assign i (+ i 1))))
|
||||
|
||||
;; Read back the two most recent prices
|
||||
(def p (.price ticks))
|
||||
(+ (p 0) (p 1)) ;; newest + second-newest
|
||||
)
|
||||
```
|
||||
|
||||
@@ -600,6 +600,19 @@ impl Environment {
|
||||
}
|
||||
|
||||
|
||||
/// Returns the names of all bindings registered in the fixed RTL scope.
|
||||
/// Useful for introspection (e.g., MCP server listing available built-ins).
|
||||
pub fn list_bindings(&self) -> Vec<String> {
|
||||
let root_scopes = self.root_scopes.borrow();
|
||||
let mut names: Vec<String> = root_scopes[0]
|
||||
.locals
|
||||
.keys()
|
||||
.map(|sym| sym.name.to_string())
|
||||
.collect();
|
||||
names.sort();
|
||||
names
|
||||
}
|
||||
|
||||
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
||||
self.preload_dependencies(source, None)?;
|
||||
let compiled = self.compile(source).into_result()?;
|
||||
|
||||
@@ -3,6 +3,7 @@ pub mod compiler;
|
||||
pub mod diagnostics;
|
||||
pub mod environment;
|
||||
pub mod lexer;
|
||||
pub mod mcp_server;
|
||||
pub mod nodes;
|
||||
pub mod parser;
|
||||
pub mod rtl;
|
||||
|
||||
@@ -39,10 +39,22 @@ struct Cli {
|
||||
/// Disable optimization
|
||||
#[arg(long)]
|
||||
no_opt: bool,
|
||||
|
||||
/// Start MCP server (stdio transport, for LLM integration)
|
||||
#[arg(long)]
|
||||
mcp: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
if cli.mcp {
|
||||
if let Err(e) = myc::ast::mcp_server::run() {
|
||||
eprintln!("MCP server error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let mut env = Environment::new();
|
||||
env.optimization = !cli.no_opt;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user