diff --git a/crates/op-mcp/Cargo.toml b/crates/op-mcp/Cargo.toml new file mode 100644 index 000000000..29cb45c00 --- /dev/null +++ b/crates/op-mcp/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "op-mcp" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +description = "OpenPencil MCP server — JSON-RPC tool registry over op-editor-core EditorState / EditorCommand" + +[lib] +name = "op_mcp" +path = "src/lib.rs" + +[dependencies] +jian-ops-schema = { path = "../../vendor/jian/crates/jian-ops-schema" } +op-editor-core = { path = "../op-editor-core" } diff --git a/crates/openpencil-shell-core/src/mcp/batch_design.rs b/crates/op-mcp/src/batch_design.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/batch_design.rs rename to crates/op-mcp/src/batch_design.rs diff --git a/crates/openpencil-shell-core/src/mcp/batch_design_tests.rs b/crates/op-mcp/src/batch_design_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/batch_design_tests.rs rename to crates/op-mcp/src/batch_design_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/component_tools.rs b/crates/op-mcp/src/component_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/component_tools.rs rename to crates/op-mcp/src/component_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/component_tools_tests.rs b/crates/op-mcp/src/component_tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/component_tools_tests.rs rename to crates/op-mcp/src/component_tools_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/copy_node_tests.rs b/crates/op-mcp/src/copy_node_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/copy_node_tests.rs rename to crates/op-mcp/src/copy_node_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/extra_read_tools.rs b/crates/op-mcp/src/extra_read_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/extra_read_tools.rs rename to crates/op-mcp/src/extra_read_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/extra_read_tools_tests.rs b/crates/op-mcp/src/extra_read_tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/extra_read_tools_tests.rs rename to crates/op-mcp/src/extra_read_tools_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/json_serializer.rs b/crates/op-mcp/src/json_serializer.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/json_serializer.rs rename to crates/op-mcp/src/json_serializer.rs diff --git a/crates/openpencil-shell-core/src/mcp.rs b/crates/op-mcp/src/lib.rs similarity index 98% rename from crates/openpencil-shell-core/src/mcp.rs rename to crates/op-mcp/src/lib.rs index 8aa498b4f..a7bde75f3 100644 --- a/crates/openpencil-shell-core/src/mcp.rs +++ b/crates/op-mcp/src/lib.rs @@ -8,10 +8,7 @@ //! `op_editor_core::EditorState` / `op_editor_core::EditorCommand`. //! Read tools now snapshot an `EditorState` (canonical `PenDocument`); //! write tools emit an `op_editor_core::EditorCommand` the host applies -//! via `EditorState::apply`. The module physically still lives inside -//! `openpencil-shell-core` — an `op-mcp` crate extraction is a later -//! Phase-7 task. shell-core's own `Document` (used by the widgets) is -//! untouched. +//! via `EditorState::apply`. //! //! ## Component-command gap //! @@ -47,6 +44,9 @@ pub mod selected_ops_tools; #[cfg(test)] mod replace_node_tests; #[cfg(test)] mod batch_design_tests; #[cfg(test)] mod scalar_vars_tests; +// Cross-cutting tests for the crate spine — stdio dispatch + parser +// invariants + a few read-tool registry round-trips. +#[cfg(test)] mod mcp_tests; // The MCP command DTO is now `op_editor_core::EditorCommand` — the // faithful port of the old shell-core `McpCommand`. Re-exported here diff --git a/crates/openpencil-shell-core/src/mcp_tests.rs b/crates/op-mcp/src/mcp_tests.rs similarity index 98% rename from crates/openpencil-shell-core/src/mcp_tests.rs rename to crates/op-mcp/src/mcp_tests.rs index 49a9278a3..d43f54848 100644 --- a/crates/openpencil-shell-core/src/mcp_tests.rs +++ b/crates/op-mcp/src/mcp_tests.rs @@ -4,8 +4,8 @@ //! Ported off the old shell-core `Document` onto `op_editor_core:: //! EditorState`. -use super::mcp::test_fixtures::{add_variable, sample, state_with}; -use super::mcp::*; +use crate::test_fixtures::{add_variable, sample, state_with}; +use crate::*; use jian_ops_schema::variable::{VariableKind, VariableScalar}; use std::collections::BTreeMap; @@ -280,10 +280,10 @@ fn json_escape_handles_special_chars() { #[test] fn get_document_info_reports_snapshot_via_registry() { - use super::mcp::test_fixtures::frame; + use crate::test_fixtures::frame; let f = frame("n10", "F", 0.0, 0.0, 200.0, 100.0, vec![ - super::mcp::test_fixtures::rect("n11", "a", 0.0, 0.0, 10.0, 10.0), - super::mcp::test_fixtures::rect("n12", "b", 20.0, 0.0, 10.0, 10.0), + crate::test_fixtures::rect("n11", "a", 0.0, 0.0, 10.0, 10.0), + crate::test_fixtures::rect("n12", "b", 20.0, 0.0, 10.0, 10.0), ]); let s = state_with(vec![f]); let info = document_info_snapshot(&s); diff --git a/crates/openpencil-shell-core/src/mcp/node_attr_tools.rs b/crates/op-mcp/src/node_attr_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/node_attr_tools.rs rename to crates/op-mcp/src/node_attr_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/node_attr_tools_tests.rs b/crates/op-mcp/src/node_attr_tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/node_attr_tools_tests.rs rename to crates/op-mcp/src/node_attr_tools_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/page_tools.rs b/crates/op-mcp/src/page_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/page_tools.rs rename to crates/op-mcp/src/page_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/parser.rs b/crates/op-mcp/src/parser.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/parser.rs rename to crates/op-mcp/src/parser.rs diff --git a/crates/openpencil-shell-core/src/mcp/read_tools.rs b/crates/op-mcp/src/read_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/read_tools.rs rename to crates/op-mcp/src/read_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs b/crates/op-mcp/src/replace_node_tests.rs similarity index 99% rename from crates/openpencil-shell-core/src/mcp/replace_node_tests.rs rename to crates/op-mcp/src/replace_node_tests.rs index 587d38068..c1b50d27f 100644 --- a/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs +++ b/crates/op-mcp/src/replace_node_tests.rs @@ -179,7 +179,7 @@ fn replace_node_rejects_malformed_drop_children() { #[test] fn parser_refuses_structured_drop_children_at_wire_layer() { - use crate::mcp::parse_tool_call; + use crate::parse_tool_call; for bad_json in [ r#"{"id":1,"method":"replace_node","params":{"node_id":"n10","kind":"rect","name":"X","x":"0","y":"0","width":"5","height":"5","drop_children":{}}}"#, r#"{"id":1,"method":"replace_node","params":{"node_id":"n10","kind":"rect","name":"X","x":"0","y":"0","width":"5","height":"5","drop_children":[true]}}"#, diff --git a/crates/openpencil-shell-core/src/mcp/scalar_vars.rs b/crates/op-mcp/src/scalar_vars.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/scalar_vars.rs rename to crates/op-mcp/src/scalar_vars.rs diff --git a/crates/openpencil-shell-core/src/mcp/scalar_vars_tests.rs b/crates/op-mcp/src/scalar_vars_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/scalar_vars_tests.rs rename to crates/op-mcp/src/scalar_vars_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/selected_ops_tools.rs b/crates/op-mcp/src/selected_ops_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/selected_ops_tools.rs rename to crates/op-mcp/src/selected_ops_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/selected_ops_tools_tests.rs b/crates/op-mcp/src/selected_ops_tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/selected_ops_tools_tests.rs rename to crates/op-mcp/src/selected_ops_tools_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/test_fixtures.rs b/crates/op-mcp/src/test_fixtures.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/test_fixtures.rs rename to crates/op-mcp/src/test_fixtures.rs diff --git a/crates/openpencil-shell-core/src/mcp/tools.rs b/crates/op-mcp/src/tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/tools.rs rename to crates/op-mcp/src/tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/tools_tests.rs b/crates/op-mcp/src/tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/tools_tests.rs rename to crates/op-mcp/src/tools_tests.rs diff --git a/crates/openpencil-shell-core/src/mcp/write_tools.rs b/crates/op-mcp/src/write_tools.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/write_tools.rs rename to crates/op-mcp/src/write_tools.rs diff --git a/crates/openpencil-shell-core/src/mcp/write_tools_tests.rs b/crates/op-mcp/src/write_tools_tests.rs similarity index 100% rename from crates/openpencil-shell-core/src/mcp/write_tools_tests.rs rename to crates/op-mcp/src/write_tools_tests.rs diff --git a/crates/openpencil-desktop/Cargo.toml b/crates/openpencil-desktop/Cargo.toml index 412018c21..93bcb70ab 100644 --- a/crates/openpencil-desktop/Cargo.toml +++ b/crates/openpencil-desktop/Cargo.toml @@ -21,6 +21,10 @@ openpencil-shell-native = { path = "../openpencil-shell-native", version = "0.1. # `op_editor_core::EditorState` (canonical `.op` document) instead of the # old shell-core `Document`. op-editor-core = { path = "../op-editor-core" } +# Phase 7 strangler reorg: the MCP tool registry + JSON-RPC stdio layer +# (`mcp.rs` + `mcp/*`) was extracted out of openpencil-shell-core into the +# op-mcp crate; `mcp_serve.rs` registers tools through `op_mcp::*`. +op-mcp = { path = "../op-mcp" } # Canonical `.op` (PenDocument) → shell `Document` loader / adapter. # Extracted out of this binary into a shared library crate so library # crates (openpencil-shell-native) can reuse the conversion; diff --git a/crates/openpencil-desktop/src/mcp_serve.rs b/crates/openpencil-desktop/src/mcp_serve.rs index a82cf1bb9..b0018a71a 100644 --- a/crates/openpencil-desktop/src/mcp_serve.rs +++ b/crates/openpencil-desktop/src/mcp_serve.rs @@ -29,7 +29,7 @@ use std::io::{BufRead, BufReader, BufWriter, Write}; use std::path::PathBuf; use op_editor_core::EditorState; -use openpencil_shell_core::mcp::{ +use op_mcp::{ batch_design_snapshot, copy_node_snapshot, delete_node_snapshot, design_content_snapshot, design_refine_snapshot, design_skeleton_snapshot, add_page_snapshot, clear_selection_snapshot, create_component_snapshot, diff --git a/crates/openpencil-shell-core/src/lib.rs b/crates/openpencil-shell-core/src/lib.rs index 621006c0b..ca9ac56a3 100644 --- a/crates/openpencil-shell-core/src/lib.rs +++ b/crates/openpencil-shell-core/src/lib.rs @@ -30,11 +30,9 @@ pub mod layout_scene; // Canvas hit-test (input path) over `LayoutScene` — replaces the // `&Document`-bound `node_at_doc_point` / `nodes_intersecting_doc_rect`. pub mod layout_scene_hit; -pub mod mcp; // Paint-time design-variable aggregation consumed by the // `LayoutScene` scene builder (`$ref` fill / stroke resolution). pub mod scene_vars; -#[cfg(test)] mod mcp_tests; // Phase 4 strangler reorg: the wasm-clean RenderBackend trait moved into the // op-editor-core crate. Re-exported as `render_backend` so `crate::render_backend::*` // paths still resolve.