mcplease 0.4.2

simple mcp framework
Documentation
[workspace]
members = [".", "cli"]
resolver = "2"

[package]
name = "mcplease"
version = "0.4.2"
edition = "2024"
description = "simple mcp framework"
license = "MIT OR Apache-2.0"
repository = "https://github.com/jbr/mcplease"
readme = "README.md"
exclude = ["spec"]
keywords = ["mcp"]
categories = ["development-tools"]

[package.metadata.docs.rs]
features = ["cli", "client", "session", "stdio", "server"]
# Turns on `feature(doc_cfg)` in lib.rs, which labels every feature-gated item
# with the feature that enables it.
rustdoc-args = ["--cfg", "docsrs"]


[dependencies]
# Always on: the protocol types need nothing but serde, and `log` is a facade
# with no transitive dependencies.
log = "0.4.33"
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"

# `server`
anyhow = { version = "1.0.104", optional = true }
fieldwork = { version = "0.5.3", optional = true }
schemars = { version = "1.2.2", optional = true }

# `cli`
clap = { version = "4.6.6", features = ["derive"], optional = true }
env_logger = { version = "0.11.11", optional = true }

# `cli` and `session` (both locate and expand storage paths)
dirs = { version = "6.0.0", optional = true }
shellexpand = { version = "3.1.2", optional = true }

# `session`
notify = { version = "8.2.0", optional = true }

# The features name the two axes a consumer picks along: *what side of the
# protocol* it implements, and *over what transport*. `types` is unconditional
# because both sides need all of it — a `JsonRpcRequest` is written by a client
# and read by a server — and it costs nothing but serde.
#
# The default is everything, so a consumer that does not opt out is unaffected
# by the split.
[features]
default = ["cli", "client", "session"]

# Author and dispatch tools, transport-agnostically: the `traits` module, the
# `tools!` and `server_info!` macros, and `handle_request`, which maps a decoded
# `JsonRpcRequest` to a `JsonRpcResponse` without performing any I/O. This is
# the whole surface a non-stdio transport (an HTTP endpoint, say) needs.
server = ["dep:anyhow", "dep:fieldwork", "dep:schemars"]

# The client side of the protocol, transport-agnostically: request
# construction (including the per-request `_meta` that `2026-07-28` requires),
# the `server/discover` → `initialize` negotiation, and the disposition of each
# message that arrives. Like `server`, it performs no I/O — and it needs no
# dependency beyond the unconditional three, so it is free to enable.
client = []

# The stdio transport: a blocking `serve` loop over stdin/stdout, the transport
# every locally-spawned MCP server speaks.
stdio = ["server"]

# The command-line path: `run`, which invokes a tool directly from argv via clap
# (so a tool is testable without an MCP client) and otherwise starts `serve`.
# This is what makes `tools!` derive clap's `Subcommand`.
cli = ["stdio", "dep:clap", "dep:dirs", "dep:env_logger", "dep:shellexpand"]

# `SessionStore`: per-session state persisted to disk and kept in sync across
# processes with a file watcher. Orthogonal to both axes — a server on any
# transport may or may not want it — and the only thing that pulls `notify`.
session = ["dep:anyhow", "dep:dirs", "dep:notify", "dep:shellexpand"]