pub struct ProxyState {
pub registry: ManifestRegistry,
pub skill_registry: SkillRegistry,
pub keyring: Keyring,
pub jwt_config: Option<JwtConfig>,
pub jwks_json: Option<Value>,
pub auth_cache: AuthCache,
pub upstream_url_allowlists: Arc<Mutex<HashMap<String, Option<Vec<UpstreamAllowEntry>>>>>,
pub lazy_schema_cache: LazySchemaCache,
}Expand description
Shared state for the proxy server.
Fields§
§registry: ManifestRegistry§skill_registry: SkillRegistry§keyring: Keyring§jwt_config: Option<JwtConfig>JWT validation config (None = auth disabled / dev mode).
jwks_json: Option<Value>Pre-computed JWKS JSON for the /.well-known/jwks.json endpoint.
auth_cache: AuthCacheShared cache for dynamically generated auth credentials.
upstream_url_allowlists: Arc<Mutex<HashMap<String, Option<Vec<UpstreamAllowEntry>>>>>Per-provider upstream-URL allowlists, compiled lazily on first
per-request validation and cached for the process lifetime. Keyed
by provider name. None value = keyring entry missing; we cache
negatives too to avoid repeating the lookup on every request.
Operator hot-reload of an allowlist requires proxy restart (same
constraint as every other keyring entry today). See issue #124.
Entries are pre-parsed UpstreamAllowEntry structs (scheme + host
glob + canonical path) rather than raw URL glob patterns. Glob over
raw URL strings is unsafe — * can cross ., #, ?, : and other
URL delimiters, letting a sandbox-crafted URL satisfy a pattern while
reqwest connects to a different host. Greptile P0/P1 on #124.
lazy_schema_cache: LazySchemaCacheLazy-discovered MCP inputSchema cache for sandbox-supplied-URL
providers (issue #135).
For providers with handler = "mcp" + mcp_url_env set, the URL
isn’t proxy-resident so we cannot discover tools at boot; operators
must declare tool names statically in the manifest, but the
schemas are gaps unless they mirror them by hand. This cache
holds schemas fetched on demand via tools/list against the
sandbox-supplied upstream when an ati tool info / tools/list
request asks for one and the static entry has input_schema: None.
Keyed by (provider_name, upstream_url) so different sandboxes
pointed at different upstreams each get their own cache entry.
Value is Option<HashMap<tool_name, inputSchema>>:
Some(map)— fetched successfully; servemap[tool_name].None— fetched and the dial / list failed; remember the negative result so we don’t re-attempt on every subsequent request. Cache lives for the process lifetime (matching the allowlist cache; operator hot-reload requires restart).
Lookup never blocks a response: a discovery miss falls back to
the static Tool.input_schema (which is None in the exact case
this cache exists to handle), preserving today’s behavior.