pub trait ArgumentValidator: Send + Sync {
// Required method
fn validate(&self, args: &Value) -> Result<(), ArgumentRefusal>;
}Expand description
A per-tool rule about a COMBINATION of argument values, run strictly AFTER
the declared inputSchema check (Phase 128, E2).
§Ordering is the contract
A validator NEVER sees arguments that failed the declared schema. It runs
inside the same decorator, after the schema check returns Ok and before the
inner handler. tests/request_policy.rs’s counting row fails if that order
inverts.
It also survives the schema opt-out: with [server.validation] enforce_input_schema = false the decorator skips only the SCHEMA CHECK, and a
registered validator still runs. Turning off one enforcement must never
silently turn off another.
§Refuse-only: this signature cannot normalize
validate takes &Value and returns a refusal, so it cannot mutate the
arguments. Normalizing an argument before dispatch — rewriting a code, casing
a string — is therefore OUT OF SCOPE for this signature. That is a deliberate
restriction, not an omission: a mutating validator has a different contract
(idempotency, what the tool’s published schema then describes, and whether
the schema check should re-run on the rewritten value), and that contract is
recorded as an open question rather than settled by the shape of a first
signature.
§Example
use pmcp_server_toolkit::{ArgumentRefusal, ArgumentValidator};
use serde_json::Value;
struct EndAfterStart;
impl ArgumentValidator for EndAfterStart {
fn validate(&self, args: &Value) -> Result<(), ArgumentRefusal> {
let start = args.get("start").and_then(Value::as_i64);
let end = args.get("end").and_then(Value::as_i64);
match (start, end) {
(Some(s), Some(e)) if e < s => Err(ArgumentRefusal::new(
"`end` must not precede `start`",
)),
_ => Ok(()),
}
}
}Required Methods§
Sourcefn validate(&self, args: &Value) -> Result<(), ArgumentRefusal>
fn validate(&self, args: &Value) -> Result<(), ArgumentRefusal>
Allow or refuse one call’s already-schema-valid arguments.
§Errors
Return ArgumentRefusal to refuse. The inner handler is then never
invoked and no backend request is made.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".