diff --git a/Cargo.lock b/Cargo.lock index c4f8ddb..c520efb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -549,7 +549,7 @@ dependencies = [ "log", "num-rational", "num-traits", - "pastey", + "pastey 0.1.1", "rayon", "thiserror 2.0.18", "v_frame", @@ -1229,6 +1229,16 @@ dependencies = [ "darling_macro 0.21.3", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -1257,6 +1267,19 @@ dependencies = [ "syn 2.0.117", ] +[[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 2.0.117", +] + [[package]] name = "darling_macro" version = "0.20.11" @@ -1279,6 +1302,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + [[package]] name = "dary_heap" version = "0.3.9" @@ -3666,6 +3700,23 @@ dependencies = [ "wiremock", ] +[[package]] +name = "kebab-mcp" +version = "0.3.0" +dependencies = [ + "anyhow", + "kebab-app", + "kebab-config", + "kebab-core", + "rmcp", + "schemars 1.2.1", + "serde", + "serde_json", + "tempfile", + "tokio", + "tracing", +] + [[package]] name = "kebab-normalize" version = "0.3.0" @@ -5457,6 +5508,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" +[[package]] +name = "pastey" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a" + [[package]] name = "path_abs" version = "0.5.1" @@ -6306,6 +6363,40 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rmcp" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12ca9067b5ebfbd5b3fcdc4acfceb81aa7d5ab2a879dff7cb75d22434276aad" +dependencies = [ + "async-trait", + "chrono", + "futures", + "pastey 0.2.2", + "pin-project-lite", + "rmcp-macros", + "schemars 1.2.1", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "rmcp-macros" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7caa6743cc0888e433105fe1bc551a7f607940b126a37bc97b478e86064627eb" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.117", +] + [[package]] name = "roaring" version = "0.10.12" @@ -6512,12 +6603,26 @@ 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 2.0.117", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -6606,6 +6711,17 @@ dependencies = [ "syn 2.0.117", ] +[[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 2.0.117", +] + [[package]] name = "serde_json" version = "1.0.149" diff --git a/Cargo.toml b/Cargo.toml index 62001d6..b37a610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "crates/kebab-parse-image", "crates/kebab-parse-pdf", "crates/kebab-tui", + "crates/kebab-mcp", ] [workspace.package] @@ -71,6 +72,10 @@ futures = "0.3" # pass; pulled into the workspace deps so future crates can share the # same major. regex = "1" +# MCP (Model Context Protocol) SDK. server + macros + transport-io provide +# stdio JSON-RPC transport for `kebab-mcp` (p9-fb-30). schemars feature +# exposes the derive macro used by tool input schemas. +rmcp = { version = "1.6", default-features = false, features = ["server", "macros", "transport-io", "schemars"] } # Dev-only HTTP mock server for kebab-llm-local Ollama adapter tests. Requires # a tokio runtime to host its mock server (the runtime adapter crate stays # sync via reqwest::blocking — wiremock is dev-only there). diff --git a/crates/kebab-mcp/Cargo.toml b/crates/kebab-mcp/Cargo.toml new file mode 100644 index 0000000..dfd6136 --- /dev/null +++ b/crates/kebab-mcp/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "kebab-mcp" +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +version = { workspace = true } + +[dependencies] +rmcp = { workspace = true } +# rt-multi-thread + io-util + io-std extend the workspace tokio entry +# (which only declares rt + macros) for the blocking stdio MCP transport. +tokio = { workspace = true, features = ["rt-multi-thread", "macros", "io-util", "io-std"] } +serde = { workspace = true } +serde_json = { workspace = true } +anyhow = { workspace = true } +tracing = { workspace = true } +# schemars 1.x matches rmcp 1.6's ^1.0 requirement (verified via crates.io +# /dependencies endpoint — rmcp declares optional schemars = "^1.0"). +schemars = "1" + +kebab-app = { path = "../kebab-app" } +kebab-config = { path = "../kebab-config" } +kebab-core = { path = "../kebab-core" } + +[dev-dependencies] +tempfile = { workspace = true } diff --git a/crates/kebab-mcp/src/lib.rs b/crates/kebab-mcp/src/lib.rs new file mode 100644 index 0000000..a6ac5a0 --- /dev/null +++ b/crates/kebab-mcp/src/lib.rs @@ -0,0 +1,16 @@ +//! MCP (Model Context Protocol) server over stdio. Exposes 4 read-only +//! tools (`search` / `ask` / `schema` / `doctor`) backed by `kebab-app` +//! facade methods. Used by `kebab-cli`'s `Cmd::Mcp` arm. +//! +//! See spec `docs/superpowers/specs/2026-05-07-p9-fb-30-mcp-server-design.md`. + +use anyhow::Result; + +use kebab_config::Config; + +/// Run the MCP server on stdio JSON-RPC. Blocks until the client closes +/// the stream (typically when the agent host exits). +pub fn serve_stdio(_cfg: Config) -> Result<()> { + // Skeleton — actual rmcp wiring lands in Task 3. + anyhow::bail!("kebab-mcp: serve_stdio not yet implemented") +}