refactor: extract op-mcp crate
Relocate mcp.rs + mcp/* + mcp_tests.rs out of openpencil-shell-core into a dedicated op-mcp crate. The MCP tool registry + JSON-RPC stdio layer only depends on jian-ops-schema + op-editor-core (its tools build on EditorState / EditorCommand). mcp.rs becomes the crate's lib.rs; the mcp/ submodule files flatten to src/ so the `pub mod` declarations resolve unchanged, and intra-module `super::` paths stay valid. mcp_tests.rs becomes a #[cfg(test)] mod of lib.rs with its `super::mcp::` paths rewritten to `crate::`. openpencil-desktop's mcp_serve.rs now imports `op_mcp::*`. Pure relocation, no behaviour change; 138 tests move with their code.
This commit is contained in:
parent
9a0112b9a9
commit
e2e287c008
15
crates/op-mcp/Cargo.toml
Normal file
15
crates/op-mcp/Cargo.toml
Normal file
|
|
@ -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" }
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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]}}"#,
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue