Skip to content

v5.2.0 - Retrieval (RAG), MCP Subscriptions & Elicitation, Agent Hardening

Choose a tag to compare

@AdrianCurtin AdrianCurtin released this 04 Jun 16:12
· 34 commits to main since this release
476a181

Feature Release

Adds a safe-by-default retrieval (RAG) layer with an agent semantic_search tool, MCP resource subscriptions bridged to LiveQuery, human-in-the-loop approval for destructive tool calls via MCP elicitation, agent impersonation and prompt hardening, bounded idempotency-aware client retries, and a fully isolated Docker integration stack. Also corrects pointer/relation targetClass resolution for built-in system classes.

Changes

Retrieval layer: Parse::Retrieval (Parse::RAG)

  • NEW: Parse::Retrieval.retrieve(query:, klass:, field:, k:, filter:, vector_filter:, chunker:, tenant_scope:, score_quantize:, **scope_opts) embeds a query, runs Atlas $vectorSearch through the ACL/CLP-enforcing find_similar, and splits each retrieved document into scored, citable Parse::Retrieval::Chunks. Embedding stays one-vector-per-record; chunking is a post-retrieval presentation step. A merged tenant scope closes the cross-tenant existence side channel.
  • NEW: Parse::Retrieval::Chunker::FixedSizeOverlap(size:, overlap:, by:, max_chunks_per_document:) sliding-window chunker (by: :chars default, or :tokens), subclassable from Chunker::Base. The per-document cap truncates with a signal rather than raising.
  • NEW: agent_searchable field:, filter_fields: model macro opts a class into the agent retrieval tool and declares the fields an agent may filter on.
  • NEW: semantic_search agent tool (permission: :readonly, client_safe: true) with the full security envelope — searchable-class allowlist, recursive underscore-key refusal, filter-field allowlist, field_allowlist projection, tenant-scope re-assertion on every returned record, and score quantization in non-admin contexts. text_field: disambiguates multi-embed models, constrained to the class's declared embed sources.
  • NEW: Parse::RAG discoverability alias; rerank: / hybrid: reserved on retrieve (raise NotImplementedError) to lock the API shape.

MCP elicitation: human-in-the-loop approval for destructive operations

  • NEW: Parse::Agent.require_approval_for = [:write, :admin] opts tiers into approval (off by default). A pluggable Parse::Agent#approval_gate is consulted by #execute with the dry-run diff; NullGate is the default and MCPElicitationGate the spec-native (MCP 2025-06-18 elicitation/create) implementation.
  • NEW: call_method resolves the effective tier from the target method's declared permission, so write/admin methods invoked through the readonly call_method tool are gated correctly.
  • SECURITY: Fails closed — a missing client capability, no open listening stream, a non-streaming transport, or an approver timeout all refuse the operation rather than executing it. Replies are session-bound so one session cannot answer another's prompt.

MCP resource subscriptions bridged to LiveQuery

  • NEW: Opt-in MCP resource subscriptions backed by Parse LiveQuery.
  • SECURITY: Class authorization (agent_hidden / per-agent allowlist + CLP) is enforced before any socket opens; AccessDenied maps to JSON-RPC -32602. A master-key (admin) LiveQuery branch requires the agent's own client to present a usable master key. Subscription state is re-checked and stored under a lock to avoid resurrecting torn-down sessions, duplicates, or cap breaches. A process-wide session cap and a listening-stream soft cap bound resource growth.

Agent roadmap: impersonation, prompt hardening, telemetry, provenance

  • NEW: Agent impersonation — Parse::Agent.new(impersonate_user:, impersonate_mint:, impersonation_label:) and agent.impersonate(user) / stop_impersonating! resolve a real _Session token for a _User (reusing an active session or minting a restricted one). Fails closed: requires a master-key client, rejects non-_User pointers, and refuses rather than widening to master-key posture when no session resolves. The audit label surfaces on the parse.agent.tool_call payload.
  • SECURITY: Aggregate tools (aggregate, group_by, distinct, pipeline export) route through the ACL-enforcing mongo-direct path for ANY non-master identity — session-token and impersonated agents included — closing the unenforced REST-aggregate gap.
  • NEW: Parse::Agent::PromptHardeningsanitize_schema_for_llm (drops non-identifier field names, strips control/zero-width chars, caps and marker-wraps descriptions), scrub_marker_injection with a prompt_marker_strict refuse mode, operator-curated prompt_injection_canaries (emit telemetry or refuse), a surfaced PROMPT_VERSION, and an allowed_llm_endpoints origin allowlist with a one-time unrestricted-endpoint warning. Adds embedding-cost telemetry and optional per-row source provenance.

unique_index_on: declarative correctness floor for first_or_create!

  • NEW: Model-level unique_index_on helper (non-sparse by default) as the correctness floor for first_or_create! / create_or_update!.
  • IMPROVED: Mutex-guarded index registry refactor avoids duplicate createIndex declarations under concurrent class loading.

Fix wrong pointer/relation targetClass for built-in system-class associations

  • FIXED: Built-in class associations now resolve correctly regardless of load order. SYSTEM_CLASS_MAP and a String#to_parse_class fallback to underscored storage names (e.g. _User) prevent pointer/relation targetClass from freezing the literal "User" and correct the emitted schema.
  • CHANGED: _Installation CLP advisory is operation-aware — warns only for server-ignored operations (find/create/update/delete) and stays silent for effective ops.

Hardened constraint and $relatedTo handling

  • IMPROVED: Per-key operator validation, explicit $relatedTo owning-class accessibility checks on the agent and mongo-direct paths, and clearer errors for mongo-direct $relatedTo.

Schema migration: correct wire-column names and convergence check

  • FIXED: type_mismatches iterates the model's field_map to resolve custom wire names instead of camelizing property names; transient schema-fetch failures no longer cache a fallback.
  • NEW: One-way server_covers_local? convergence check.

Aggregation and connectivity probes

  • NEW: group_by class-method delegators and operation-aware table headers.
  • CHANGED: Parse.connected? probes the health endpoint by default (reports reachable even under hardened CLP); adds Parse.reachable? and an endpoint parameter for data-class credential validation.

Parse::Client#request: bounded, idempotency-aware retries

  • FIXED: Infinite retry loop removed; retry budget is hoisted and exponential-backoff math is correct (positive backoff with jitter) when callers override the retry count.
  • CHANGED: Retries are idempotency-aware — GET/DELETE always, PUT only without an atomic __op, POST never for ambiguous failures, 429 always. Adds an opt-in idempotent-retry mode with a stable X-Parse-Request-Id, Parse::Error::DuplicateRequestError, and replay recovery in first_or_create / create_or_update. Also retries on Faraday::TimeoutError.

Token economy and integration coverage

  • IMPROVED: Leaner tool surface, responses, and retrieval payloads; new integration coverage for retrieval, elicitation/approval, subscription authorization, retry/idempotency/connectivity, prompt hardening, and resource caps. bundler-audit added to the development/test bundle.

Test infrastructure

  • CHANGED: The integration stack moved to a dedicated 29xxx host-port block and is namespaced via PSNEXT_PREFIX (default psnext-it) — Compose project, container names, and volumes — so it never collides with another Parse instance on the host. Adds .env.test defaults and README usage/troubleshooting notes.

Commit: 476a181
Author: Adrian Curtin
Date: June 4, 2026