Generator MCP Design Rationale¶
This document explains what the AI integration does, why its boundaries exist, and where each responsibility lives in the codebase. Use MCP Permissions for the complete current tool inventory and required process, database and review rights.
Objective¶
The default review-first AI workflow should inspect a source safely, create a reviewable generation contract, generate deterministic synthetic data, validate it, and export it without receiving production rows or gaining unrestricted filesystem or database access.
The implementation keeps planning and orchestration in the AI layer while all generation and validation decisions remain deterministic Python code.
The explicit opt-in row-returning tool run_safe_select is intentionally
narrower than an arbitrary read-only SQL client. It requires a literal bounded
LIMIT, rejects unrestricted projections and likely sensitive fields, and also
rejects joins, CTEs, subqueries, ordering, table functions, and UNNEST.
It masks every returned string, including heuristic false negatives. Other
non-string source values may remain, so default aggregate-only tools should be
used for profiling.
Why Two MCP Servers¶
The integration deliberately separates source inspection from generation:
mcp_trino_server.pyhas read-only access to an allowlisted Trino surface.- the ordinary synthetic tools in
mcp_generator_server.pyuse a configured local workspace and need no database connection.
This separation follows least privilege. Database credentials do not need to be available to the generator, and the Trino server does not need permission to write output files. A compromised or mistaken tool call therefore has a smaller blast radius.
The separate configured SQL transformation session can capture an authorized database into owned temporary snapshots. It requires additional adapter, network, database and storage rights plus its own activation acceptance; it is outside the aggregate-profile-to-synthetic pipeline below. A local process inherits its OS user's rights; the workspace setting alone is not a sandbox.
Trino or CSV
|
v
Safe profile metadata
|
v
DatasetSpec 1.1 (legacy 1.0 remains readable)
|
v
Human review + fresh consent for the exact current spec
|
v
Deterministic generator
|
v
Schema + relationship + constraint validation
|
v
Synthetic files + effective spec + report + manifest
Only safe profile metadata crosses the source/generator boundary: names, types, null ratios, cardinalities, ranges, non-sensitive categories, and masked patterns. Source rows and raw sensitive values do not cross it.
Tool Logic¶
The generator rights table
describes all 14 console-registered tools, their inputs, effects and approvals.
The console entrypoint owns the workspace and session lifetime; the module-level
SDK object has only the 12 base tools. Transformation activation/release
acceptance is separate from registration. The ordinary
approve_dataset_plan receipt is not a source-preservation receipt and cannot
authorize transformation preservation; MCP has no preservation approval issuer.
export_dataset intentionally regenerates data from a DatasetSpec. It does
not accept arbitrary row files, because a generic conversion tool could be used
to export production data.
Data Flow¶
Trino Source¶
- The AI calls allowlisted metadata and aggregate profiling tools in
mcp_trino_server.py. - The Trino server returns a compact safe profile payload.
- The AI passes that payload to
plan_trino_datasetasprofile_payload, with an explicit workspace, count and seed. - The generator server validates the profile, writes a versioned spec and stops before generation.
- The client inspects the plan, presents the full current
dataset_spec.yamlfor human review and obtains fresh, explicit consent for that exact file. - After rechecking the file and fingerprint, it calls
approve_dataset_planwithreviewed_spec_sha256frominspect_dataset_plan.
No local copy of the source table is required.
CSV Source¶
- The CSV must be inside
TEST_DATA_AGENT_WORKSPACE_ROOT. plan_datasetdetects a CSV file or folder and invokes safe profiling.- Sensitive columns retain masked patterns, never raw top values.
- The agent writes a reviewable generation contract and stops for approval.
- The client inspects the plan, presents the full current specification and
obtains fresh, explicit human consent. It rechecks the file and fingerprint
before calling
approve_dataset_planwith that reviewed fingerprint. - Approved generation uses distributions and a seed, not source-row shuffling. Editing the file requires another review and new consent; a summary or fingerprint alone is not human specification acceptance.
The lower-level profile_csv and infer_dataset_spec tools remain available
when a client needs explicit control over intermediate artifacts. These are
lower-level operations, rather than the persisted review-first plan lifecycle.
See MCP usage for the consent and resume procedure.
Direct CSV and example-folder workflows compare complete generated rows against the source before writing output. An exact match stops generation without including the matched values in the error.
Safety Decisions¶
Workspace Boundary¶
Ordinary generator MCP tool paths are resolved against
TEST_DATA_AGENT_WORKSPACE_ROOT. Paths outside that root are rejected after
resolution, which also blocks traversal through existing symlinks.
Owned runtime temporary storage and separately configured audit/authentication
files have different locations; see minimum process rights.
MCP output files must be new, and generation folders must be new or empty. This prevents accidental overwrites and avoids mixing a new synthetic dataset with stale files from an earlier run.
Implementation: src/test_data_agent/mcp_generator_server.py.
Shared Deployment Audit¶
Both MCP servers can write metadata-only, HMAC-authenticated audit events when the operator configures an audit path and key. Audit records never contain tool arguments, SQL, profiles, rows, return values, or exception messages. Invalid audit configuration prevents tool execution. See MCP Audit Logging.
Safe Profiles¶
Fields marked sensitive, or inferred as sensitive from their name or semantic
type, may use masked-pattern or synthetic-identifier distributions. Sensitive
integer/float fields also support coarse numeric_shape or a numeric
distribution with a non-identity scale factor. Raw categorical distributions
for sensitive fields are rejected; exact sensitive Trino extrema and percentiles
are not accepted as safe profiles.
Implementation: src/test_data_agent/safety.py and
src/test_data_agent/generation/planner.py.
Synthetic Sensitive Values¶
Sensitive values are generated independently from the source. Emails use the
reserved example.test domain, phones use a fictional 555 range, and SSN-like
values use an invalid 000 prefix.
Implementation: src/test_data_agent/generation/entity_generator.py.
No Rows In MCP Responses¶
Generator tools write datasets to the workspace and return only paths, row counts, versions, and validation results. This keeps large payloads out of the model context and reduces the chance of accidental disclosure in prompts, logs, or chat history.
Business-rule generation follows the same boundary. Direct generate_dataset
and export_dataset responses include the rule fingerprint, rule/pass fail
counts, validity, truncation status and business_validation_report_path.
approve_dataset_plan returns its compact generation summary and bundle paths;
the rule summary and report remain in the hashed workspace bundle rather than
separate response keys. Bounded, value-free rule diagnostics remain in that
artifact.
Structured Business Rules¶
Business rules may be embedded in the reviewed DatasetSpec, so the same
rules reach deterministic generation, review-first approval, validation and
export regardless of the source or output adapter. generate_dataset and
export_dataset also accept one workspace business_rules_path or inline
business_rules_payload when the spec has no embedded rules. Combining rule
sources is rejected; supplied rules are saved in the effective spec.
Rule models forbid
unknown fields, cap list and expression sizes, and permit only constants,
field names, basic arithmetic, and explicit sum/count aggregate helpers.
The server also rejects requests whose DatasetSpec row counts and rule set
would exceed the configured estimated evaluation budget.
Before generation, rules/contract.py verifies every entity and field
reference against the DatasetSpec. Literal assignments and comparisons against
sensitive fields fail closed. Other literals undergo the shared content, size
and type checks, including exact DECIMAL shape validation and its explicitly
reviewed non-sensitive numeric_measure handling. No output folder is
published when this boundary fails.
Provenance Manifest¶
Every generated bundle includes generation_manifest.json with:
- package version
- DatasetSpec schema version
- SHA-256 fingerprint of the effective spec
- seed and output format
- row counts
- validation status
- optional business-rule fingerprint, rule count, pass/fail counts, validity, and error-truncation status
synthetic: truesource_rows_copied: false
The MCP validation tool requires this manifest and checks that its fingerprint
matches the supplied effective spec. Manifest output hashes also bind the data,
validation artifacts and any business_validation_report.json; missing or
changed bound artifacts fail validation. This prevents validating a bundle
against an unrelated contract or accepting a deleted rule report.
Implementation: src/test_data_agent/io/artifacts.py.
Review-first agent generation also writes approval_receipt.json beside the
workspace plan. The receipt binds the random plan identifier and safe-profile
fingerprint to the exact effective-spec fingerprint confirmed by the caller.
The fingerprint is recomputed immediately before generation; mismatches fail
without publishing output.
Why DatasetSpec Is Versioned¶
DatasetSpec is the contract between the AI planner and deterministic code.
Newly constructed specs use schema_version: "1.1"; readers explicitly support
both 1.0 and 1.1. The serialized version permits evolution without silently
changing old contracts. Exact decimal fields require 1.1 and their declared
precision/scale and decimal_range; they cannot be silently read as floats.
Both supported versions validate:
- unique entity and field names
- valid primary-key references
- relationship entity/field references
- constraint entity/field references
- scoped privacy-rule references
Older specs without schema_version load as version 1.0 for compatibility.
Package version and spec schema version are independent.
Implementation: src/test_data_agent/core/dataset.py and
src/test_data_agent/core/entity.py.
Why The Effective Spec Is Saved¶
Generation may override the seed, count, or output format supplied in the
original spec. The output folder therefore receives an effective
dataset_spec.yaml containing the values actually used. Validation and the
manifest fingerprint refer to this effective spec, making a run reproducible.
Implementation: src/test_data_agent/io/workflows.py.
Output Location¶
For an output folder such as generated/orders_run, the bundle is:
generated/orders_run/
dataset_spec.yaml
generation_manifest.json
validation_report.json
orders.csv
customers.csv
There is one data file per entity. The extension is selected by the requested
CSV, JSON, SQL, or Parquet format. plan_dataset exposes CSV, JSON and Parquet
selection; plan_trino_dataset and direct generation/export also accept SQL.
See the
source/output matrix for interface details.
Module Ownership¶
core/: versioned Pydantic domain contracts.adapters/: conversion of safe CSV, Trino, JSON, and older profile metadata.profiling/: schema, distribution, relationship, and constraint inference.generation/: seeded row generation and deterministic constraint solving.validation/: executable schema, relationship, and constraint checks.io/: artifact reading, writing, manifests, and reusable workflows.safety.py: profile and source-row reuse invariants.mcp_trino_server.py: read-only source-side tools.mcp_generator_server.py: workspace-side AI tools.scripts/run_ai_demo.py: local profile-to-CSV demonstration.
Alternatives Intentionally Rejected¶
These restrictions describe the ordinary aggregate-profile-to-synthetic pipeline. Separately registered mixed-origin transformation consumers remain behind their distinct snapshot, classification and local-receipt contracts; this pipeline grants them no source-preservation authority.
- One MCP server with both database credentials and broad filesystem access.
- Arbitrary unrestricted SQL tools.
- Returning raw or generated datasets directly in MCP responses.
- Giving the planning client the explicit opt-in row-returning tool
run_safe_select; it is not needed byprofile_table_safe->plan_trino_dataset. - Exporting or converting arbitrary row files.
- Building output by copying, shuffling, or duplicating source rows.
- Treating free-form LLM reasoning as validation.
These alternatives are convenient, but they weaken isolation, auditability, or the guarantee that output is synthetic.
Verification¶
The main coverage is in:
tests/test_mcp_generator_server.pytests/test_safety.pytests/test_ai_trino_workflow.pytests/test_dataset_spec_contract.pytests/test_domain_agnostic_pipeline.py
The local end-to-end demo is:
python3 scripts/run_ai_demo.py \
--profile examples/trino_safe_profile.json \
--output out/ai_demo \
--count 100 \
--seed 12345