pub struct HttpCodeExecutor { /* private fields */ }Expand description
Low-level HTTP executor bridging the toolkit’s outbound
HttpAuthProvider to pmcp-code-mode’s
HttpExecutor trait.
This is the OpenAPI analog of SqlCodeExecutor, but at a DIFFERENT layer:
it impls the LOW-LEVEL pmcp_code_mode::HttpExecutor
(execute_request(method, path, body)), NOT the high-level
CodeExecutor. It is wrapped by a
JsCodeExecutor for the Code Mode path
(the JsCodeExecutor<HttpCodeExecutor>: CodeExecutor blanket impl) and is
called directly by script tools (Plan 05). The single-call synthesizer
(Plan 03) does NOT use this path — it calls HttpConnector::execute
directly.
§Per-request passthrough token (H1)
The inbound_token field carries the per-request MCP client token captured
by the binary (Plan 06) into [AuthContext]. It is passed to
HttpAuthProvider::apply so an
OAuthPassthroughAuth provider
forwards it to the backend; static providers ignore it (proven in Plan 01).
Because Code Mode reuses ONE executor instance across requests, the binary
produces a per-request clone carrying the captured token via
HttpCodeExecutor::with_inbound_token.
§Redaction (Pitfall 5 / T-90-04-01)
Auth/transport failures are mapped to
ExecutionError::RuntimeError
whose message names the operation / status only — it NEVER echoes the
request URL or the Authorization token.
§Feature gate (H2)
Gated under openapi-code-mode (the Plan 90-01 umbrella that forwards
pmcp-code-mode/js-runtime). The bare code-mode feature does NOT bring
HttpExecutor into scope, so this type cannot be gated on
all(feature = "http", feature = "code-mode").
Implementations§
Source§impl HttpCodeExecutor
impl HttpCodeExecutor
Sourcepub fn new(
client: Client,
base_url: String,
auth: Arc<dyn HttpAuthProvider>,
) -> Self
pub fn new( client: Client, base_url: String, auth: Arc<dyn HttpAuthProvider>, ) -> Self
Construct an executor over client + base_url, authenticating outgoing
requests via auth. The per-request inbound_token starts None;
the binary attaches it per request with
HttpCodeExecutor::with_inbound_token.
Sourcepub fn with_tool_label(self, tool: impl AsRef<str>) -> Self
pub fn with_tool_label(self, tool: impl AsRef<str>) -> Self
Label this executor with the MCP tool it serves, so an E1 policy is told
which tools/call an outbound request came from (Phase 128).
Attach it where a PER-TOOL executor is minted — ScriptToolHandler::new
for a script tool, code_mode_http_tools_from_executor for execute_code.
On the Code Mode surface one tools/call may issue many outbound requests
and they all carry this same label.
Sourcepub fn tool_label(&self) -> &str
pub fn tool_label(&self) -> &str
The MCP tool this executor serves, or "" when it carries no label (a
caller driving the executor directly, with no tool to name).
Sourcepub fn with_call_id(self, call_id: impl AsRef<str>) -> Self
pub fn with_call_id(self, call_id: impl AsRef<str>) -> Self
Stamp the per-tools/call id onto every policy request this executor makes,
see crate::policy::OutboundRequest::call_id.
request_executor_from_extra calls this once per tools/call, so an
embedder normally never does. It is public for an embedder that derives its
own per-call executor and wants its requests grouped the same way.
Sourcepub fn call_id(&self) -> &str
pub fn call_id(&self) -> &str
The id of the tools/call this executor serves, or "" on a base executor
that no call has derived from (nothing to group by).
Sourcepub fn with_request_policy(self, policy: Arc<dyn RequestPolicy>) -> Self
pub fn with_request_policy(self, policy: Arc<dyn RequestPolicy>) -> Self
Attach the E1 crate::policy::RequestPolicy consulted before every
outbound request this executor makes (Phase 128).
Cheap clone-with-builder, the same shape as
with_inbound_token.
§Call it BEFORE the executor fans out
Both HTTP surfaces run on ONE executor (D-02) — script tools take a clone
and Code Mode takes the original — so a clone taken before this builder
runs is permanently ungoverned. The same constraint
with_schema documents, for the same reason.
Sourcepub fn has_request_policy(&self) -> bool
pub fn has_request_policy(&self) -> bool
Whether this executor consults an E1 policy before sending.
Public for the same reason has_schema is: the wiring
lives in a different crate, so a registered-but-unreached policy must be
observable from outside rather than only from a #[cfg(test)] accessor.
Sourcepub fn with_schema(self, schema: Arc<OpenApiSchema>) -> Self
pub fn with_schema(self, schema: Arc<OpenApiSchema>) -> Self
Attach the operator’s parsed OpenAPI document, so a path placeholder can be narrowed by what the spec DECLARES for it (Phase 128 D4(b)).
Cheap clone-with-builder, the same shape as
with_inbound_token: the Arc is shared with
the api_schema resource rather than the document being duplicated.
§Call it BEFORE the executor fans out
Both HTTP surfaces run on ONE executor (D-02) — script tools take a clone
and Code Mode takes the original. A clone taken before this builder runs is
permanently unnarrowed, so the call has to precede both fan-out sites. The
production wiring is pmcp-openapi-server’s build_server, the only place
the executor and the parsed spec are both in scope.
Sourcepub fn with_inbound_token(self, token: Option<String>) -> Self
pub fn with_inbound_token(self, token: Option<String>) -> Self
Cheap clone-with-token builder (H1): the binary calls this PER REQUEST to
attach the captured inbound MCP token so an oauth_passthrough provider
forwards it. Static providers ignore the token, so calling this on a
static-auth executor is harmless.
Single-call tools (Plan 03) don’t use this path; the per-request token flows through Code Mode + script tools only.
Sourcepub fn has_schema(&self) -> bool
pub fn has_schema(&self) -> bool
Whether this executor carries an OpenAPI document, and therefore whether a path placeholder can be narrowed by a spec DECLARATION (Phase 128 D4(b)).
false never means “unchecked”: a spec-less executor still applies the
unconditional character floor and the always-on length cap to every
placeholder value. It means only that no ADDITIONAL declared narrowing is
available.
Public, and deliberately so. T-128-36c is the risk that with_schema gets
wired to a #[cfg(test)] helper — or applied after the executor has already
fanned out — leaving the production binary unnarrowed while every test
passes. The wiring lives in a DIFFERENT crate (pmcp-openapi-server’s
build_server), so a #[cfg(test)] accessor could not prove it from there.
This is a read-only boolean over a private field; it exposes nothing about
the document.
Trait Implementations§
Source§impl Clone for HttpCodeExecutor
impl Clone for HttpCodeExecutor
Source§impl HttpExecutor for HttpCodeExecutor
impl HttpExecutor for HttpCodeExecutor
Source§fn placeholder_rules(
&self,
method: &str,
path_template: &str,
param: &str,
) -> PlaceholderRules<'_>
fn placeholder_rules( &self, method: &str, path_template: &str, param: &str, ) -> PlaceholderRules<'_>
Narrow a layer-2 {param} value by what the carried OpenAPI document
DECLARES for it (Phase 128 D4(b)).
Delegates to the private spec_placeholder_rules helper in this module,
whose rustdoc states exactly what a schema/operation/parameter MISS costs —
the floor and the cap are retained, the spec’s narrowing is lost — and what
bounds that loss. Named in plain backticks rather than as an intra-doc link
because this method is public and the helper is private, which rustdoc
(correctly) warns about.
Source§fn execute_request<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
method: &'life1 str,
path: ResolvedPath<'life2>,
body: Option<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ExecutionError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn execute_request<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
method: &'life1 str,
path: ResolvedPath<'life2>,
body: Option<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ExecutionError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Auto Trait Implementations§
impl !RefUnwindSafe for HttpCodeExecutor
impl !UnwindSafe for HttpCodeExecutor
impl Freeze for HttpCodeExecutor
impl Send for HttpCodeExecutor
impl Sync for HttpCodeExecutor
impl Unpin for HttpCodeExecutor
impl UnsafeUnpin for HttpCodeExecutor
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