#[non_exhaustive]pub struct OutboundRequest<'a> {
pub tool: &'a str,
pub method: &'a str,
pub path: &'a str,
pub query: &'a [(String, String)],
pub body: Option<&'a Value>,
}Expand description
One outbound backend request, as it will be sent, handed to a
RequestPolicy for inspection.
§The D-12 guarantee, stated as a guarantee
This struct has NO credential-bearing field, and it is constructed BEFORE the
HttpAuthProvider runs on either HTTP surface. A policy implementation
therefore cannot observe an outgoing credential — not because it is asked not
to, but because the value it is handed was assembled before the credential
existed. tests/request_policy.rs’s credential-scan row asserts this by
searching every field for the configured secret.
Borrowed throughout (&'a str, &'a [_]): a server with no registered policy
never constructs one, so the empty case adds no allocation.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.tool: &'a strThe MCP tool whose tools/call produced this request.
Both shipped surfaces name a tool: the curated single-call surface passes
the synthesized tool’s own name, and the Code Mode surface passes the
label attached to the executor at synthesis (a script tool’s [[tools]]
name, or execute_code for the generic Code Mode tool). On the Code
Mode surface ONE tools/call may produce many outbound requests, and all
of them carry that same label.
Empty ONLY when a caller drives a connector directly rather than through a
synthesized handler — there is then no tool to name. A policy that keys on
the tool name should treat the empty string as “unattributed”, never as a
tool called "".
method: &'a strThe HTTP method, upper-cased (GET, POST, …).
path: &'a strThe FULLY RESOLVED request target: every path placeholder substituted and the configured base URL already joined on. The SDK appends no query string to it.
It is the resolved path and never the template, so an endpoint allowlist
sees the URL as it will be sent. The query pairs the SDK will add are
carried separately in Self::query.
§An author-written ? STAYS in path
“The SDK appends no query string” is about what the SDK adds, not about what
a script author wrote. On the Code Mode surface,
api.get('/search/current?string=x') puts a literal ?string=x in the path
template, and the path floor deliberately permits ONE author-written ?
(validate_resolved_target), so it reaches a policy INSIDE path and never
appears in Self::query. A policy that must see or refuse every query pair
therefore has to look for a ? in path as well as read query. The
object form, api.get(path, { .. }), is what populates query.
query: &'a [(String, String)]The query pairs that will be appended to Self::path, EXCLUDING any
pair the auth provider contributes.
An API-key-in-query credential is an auth contribution and is therefore absent here by construction — that omission is the D-12 guarantee, not an oversight.
Populated on BOTH surfaces. On the Code Mode surface that required moving
the non-auth half of the remaining-body-to-query conversion above the hook
(Phase 128 plan 09); without that move a policy written to inspect query
pairs would have inspected an empty slice while the pairs that were about
to be sent still sat in Self::body.
body: Option<&'a Value>The JSON request body, when one will be sent.
None for a GET-like request, whose remaining fields have already been
converted into Self::query by the time the policy runs.
Implementations§
Source§impl<'a> OutboundRequest<'a>
impl<'a> OutboundRequest<'a>
Sourcepub fn new(
tool: &'a str,
method: &'a str,
path: &'a str,
query: &'a [(String, String)],
body: Option<&'a Value>,
) -> Self
pub fn new( tool: &'a str, method: &'a str, path: &'a str, query: &'a [(String, String)], body: Option<&'a Value>, ) -> Self
Construct an OutboundRequest.
A constructor rather than a struct literal because the type is
#[non_exhaustive]; this is also what lets an out-of-crate test build one
to exercise a policy in isolation.
Trait Implementations§
Source§impl<'a> Clone for OutboundRequest<'a>
impl<'a> Clone for OutboundRequest<'a>
impl<'a> Copy for OutboundRequest<'a>
Auto Trait Implementations§
impl<'a> Freeze for OutboundRequest<'a>
impl<'a> RefUnwindSafe for OutboundRequest<'a>
impl<'a> Send for OutboundRequest<'a>
impl<'a> Sync for OutboundRequest<'a>
impl<'a> Unpin for OutboundRequest<'a>
impl<'a> UnsafeUnpin for OutboundRequest<'a>
impl<'a> UnwindSafe for OutboundRequest<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more