scrybe-cli 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/Cargo.lock +24 -21
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/Cargo.toml +15 -9
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/PKG-INFO +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/pyproject.toml +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/Cargo.toml +1 -1
- scrybe_cli-0.4.0/scrybe-cli/src/rpc_client.rs +27 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/Cargo.toml +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/Cargo.toml +7 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/pyproject.toml +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/src/server.rs +49 -10
- scrybe_cli-0.4.0/scrybe-mcp-server/src/tools.rs +1234 -0
- scrybe_cli-0.4.0/scrybe-mcp-server/tests/docx_packaging.rs +76 -0
- scrybe_cli-0.4.0/scrybe-mcp-server/tests/live_app_open.rs +86 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/Cargo.toml +2 -2
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/pyproject.toml +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/Cargo.toml +1 -1
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-rpc/Cargo.toml +1 -1
- scrybe_cli-0.2.0/scrybe-cli/src/rpc_client.rs → scrybe_cli-0.4.0/scrybe-rpc/src/client.rs +38 -13
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-rpc/src/lib.rs +4 -0
- scrybe_cli-0.2.0/scrybe-mcp-server/src/tools.rs +0 -703
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/python/scrybe_cli/__init__.py +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/python/scrybe_cli/py.typed +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/src/lib.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/src/lint.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/src/main.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/src/wrap.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-cli/tests/rpc_socket.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/ast.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/change.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/content.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/document.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/error.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/lib.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/plugin.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-core/src/workspace.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/python/scrybe_mcp_server/__init__.py +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/python/scrybe_mcp_server/py.typed +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/src/lib.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mcp-server/src/main.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/python/scrybe_mermaid/__init__.py +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/python/scrybe_mermaid/py.typed +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/src/codec.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/src/error.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/src/lib.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-mermaid/tests/test_python_quickstart.py +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/README.md +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/html.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/lib.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/math.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/mermaid.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/theme.rs +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/themes/dark.css +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/themes/default.css +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-render/src/themes/solarized.css +0 -0
- {scrybe_cli-0.2.0 → scrybe_cli-0.4.0}/scrybe-rpc/README.md +0 -0
|
@@ -3169,9 +3169,9 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
|
|
3169
3169
|
|
|
3170
3170
|
[[package]]
|
|
3171
3171
|
name = "pyo3"
|
|
3172
|
-
version = "0.
|
|
3172
|
+
version = "0.29.0"
|
|
3173
3173
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3174
|
-
checksum = "
|
|
3174
|
+
checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
|
|
3175
3175
|
dependencies = [
|
|
3176
3176
|
"libc",
|
|
3177
3177
|
"once_cell",
|
|
@@ -3183,18 +3183,18 @@ dependencies = [
|
|
|
3183
3183
|
|
|
3184
3184
|
[[package]]
|
|
3185
3185
|
name = "pyo3-build-config"
|
|
3186
|
-
version = "0.
|
|
3186
|
+
version = "0.29.0"
|
|
3187
3187
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3188
|
-
checksum = "
|
|
3188
|
+
checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
|
|
3189
3189
|
dependencies = [
|
|
3190
3190
|
"target-lexicon 0.13.5",
|
|
3191
3191
|
]
|
|
3192
3192
|
|
|
3193
3193
|
[[package]]
|
|
3194
3194
|
name = "pyo3-ffi"
|
|
3195
|
-
version = "0.
|
|
3195
|
+
version = "0.29.0"
|
|
3196
3196
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3197
|
-
checksum = "
|
|
3197
|
+
checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
|
|
3198
3198
|
dependencies = [
|
|
3199
3199
|
"libc",
|
|
3200
3200
|
"pyo3-build-config",
|
|
@@ -3202,9 +3202,9 @@ dependencies = [
|
|
|
3202
3202
|
|
|
3203
3203
|
[[package]]
|
|
3204
3204
|
name = "pyo3-macros"
|
|
3205
|
-
version = "0.
|
|
3205
|
+
version = "0.29.0"
|
|
3206
3206
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3207
|
-
checksum = "
|
|
3207
|
+
checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
|
|
3208
3208
|
dependencies = [
|
|
3209
3209
|
"proc-macro2",
|
|
3210
3210
|
"pyo3-macros-backend",
|
|
@@ -3214,13 +3214,12 @@ dependencies = [
|
|
|
3214
3214
|
|
|
3215
3215
|
[[package]]
|
|
3216
3216
|
name = "pyo3-macros-backend"
|
|
3217
|
-
version = "0.
|
|
3217
|
+
version = "0.29.0"
|
|
3218
3218
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3219
|
-
checksum = "
|
|
3219
|
+
checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
|
|
3220
3220
|
dependencies = [
|
|
3221
3221
|
"heck 0.5.0",
|
|
3222
3222
|
"proc-macro2",
|
|
3223
|
-
"pyo3-build-config",
|
|
3224
3223
|
"quote",
|
|
3225
3224
|
"syn 2.0.117",
|
|
3226
3225
|
]
|
|
@@ -3525,7 +3524,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
3525
3524
|
|
|
3526
3525
|
[[package]]
|
|
3527
3526
|
name = "scrybe-app"
|
|
3528
|
-
version = "0.
|
|
3527
|
+
version = "0.4.0"
|
|
3529
3528
|
dependencies = [
|
|
3530
3529
|
"anyhow",
|
|
3531
3530
|
"dirs 5.0.1",
|
|
@@ -3543,6 +3542,7 @@ dependencies = [
|
|
|
3543
3542
|
"tauri-plugin-dialog",
|
|
3544
3543
|
"tauri-plugin-shell",
|
|
3545
3544
|
"tauri-plugin-single-instance",
|
|
3545
|
+
"tempfile",
|
|
3546
3546
|
"thiserror 2.0.18",
|
|
3547
3547
|
"tokio",
|
|
3548
3548
|
"tracing",
|
|
@@ -3551,7 +3551,7 @@ dependencies = [
|
|
|
3551
3551
|
|
|
3552
3552
|
[[package]]
|
|
3553
3553
|
name = "scrybe-cli"
|
|
3554
|
-
version = "0.
|
|
3554
|
+
version = "0.4.0"
|
|
3555
3555
|
dependencies = [
|
|
3556
3556
|
"anyhow",
|
|
3557
3557
|
"clap",
|
|
@@ -3570,7 +3570,7 @@ dependencies = [
|
|
|
3570
3570
|
|
|
3571
3571
|
[[package]]
|
|
3572
3572
|
name = "scrybe-core"
|
|
3573
|
-
version = "0.
|
|
3573
|
+
version = "0.4.0"
|
|
3574
3574
|
dependencies = [
|
|
3575
3575
|
"anyhow",
|
|
3576
3576
|
"blake3",
|
|
@@ -3587,7 +3587,7 @@ dependencies = [
|
|
|
3587
3587
|
|
|
3588
3588
|
[[package]]
|
|
3589
3589
|
name = "scrybe-mcp-client"
|
|
3590
|
-
version = "0.
|
|
3590
|
+
version = "0.4.0"
|
|
3591
3591
|
dependencies = [
|
|
3592
3592
|
"anyhow",
|
|
3593
3593
|
"dirs 5.0.1",
|
|
@@ -3602,24 +3602,27 @@ dependencies = [
|
|
|
3602
3602
|
|
|
3603
3603
|
[[package]]
|
|
3604
3604
|
name = "scrybe-mcp-server"
|
|
3605
|
-
version = "0.
|
|
3605
|
+
version = "0.4.0"
|
|
3606
3606
|
dependencies = [
|
|
3607
3607
|
"anyhow",
|
|
3608
3608
|
"clap",
|
|
3609
3609
|
"scrybe-core",
|
|
3610
3610
|
"scrybe-mermaid",
|
|
3611
3611
|
"scrybe-render",
|
|
3612
|
+
"scrybe-rpc",
|
|
3612
3613
|
"serde",
|
|
3613
3614
|
"serde_json",
|
|
3615
|
+
"tempfile",
|
|
3614
3616
|
"thiserror 2.0.18",
|
|
3615
3617
|
"tokio",
|
|
3616
3618
|
"tracing",
|
|
3617
3619
|
"tracing-subscriber",
|
|
3620
|
+
"which",
|
|
3618
3621
|
]
|
|
3619
3622
|
|
|
3620
3623
|
[[package]]
|
|
3621
3624
|
name = "scrybe-mermaid"
|
|
3622
|
-
version = "0.
|
|
3625
|
+
version = "0.4.0"
|
|
3623
3626
|
dependencies = [
|
|
3624
3627
|
"anyhow",
|
|
3625
3628
|
"base64 0.22.1",
|
|
@@ -3635,7 +3638,7 @@ dependencies = [
|
|
|
3635
3638
|
|
|
3636
3639
|
[[package]]
|
|
3637
3640
|
name = "scrybe-py"
|
|
3638
|
-
version = "0.
|
|
3641
|
+
version = "0.4.0"
|
|
3639
3642
|
dependencies = [
|
|
3640
3643
|
"anyhow",
|
|
3641
3644
|
"pyo3",
|
|
@@ -3649,7 +3652,7 @@ dependencies = [
|
|
|
3649
3652
|
|
|
3650
3653
|
[[package]]
|
|
3651
3654
|
name = "scrybe-render"
|
|
3652
|
-
version = "0.
|
|
3655
|
+
version = "0.4.0"
|
|
3653
3656
|
dependencies = [
|
|
3654
3657
|
"anyhow",
|
|
3655
3658
|
"pulldown-cmark",
|
|
@@ -3662,7 +3665,7 @@ dependencies = [
|
|
|
3662
3665
|
|
|
3663
3666
|
[[package]]
|
|
3664
3667
|
name = "scrybe-rpc"
|
|
3665
|
-
version = "0.
|
|
3668
|
+
version = "0.4.0"
|
|
3666
3669
|
dependencies = [
|
|
3667
3670
|
"serde",
|
|
3668
3671
|
"serde_json",
|
|
@@ -3671,7 +3674,7 @@ dependencies = [
|
|
|
3671
3674
|
|
|
3672
3675
|
[[package]]
|
|
3673
3676
|
name = "scrybe-vcs"
|
|
3674
|
-
version = "0.
|
|
3677
|
+
version = "0.4.0"
|
|
3675
3678
|
dependencies = [
|
|
3676
3679
|
"anyhow",
|
|
3677
3680
|
"chrono",
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
resolver = "2"
|
|
3
3
|
members = ["scrybe-core", "scrybe-render", "scrybe-mcp-server", "scrybe-mermaid", "scrybe-cli", "scrybe-rpc"]
|
|
4
4
|
|
|
5
|
+
# Shared package metadata. Every member inherits the version via
|
|
6
|
+
# `version.workspace = true`, so a release bumps all crates in lock-step
|
|
7
|
+
# from one place. (See RELEASE.md; issue #128.)
|
|
8
|
+
[workspace.package]
|
|
9
|
+
version = "0.4.0"
|
|
10
|
+
|
|
5
11
|
# Workspace-level dependency pins keep all crates in lock-step.
|
|
6
12
|
[workspace.dependencies]
|
|
7
13
|
# Core utilities
|
|
@@ -43,7 +49,7 @@ png = "0.17"
|
|
|
43
49
|
base64 = "0.22"
|
|
44
50
|
|
|
45
51
|
# PyO3
|
|
46
|
-
pyo3 = { version = "0.
|
|
52
|
+
pyo3 = { version = "0.29", features = ["auto-initialize"] }
|
|
47
53
|
|
|
48
54
|
# Tauri 2
|
|
49
55
|
tauri = { version = "2", features = ["protocol-asset"] }
|
|
@@ -52,14 +58,14 @@ tauri-build = { version = "2", features = [] }
|
|
|
52
58
|
# Internal crates — version pinned (=) so cargo publish accepts the
|
|
53
59
|
# tarballs (path-deps without versions are rejected at publish time).
|
|
54
60
|
# Workspace lock-step: every release bumps all members together.
|
|
55
|
-
scrybe-core = { path = "scrybe-core", version = "=0.
|
|
56
|
-
scrybe-render = { path = "scrybe-render", version = "=0.
|
|
57
|
-
scrybe-mcp-client = { path = "scrybe-mcp-client", version = "=0.
|
|
58
|
-
scrybe-mcp-server = { path = "scrybe-mcp-server", version = "=0.
|
|
59
|
-
scrybe-mermaid = { path = "scrybe-mermaid", version = "=0.
|
|
60
|
-
scrybe-vcs = { path = "scrybe-vcs", version = "=0.
|
|
61
|
-
scrybe-py = { path = "scrybe-py", version = "=0.
|
|
62
|
-
scrybe-rpc = { path = "scrybe-rpc", version = "=0.
|
|
61
|
+
scrybe-core = { path = "scrybe-core", version = "=0.4.0" }
|
|
62
|
+
scrybe-render = { path = "scrybe-render", version = "=0.4.0" }
|
|
63
|
+
scrybe-mcp-client = { path = "scrybe-mcp-client", version = "=0.4.0" }
|
|
64
|
+
scrybe-mcp-server = { path = "scrybe-mcp-server", version = "=0.4.0" }
|
|
65
|
+
scrybe-mermaid = { path = "scrybe-mermaid", version = "=0.4.0" }
|
|
66
|
+
scrybe-vcs = { path = "scrybe-vcs", version = "=0.4.0" }
|
|
67
|
+
scrybe-py = { path = "scrybe-py", version = "=0.4.0" }
|
|
68
|
+
scrybe-rpc = { path = "scrybe-rpc", version = "=0.4.0" }
|
|
63
69
|
|
|
64
70
|
[workspace.lints.clippy]
|
|
65
71
|
explicit_iter_loop = "warn"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//! Thin JSON-RPC client to talk to the running Scrybe GUI.
|
|
2
|
+
//!
|
|
3
|
+
//! The implementation now lives in [`scrybe_rpc::client`] so the CLI and the
|
|
4
|
+
//! MCP server dial the live app through **one** shared dialer (two divergent
|
|
5
|
+
//! clients is exactly the split `scrybe-rpc` exists to prevent). This module
|
|
6
|
+
//! re-exports it to keep the existing `rpc_client::*` call sites unchanged.
|
|
7
|
+
|
|
8
|
+
pub use scrybe_rpc::client::{is_live, send, send_to, socket_path, try_connect, try_connect_at};
|
|
9
|
+
|
|
10
|
+
#[cfg(test)]
|
|
11
|
+
mod tests {
|
|
12
|
+
use super::*;
|
|
13
|
+
|
|
14
|
+
#[test]
|
|
15
|
+
fn socket_path_reexported() {
|
|
16
|
+
// The re-export links and resolves to the shared implementation.
|
|
17
|
+
assert!(!socket_path().as_os_str().is_empty());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[cfg(unix)]
|
|
21
|
+
#[test]
|
|
22
|
+
fn send_to_errors_when_no_server() {
|
|
23
|
+
let path = std::path::PathBuf::from("/tmp/scrybe-nonexistent-sock-cli-reexport-test");
|
|
24
|
+
let err = send_to(&path, "open", serde_json::json!({"path": "/tmp/foo.md"})).unwrap_err();
|
|
25
|
+
assert!(err.contains("no Scrybe running"));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "scrybe-mcp-server"
|
|
3
|
-
version =
|
|
3
|
+
version.workspace = true
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Scrybe MCP server — inbound MCP tools: open/read/section/edit/diff/find/embed/lint"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -18,6 +18,7 @@ path = "src/main.rs"
|
|
|
18
18
|
scrybe-core.workspace = true
|
|
19
19
|
scrybe-render.workspace = true
|
|
20
20
|
scrybe-mermaid.workspace = true
|
|
21
|
+
scrybe-rpc.workspace = true
|
|
21
22
|
anyhow.workspace = true
|
|
22
23
|
thiserror.workspace = true
|
|
23
24
|
serde.workspace = true
|
|
@@ -26,6 +27,11 @@ tracing.workspace = true
|
|
|
26
27
|
tracing-subscriber.workspace = true
|
|
27
28
|
tokio.workspace = true
|
|
28
29
|
clap.workspace = true
|
|
30
|
+
which.workspace = true
|
|
31
|
+
|
|
32
|
+
[dev-dependencies]
|
|
33
|
+
tempfile = "3"
|
|
34
|
+
serde_json.workspace = true
|
|
29
35
|
|
|
30
36
|
[lints]
|
|
31
37
|
workspace = true
|
|
@@ -89,16 +89,29 @@ impl McpServer {
|
|
|
89
89
|
let name = params["name"].as_str()?;
|
|
90
90
|
let args = params.get("arguments").unwrap_or(&Value::Null);
|
|
91
91
|
let content = self.registry.call_tool(name, args);
|
|
92
|
+
// A tool result carrying an `error` field is a failed call; set
|
|
93
|
+
// `isError` so agents can tell success from failure structurally
|
|
94
|
+
// instead of parsing the text payload.
|
|
95
|
+
let is_error = content.get("error").is_some();
|
|
92
96
|
serde_json::json!({
|
|
93
|
-
"content": [{"type": "text", "text": content.to_string()}]
|
|
97
|
+
"content": [{"type": "text", "text": content.to_string()}],
|
|
98
|
+
"isError": is_error,
|
|
94
99
|
})
|
|
95
100
|
}
|
|
96
|
-
other =>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
other => {
|
|
102
|
+
// Unknown method → a real top-level JSON-RPC error object,
|
|
103
|
+
// sibling to `id` (never nested under `result`).
|
|
104
|
+
return id.map(|i| {
|
|
105
|
+
serde_json::json!({
|
|
106
|
+
"jsonrpc": "2.0",
|
|
107
|
+
"id": i,
|
|
108
|
+
"error": {
|
|
109
|
+
"code": -32601,
|
|
110
|
+
"message": format!("method not found: {other}")
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
}
|
|
102
115
|
};
|
|
103
116
|
|
|
104
117
|
id.map(|i| {
|
|
@@ -207,16 +220,42 @@ mod tests {
|
|
|
207
220
|
}
|
|
208
221
|
|
|
209
222
|
#[test]
|
|
210
|
-
fn
|
|
223
|
+
fn test_unknown_method_returns_top_level_error() {
|
|
211
224
|
let mut s = server();
|
|
212
225
|
let req = json!({"jsonrpc": "2.0", "id": 7, "method": "nonexistent"});
|
|
213
226
|
let resp = s.handle(&req).unwrap();
|
|
227
|
+
// JSON-RPC error MUST be top-level, not nested under `result`.
|
|
228
|
+
assert_eq!(resp["error"]["code"], -32601);
|
|
214
229
|
assert!(
|
|
215
|
-
resp
|
|
216
|
-
"
|
|
230
|
+
resp.get("result").is_none(),
|
|
231
|
+
"error response must not carry a result: {resp}"
|
|
217
232
|
);
|
|
218
233
|
}
|
|
219
234
|
|
|
235
|
+
#[test]
|
|
236
|
+
fn test_tools_call_failure_sets_is_error() {
|
|
237
|
+
// `read` with an unknown id returns an error payload → isError: true.
|
|
238
|
+
let mut s = server();
|
|
239
|
+
let req = json!({
|
|
240
|
+
"jsonrpc": "2.0", "id": 9, "method": "tools/call",
|
|
241
|
+
"params": {"name": "read", "arguments": {"id": "bogus-id"}}
|
|
242
|
+
});
|
|
243
|
+
let resp = s.handle(&req).unwrap();
|
|
244
|
+
assert_eq!(resp["result"]["isError"], true);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#[test]
|
|
248
|
+
fn test_tools_call_success_is_not_error() {
|
|
249
|
+
// A successful render carries no error field → isError: false.
|
|
250
|
+
let mut s = server();
|
|
251
|
+
let req = json!({
|
|
252
|
+
"jsonrpc": "2.0", "id": 10, "method": "tools/call",
|
|
253
|
+
"params": {"name": "render", "arguments": {"source": "# Hi"}}
|
|
254
|
+
});
|
|
255
|
+
let resp = s.handle(&req).unwrap();
|
|
256
|
+
assert_eq!(resp["result"]["isError"], false);
|
|
257
|
+
}
|
|
258
|
+
|
|
220
259
|
#[test]
|
|
221
260
|
fn test_jsonrpc_version_in_response() {
|
|
222
261
|
let mut s = server();
|