pmcp_code_mode/lib.rs
1// Originated from pmcp-run/built-in/shared/pmcp-code-mode (https://github.com/guyernest/pmcp-run)
2// Moved into rust-mcp-sdk workspace as a first-class SDK crate for Phase 67.1
3//
4// Clippy pedantic/nursery allows for code imported from pmcp-run.
5// These will be cleaned up incrementally in future phases.
6#![allow(clippy::use_self)]
7#![allow(clippy::doc_markdown)]
8#![allow(clippy::needless_raw_string_hashes)]
9#![allow(clippy::needless_borrows_for_generic_args)]
10#![allow(clippy::if_same_then_else)]
11#![allow(clippy::map_unwrap_or)]
12#![allow(clippy::unused_self)]
13#![allow(clippy::too_many_arguments)]
14#![allow(clippy::struct_excessive_bools)]
15#![allow(clippy::cast_possible_wrap)]
16#![allow(clippy::only_used_in_recursion)]
17#![allow(clippy::self_only_used_in_recursion)]
18#![allow(clippy::redundant_pub_crate)]
19#![allow(clippy::manual_is_variant_and)]
20#![allow(clippy::unnecessary_literal_bound)]
21
22//! Code Mode - LLM-generated query validation and execution.
23//!
24//! This crate provides the infrastructure for "Code Mode", which allows MCP clients
25//! to generate and execute structured queries (GraphQL, SQL, REST) with a validation
26//! pipeline that ensures security and provides human-readable explanations.
27//!
28//! ## Architecture
29//!
30//! ```text
31//! describe_schema() → LLM generates code → validate_code() → user approval → execute_code()
32//! ```
33//!
34//! ## Key Components
35//!
36//! - **Validation Pipeline**: Parse → Policy Check → Security Analysis → Explanation → Token
37//! - **Approval Tokens**: HMAC-signed tokens binding code hash to validation result
38//! - **Explanations**: Template-based business-language descriptions of queries
39//! - **Policy Evaluation**: Pluggable trait for Cedar/AVP/custom policy engines
40//!
41//! ## Example Usage
42//!
43//! ```ignore
44//! use pmcp_code_mode::{
45//! CodeModeConfig, ValidationPipeline, ValidationContext
46//! };
47//!
48//! // Create a validation pipeline
49//! let config = CodeModeConfig::enabled();
50//! let pipeline = ValidationPipeline::new(config, b"secret-key".to_vec());
51//!
52//! // Validate a query
53//! let context = ValidationContext::new("user-123", "session-456", "schema-hash", "perms-hash");
54//! let result = pipeline.validate_graphql_query("query { users { id name } }", &context)?;
55//! ```
56
57// High-level CodeExecutor trait (always available, no feature gate)
58mod code_executor;
59
60pub mod config;
61mod explanation;
62mod graphql;
63pub mod handler;
64mod token;
65mod types;
66pub mod validation;
67
68// Code Mode instruction and policy templates
69pub mod templates;
70
71// Schema Exposure Architecture - Three-Layer Schema Model
72pub mod schema_exposure;
73
74// Policy evaluation framework
75pub mod policy;
76
77// Cedar policy annotation parsing (no AWS dependency)
78pub mod policy_annotations;
79
80// Cedar schema and policy validation (test only)
81#[cfg(test)]
82pub mod cedar_validation;
83
84// JavaScript validation for OpenAPI Code Mode (requires SWC parser)
85#[cfg(feature = "openapi-code-mode")]
86mod javascript;
87
88// Static class policy for OpenAPI Code Mode (enforced without an evaluator)
89#[cfg(feature = "openapi-code-mode")]
90pub mod openapi_policy;
91
92// SQL validation for SQL Code Mode (requires sqlparser)
93#[cfg(feature = "sql-code-mode")]
94pub mod sql;
95
96// AWS Verified Permissions policy evaluator
97#[cfg(feature = "avp")]
98pub mod avp;
99
100// JavaScript execution runtime (AST-based execution in pure Rust)
101#[cfg(feature = "js-runtime")]
102pub mod executor;
103
104// Shared expression evaluation logic (used by both sync and async executors).
105//
106// `pub` (rather than the original `mod`) so that `tests/eval_semantic_regression.rs`
107// can pin the JsonValue output of `evaluate_with_scope` and
108// `evaluate_array_method_with_scope` against representative ValueExpr programs
109// (Phase 75 Wave 0 Task 2 — regression contract for Wave 3's mandatory cog 123/117 → ≤25 refactor).
110//
111// Why public: the eval functions need to be directly callable from a separate
112// `tests/` integration target so the snapshot can detect semantic drift. Making
113// the module `pub` is the smallest change that exposes the symbols; alternative
114// (per-symbol re-export at the crate root) would clutter the public surface
115// with internal helpers like `is_truthy` / `to_number` / `evaluate_binary_op`.
116#[cfg(feature = "js-runtime")]
117pub mod eval;
118
119// Re-export async_trait to avoid version conflicts in derive macro output (D-07)
120pub use async_trait::async_trait;
121
122/// The D4 path-placeholder floor, re-exported from core `pmcp`.
123///
124/// There is exactly **ONE** implementation of these rules and it lives in
125/// `pmcp::server::schema_validation`. This is a `pub use`, never a second copy
126/// (Phase 128, Q2). Two reasons the home is core rather than here:
127///
128/// 1. The toolkit's curated `http` build has no `pmcp-code-mode` edge and must
129/// not gain one (SC-1), so the shared rule cannot live in this crate.
130/// 2. This repo has a documented three-way-drift incident from a security rule
131/// that existed in more than one copy, so a second denylist is a prohibited
132/// shape rather than a style preference.
133///
134/// The re-export exists because D-09 obliges the SDK to publish the helper under
135/// the name a third-party `HttpExecutor` implementor would look for. An
136/// implementor whose template syntax is not OpenAPI's `{key}` can call
137/// `pmcp_code_mode::validate_path_placeholder` on each value it substitutes and
138/// `pmcp_code_mode::validate_resolved_path` on the composed result — or
139/// `pmcp_code_mode::validate_resolved_target`, which is that rule widened by the
140/// single author-written `?` separator, and is what `ResolvedPath::from_checked`
141/// itself calls. Either reaches the
142/// same rule the SDK itself applies before calling
143/// `HttpExecutor::execute_request`. (Plain backticks, not an intra-doc link:
144/// `executor` is gated on `js-runtime` and the link would not resolve in a
145/// default-feature doc build.)
146pub use pmcp::server::schema_validation::{
147 validate_path_placeholder, validate_resolved_path, validate_resolved_target,
148 PlaceholderRefusal, PlaceholderRules, PLACEHOLDER_MAX_LENGTH,
149};
150
151// High-level CodeExecutor trait (always available, no feature gate) (D-04)
152pub use code_executor::CodeExecutor;
153
154// Re-export public types
155pub use config::{resolve_server_id_from_env, CodeModeConfig};
156
157pub use explanation::{ExplanationGenerator, TemplateExplanationGenerator};
158
159pub use graphql::{GraphQLOperationType, GraphQLQueryInfo, GraphQLValidator};
160
161// JavaScript/OpenAPI Code Mode exports
162#[cfg(feature = "openapi-code-mode")]
163pub use javascript::{
164 ApiCall, HttpMethod, JavaScriptCodeInfo, JavaScriptValidator, OutputDeclaration,
165 SafetyViolation, SafetyViolationType,
166};
167
168// SQL Code Mode exports
169#[cfg(feature = "sql-code-mode")]
170pub use sql::{SqlStatementInfo, SqlStatementType, SqlValidator};
171
172// JavaScript execution runtime exports
173#[cfg(feature = "js-runtime")]
174pub use executor::{
175 filter_blocked_fields, find_blocked_fields_in_output, ApiCallLog, ArrayMethodCall,
176 BinaryOperator, BuiltinFunction, CompileError, ExecutionConfig, ExecutionPlan, ExecutionResult,
177 HttpExecutor, JsExecutor, MockExecutionMode, MockHttpExecutor, MockedCall, PathPart,
178 PathTemplate, PlanCompiler, PlanExecutor, PlanMetadata, PlanStep, ResolvedPath, SdkExecutor,
179 UnaryOperator, ValueExpr,
180};
181
182// Standard CodeExecutor adapters (bridge low-level traits to derive-macro-compatible API)
183#[cfg(feature = "js-runtime")]
184pub use code_executor::{JsCodeExecutor, SdkCodeExecutor};
185
186// MCP Code Mode executor
187#[cfg(feature = "mcp-code-mode")]
188pub use executor::McpExecutor;
189
190#[cfg(feature = "mcp-code-mode")]
191pub use code_executor::McpCodeExecutor;
192
193pub use token::{
194 canonicalize_code, compute_context_hash, hash_code, ApprovalToken, HmacTokenGenerator,
195 TokenGenerator, TokenSecret,
196};
197
198pub use types::{
199 CodeLanguage, CodeLocation, CodeType, Complexity, ExecutionError, PolicyViolation, RiskLevel,
200 SecurityAnalysis, SecurityIssue, SecurityIssueType, TokenError, UnifiedAction, ValidationError,
201 ValidationMetadata, ValidationResult,
202};
203
204pub use validation::{ValidationContext, ValidationPipeline};
205
206// Code Mode templates
207pub use templates::TemplateContext;
208
209// Code Mode handler trait and utilities
210pub use handler::{
211 format_error_response, format_execution_error, CodeModeHandler, CodeModeToolBuilder,
212 ExecuteCodeInput, ValidateCodeInput, ValidationResponse,
213};
214
215// Policy types re-exports
216pub use policy::{
217 get_baseline_policies, get_code_mode_schema_json, AuthorizationDecision, NoopPolicyEvaluator,
218 OperationEntity, PolicyEvaluationError, PolicyEvaluator, ServerConfigEntity,
219};
220
221#[cfg(feature = "openapi-code-mode")]
222pub use policy::{
223 get_openapi_baseline_policies, get_openapi_code_mode_schema_json, normalize_operation_format,
224 normalize_path_to_pattern, OpenAPIServerEntity, ScriptEntity,
225};
226
227#[cfg(feature = "sql-code-mode")]
228pub use policy::{
229 get_sql_baseline_policies, get_sql_code_mode_schema_json, SqlServerEntity, StatementEntity,
230};
231
232// Cedar policy evaluator
233#[cfg(feature = "cedar")]
234pub use policy::cedar::CedarPolicyEvaluator;
235
236// AVP (AWS Verified Permissions) policy evaluator
237#[cfg(feature = "avp")]
238pub use avp::{AvpClient, AvpConfig, AvpError, AvpPolicyEvaluator};
239
240// Schema Exposure Architecture types
241pub use schema_exposure::{
242 CodeModeExposurePolicy, DerivationMetadata, DerivationStats, DerivedSchema, ExposureMode,
243 FilterReason, FilteredOperation, GlobalBlocklist, McpExposurePolicy, MethodExposurePolicy,
244 Operation, OperationCategory, OperationDetails, OperationParameter, OperationRiskLevel,
245 SchemaDeriver, SchemaFormat, SchemaMetadata, SchemaSource, ToolExposurePolicy, ToolOverride,
246};