Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
842 changes: 494 additions & 348 deletions Cargo.lock

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,20 @@ tonin-mcp-macros = { path = "crates/tonin-mcp-macros", version = "0.12.1" }
tonin-build = { path = "crates/tonin-build", version = "0.12.1" }

tokio = { version = "1", features = ["full"] }
tonic = "0.12"
tonic = "0.14"
tonic-prost = "0.14"
dashmap = "6"
futures-util = "0.3"
tokio-stream = { version = "0.1", features = ["net"] }
tonic-build = "0.12"
prost = "0.13"
prost-types = "0.13"
tonic-prost-build = "0.14"
prost = "0.14"
prost-types = "0.14"
tower = "0.5"
hyper = "1"
http = "1"
http-body-util = "0.1"
async-trait = "0.1"
thiserror = "1"
thiserror = "2"
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand All @@ -59,7 +60,7 @@ toml = "0.8"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
clap = { version = "4", features = ["derive", "env"] }
reqwest = { version = "0.12", default-features = false, features = ["stream", "rustls-tls"] }
reqwest = { version = "0.13", default-features = false, features = ["stream", "rustls"] }
flate2 = "1"
tar = "0.4"

Expand Down
4 changes: 2 additions & 2 deletions crates/tonin-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ homepage.workspace = true
readme.workspace = true
keywords.workspace = true
categories.workspace = true
description = "build.rs helper for tonin services. Wraps tonic-build with tonin conventions."
description = "build.rs helper for tonin services. Wraps tonic-prost-build with tonin conventions."

[dependencies]
tonic-build = { workspace = true }
tonic-prost-build = { workspace = true }
4 changes: 2 additions & 2 deletions crates/tonin-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ pub fn compile(protos: &[&str], includes: &[&str]) -> Result<(), Box<dyn std::er
eprintln!(
"tonin-build: codec=buffa requested; falling back to prost (codegen plugin not yet wired)"
);
tonic_build::configure().compile_protos(protos, includes)?;
tonic_prost_build::configure().compile_protos(protos, includes)?;
}
Codec::Prost => {
tonic_build::configure().compile_protos(protos, includes)?;
tonic_prost_build::configure().compile_protos(protos, includes)?;
}
}
Ok(())
Expand Down
12 changes: 6 additions & 6 deletions crates/tonin-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ description = "tonin-sdk: Service builder, Config, Context, Error, and runtime f
tokio = { workspace = true }
tonic = { workspace = true }
# Serves grpc.health.v1.Health so Kubernetes `grpc:` probes work out of the box.
tonic-health = "0.12"
tonic-health = "0.14"
tower = { workspace = true }
hyper = { workspace = true, features = ["server", "http1", "http2"] }
http = { workspace = true }
Expand Down Expand Up @@ -44,20 +44,20 @@ opentelemetry-semantic-conventions = "0.32"
opentelemetry-http = "0.32"

# MCP runtime (folded from tonin-mcp)
rmcp = { version = "1", default-features = false, features = ["server", "macros", "transport-streamable-http-server"] }
rmcp-macros = "1"
schemars = "0.8"
rmcp = { version = "2", default-features = false, features = ["server", "macros", "transport-streamable-http-server"] }
rmcp-macros = "2"
schemars = "1"
hyper-util = { version = "0.1", features = ["server-auto", "tokio", "service"] }

# Auth defaults — JWT validation + JWKS fetch.
jsonwebtoken = { version = "10.4.0", features = ["rust_crypto"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
reqwest = { workspace = true, features = ["rustls", "json"] }
base64 = "0.22"

# Pre-wired state: postgres + redis. Lazy — connections only open if
# DATABASE_URL / REDIS_URL are present at boot. See src/state.rs.
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "postgres"] }
redis = { version = "0.27", default-features = false, features = ["tokio-rustls-comp"] }
redis = { version = "1", default-features = false, features = ["tokio-rustls-comp"] }

[dev-dependencies]
tokio = { workspace = true }
Expand Down
12 changes: 6 additions & 6 deletions crates/tonin-sdk/src/auth/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::task::{Context, Poll};
use futures_util::future::BoxFuture;
use http::{Request, Response};
use tonic::Status;
use tonic::body::BoxBody;
use tonic::body::Body;
use tower::{Layer, Service};

use super::{AuthCtx, AuthError, CURRENT_AUTH, TokenExtractor, TokenVerifier};
Expand Down Expand Up @@ -72,21 +72,21 @@ pub struct AuthService<S> {
optional: bool,
}

impl<S> Service<Request<BoxBody>> for AuthService<S>
impl<S> Service<Request<Body>> for AuthService<S>
where
S: Service<Request<BoxBody>, Response = Response<BoxBody>> + Clone + Send + 'static,
S: Service<Request<Body>, Response = Response<Body>> + Clone + Send + 'static,
S::Error: Send + 'static,
S::Future: Send + 'static,
{
type Response = Response<BoxBody>;
type Response = Response<Body>;
type Error = S::Error;
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;

fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}

fn call(&mut self, mut req: Request<BoxBody>) -> Self::Future {
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
// The gRPC health service backs Kubernetes `grpc:` probes, which send
// no credentials. Let it through without auth so liveness/readiness
// checks aren't 401'd on services that require a token.
Expand Down Expand Up @@ -140,7 +140,7 @@ fn metadata_from_headers(h: &http::HeaderMap) -> tonic::metadata::MetadataMap {

/// Encode an `AuthError` as a gRPC status response. tonic 0.12 exposes
/// `Status::into_http()` for this.
fn error_response(e: AuthError) -> Response<BoxBody> {
fn error_response(e: AuthError) -> Response<Body> {
let status: Status = e.into();
status.into_http()
}
15 changes: 8 additions & 7 deletions crates/tonin-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@
//! .await
//! }
//!
//! # use tonic::body::BoxBody;
//! # use tonic::body::Body;
//! # #[derive(Clone)]
//! # struct MyGrpc;
//! # impl tonic::server::NamedService for MyGrpc {
//! # const NAME: &'static str = "my.Grpc";
//! # }
//! # impl tower::Service<http::Request<BoxBody>> for MyGrpc {
//! # type Response = http::Response<BoxBody>;
//! # impl tower::Service<http::Request<Body>> for MyGrpc {
//! # type Response = http::Response<Body>;
//! # type Error = std::convert::Infallible;
//! # type Future = std::pin::Pin<Box<dyn std::future::Future<
//! # Output = std::result::Result<Self::Response, Self::Error>> + Send>>;
//! # fn poll_ready(&mut self, _: &mut std::task::Context<'_>)
//! # -> std::task::Poll<std::result::Result<(), Self::Error>> { unimplemented!() }
//! # fn call(&mut self, _: http::Request<BoxBody>) -> Self::Future { unimplemented!() }
//! # fn call(&mut self, _: http::Request<Body>) -> Self::Future { unimplemented!() }
//! # }
//! # fn my_grpc_service() -> MyGrpc { MyGrpc }
//! ```
Expand Down Expand Up @@ -278,12 +278,13 @@ impl Service {
pub fn handler<S>(mut self, svc: S) -> Self
where
S: tower::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<tonic::body::BoxBody>,
http::Request<tonic::body::Body>,
Response = http::Response<tonic::body::Body>,
Error = std::convert::Infallible,
> + tonic::server::NamedService
+ Clone
+ Send
+ Sync
+ 'static,
S::Future: Send + 'static,
{
Expand Down Expand Up @@ -318,7 +319,7 @@ impl Service {
// Serve grpc.health.v1.Health so Kubernetes `grpc:` probes work out of
// the box. Mark the overall ("") service SERVING; the auth layer
// allowlists this path so probes pass without credentials.
let (mut health_reporter, health_service) = tonic_health::server::health_reporter();
let (health_reporter, health_service) = tonic_health::server::health_reporter();
health_reporter
.set_service_status("", tonic_health::ServingStatus::Serving)
.await;
Expand Down
6 changes: 3 additions & 3 deletions crates/tonin-sdk/src/mcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use hyper_util::server::conn::auto::Builder as HyperBuilder;
use hyper_util::service::TowerToHyperService;
use rmcp::handler::server::router::tool::ToolRouter;
use rmcp::model::{
CallToolResult, Content, Implementation, ProtocolVersion, ServerCapabilities, ServerInfo,
CallToolResult, ContentBlock, Implementation, ProtocolVersion, ServerCapabilities, ServerInfo,
};
use rmcp::transport::streamable_http_server::StreamableHttpService;
use rmcp::transport::streamable_http_server::session::local::LocalSessionManager;
Expand All @@ -52,7 +52,7 @@ pub use rmcp as __rmcp_reexport;

pub use rmcp::handler::server::wrapper::Parameters;
pub use rmcp::model::CallToolResult as McpCallToolResult;
pub use rmcp::model::Content as McpContent;
pub use rmcp::model::ContentBlock as McpContent;
pub use rmcp::{ErrorData as McpErrorData, ServerHandler as McpServerHandler};

/// Configuration for the in-process MCP listener.
Expand Down Expand Up @@ -99,7 +99,7 @@ impl McpServer {
/// same orchestration probes during the rollout.
#[tool(description = "Liveness probe. Returns 'ok' if the service is running.")]
async fn health(&self) -> Result<CallToolResult, McpError> {
Ok(CallToolResult::success(vec![Content::text("ok")]))
Ok(CallToolResult::success(vec![ContentBlock::text("ok")]))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ license = { text = "Apache-2.0" }
# to call this service install only this package + grpcio + protobuf;
# they DO NOT pull in the server framework.
dependencies = [
"grpcio>=1.66",
"grpcio>=1.81",
"protobuf>=5",
"tonin-client",
]

[project.optional-dependencies]
codegen = [
"grpcio-tools>=1.66",
"grpcio-tools>=1.81",
]

[build-system]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ license = { text = "Apache-2.0" }
dependencies = [
"tonin",
"{{ service_name }}-client",
"grpcio>=1.66",
"grpcio>=1.81",
"protobuf>=5",
]

[project.optional-dependencies]
codegen = [
"grpcio-tools>=1.66",
"grpcio-tools>=1.81",
]
test = [
"pytest>=8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ license = "Apache-2.0"
# cost. schemars is pulled in for MCP schema derivation (build-time
# attribute on every generated message), still no runtime overhead
# for non-MCP consumers.
tonic = "0.12"
prost = "0.13"
tonic = "0.14"
tonic-prost = "0.14"
prost = "0.14"
serde = { version = "1", features = ["derive"] }
schemars = "1"
tonin-client = "0.1"
tonin-client = "0.12"

[build-dependencies]
tonic-build = "0.12"
tonic-prost-build = "0.14"
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// `#[tonin::mcp_expose]` reads them via schemars). They're
// additive — services that don't use MCP pay only the build-time
// cost of the derives, no runtime cost.
tonic_build::configure()
tonic_prost_build::configure()
.build_server(false)
.build_client(true)
.type_attribute(
Expand Down
13 changes: 7 additions & 6 deletions crates/tonin/templates/service/rust/server/Cargo.toml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ path = "src/main.rs"
path = "src/lib.rs"

[dependencies]
tonin = "0.1"
tonin = "0.12"
{{ service_name }}-client = { path = "../client-rust" }

tokio = { version = "1", features = ["full"] }
tonic = "0.12"
prost = "0.13"
tonic = "0.14"
tonic-prost = "0.14"
prost = "0.14"
async-trait = "0.1"
tracing = "0.1"
futures = "0.3"
Expand All @@ -31,8 +32,8 @@ futures = "0.3"
# transitively required by the macro output only.
serde_json = "1"
schemars = "1"
rmcp = { version = "1", default-features = false, features = ["server", "macros"] }
rmcp-macros = "1"
rmcp = { version = "2", default-features = false, features = ["server", "macros"] }
rmcp-macros = "2"

tokio-stream = "0.1"

Expand All @@ -42,4 +43,4 @@ tokio-stream = "0.1"
[build-dependencies]
# Server build.rs generates the SERVER side (Greeter trait, GreeterServer)
# only — message types come from ../client-rust via the path dep above.
tonic-build = "0.12"
tonic-prost-build = "0.14"
2 changes: 1 addition & 1 deletion crates/tonin/templates/service/rust/server/build.rs.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Server-side codegen: emit the Greeter trait + GreeterServer.
// Messages and the GreeterClient come from `../client-rust` via the
// path dep in Cargo.toml — no duplicate codegen.
tonic_build::configure()
tonic_prost_build::configure()
.build_server(true)
.build_client(false)
.extern_path(".{{ service_name_snake }}.v1", "::{{ service_name_snake }}_client::proto")
Expand Down
6 changes: 3 additions & 3 deletions crates/tonin/templates/service/ts/client-ts/package.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"clean": "rm -rf dist src/gen"
},
"dependencies": {
"@grpc/grpc-js": "^1.11",
"@grpc/grpc-js": "^1.14.4",
"google-protobuf": "^3.21",
"tonin-client": "^0.1.0"
"tonin-client": "^0.12.1"
},
"peerDependencies": {
"grpc-web": "^1.5"
Expand All @@ -35,7 +35,7 @@
"@bufbuild/buf": "^1.46",
"@protobuf-ts/plugin": "^2.9",
"ts-proto": "^2.2",
"typescript": "^5.6",
"typescript": "^6.0.3",
"@types/google-protobuf": "^3.15"
}
}
1 change: 1 addition & 0 deletions examples/greeter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "src/main.rs"
tonin-sdk = { workspace = true }
tokio = { workspace = true }
tonic = { workspace = true }
tonic-prost = { workspace = true }
prost = { workspace = true }
tonin-client = { workspace = true }
futures-util = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions examples/inventory/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "src/main.rs"
tonin-sdk = { workspace = true }
tokio = { workspace = true }
tonic = { workspace = true }
tonic-prost = { workspace = true }
prost = { workspace = true }

[build-dependencies]
Expand Down
1 change: 1 addition & 0 deletions examples/orders/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "src/main.rs"
tonin-sdk = { workspace = true }
tokio = { workspace = true }
tonic = { workspace = true }
tonic-prost = { workspace = true }
prost = { workspace = true }
tracing = { workspace = true }

Expand Down
2 changes: 1 addition & 1 deletion python/tonin-client/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = { text = "Apache-2.0" }
# the Metadata type AuthCtx.propagate writes into. Peers already have it
# via the generated stubs; pinning it here makes the typing explicit.
dependencies = [
"grpcio>=1.66",
"grpcio>=1.81",
]

[project.optional-dependencies]
Expand Down
Loading
Loading