misata-mcp
The Misata MCP server lets agents create, inspect, validate, audit, and test synthetic datasets and databases.
List built-in domains and preview/inspect how a natural-language story will be interpreted before generating.
Generate reproducible CSV datasets from a plain-English story or an explicit schema, with constraints, foreign keys, rollups, curves, shares, lifecycles, correlations, and exact incidences.
Validate
misata.yamlstructurally and semantically before generation.Create and seed an isolated SQLite sandbox, then run read-only SQL queries against it.
Plan and optionally apply seeding of real PostgreSQL/SQLite databases; writes require explicit
apply, withtruncate/appendsafety controls.Audit existing CSV datasets for contradictions and synthetic-data tells, and validate values against clinical/financial domain plausibility rules.
Return useful metadata such as file paths, row counts, sample rows, integrity proofs, audit scores, and findings.
Misata
Declare what must be true. Get data that makes it true. Prove it.
Misata is a declarative synthetic data generator for Python. You write down the facts a dataset has to satisfy, from a monthly revenue curve to a balanced ledger to a foreign key that must never dangle, and the engine builds multi-table data that satisfies all of them at once. Then DuckDB checks the files on disk and writes a certificate anyone can re-run.
Docs · Use cases · The language · Limitations · Studio · Changelog
Sixty seconds
pip install "misata[duckdb]"# misata.yaml
seed: 7
tables:
customers:
rows: 2000
columns:
customer_id: {type: int, unique: true, min: 1, max: 2000}
name: {type: text, text_type: name}
signed_up: {type: date, start: "2024-01-01", end: "2024-12-31"}
orders:
rows: 40000
columns:
order_id: {type: int, unique: true, min: 1, max: 1000000}
customer_id: {type: foreign_key}
channel: {type: categorical, choices: [web, app, store]}
amount: {type: float, min: 5, max: 900}
ordered_at: {type: date, start: "2025-01-01", end: "2025-12-31"}
relationships:
- customers.customer_id -> orders.customer_id
outcome_curves:
- table: orders
column: amount
time_column: ordered_at
start_date: "2025-01-01"
curve_points:
- {month: 1, target_value: 180000}
- {month: 6, target_value: 240000}
- {month: 12, target_value: 310000}
group_shares:
- table: orders
measure: amount
group_column: channel
shares: {web: 0.5, app: 0.3, store: 0.2}misata generate -c misata.yaml -o data --attest
python data/verify.pyAttestation: data
result: PASSED
files pinned: 2
invariants held: 69 of 69
ok 2 file(s) match their attested sha256
ok 69 of 69 invariant(s) holdThe 69 are derived from the YAML before a row exists: twelve monthly revenue
totals (180,000.00 in January, 240,000.00 in June, 310,000.00 in December,
straight lines between), the channel split inside every one of those months,
the planned row count per month, zero orphaned customer_ids and unique keys.
verify.py needs only the standard library and duckdb, and it shares no
code with the generator.
The YAML above, generated and summed by month and channel. Each bar is a month of generated revenue split by channel; the cap is the total the YAML declares. Drawn by readme_charts.py from a fresh run of this README's own YAML.
Change one cent in one row and it says so:
FAIL orders.csv: sha256 301165f9dc4e does not match the attested 670f89195826
FAIL orders.amount.month:1.outcome_curve_period: expected 180000.00, observed 180000.01
FAIL orders.amount.outcome_curve_total: expected 2945000.00, observed 2945000.01
FAIL orders.amount.web.2025-01.group_share_period: expected 90000.00, observed 90000.01
FAIL orders.amount.web.group_share_total: expected 1472500.00, observed 1472500.01
FAIL 65 of 69 invariant(s) holdRelated MCP server: MCP Data Visualization Server
Why declare instead of generate
Every test fixture has an oracle problem. To check a dbt model, a Spark job, a dashboard tile or a data agent you need input data and an answer you know independently of the code under test. Copying production gives you data without an answer. Hand-written fixtures give you an answer that rots. Random generators give you data whose answer you have to compute with the code you are testing.
Misata turns it around. The specification is the ground truth and the rows are derived from it. "January revenue is 180,000" is true before a single row exists, so your pipeline either returns 180,000.00 or it has a bug.
flowchart LR
A["Declare<br/>curves, shares, ledgers,<br/>keys, lifecycles"] --> B{"Can they<br/>all hold?"}
B -- "no" --> R["Refused, with the<br/>arithmetic and a fix"]
B -- "yes" --> C["Build rows<br/>closed form where it can,<br/>by construction elsewhere"]
C --> D["Write<br/>CSV, Parquet, JSONL,<br/>DuckDB, Postgres"]
D --> E["Attest<br/>DuckDB re-runs every<br/>derived invariant"]
E --> F["Certificate<br/>in-toto Statement<br/>plus verify.py"]Three properties make this different from a generator with options:
A declaration is honoured or refused, never quietly replaced. Declarations that cannot all hold stop generation with an error that names each one, shows the arithmetic and suggests the change.
The certificate is checked by code that did not write the data. A bug in Misata's arithmetic shows up as a failed invariant, not a self-consistent wrong answer.
The same spec, seed and version give the same bytes on Linux, macOS and Windows, so a fixture can live in git with its fingerprint.
Where this is going
Misata's aim is that nobody writes a Python script to make a dataset, of any kind. You say what has to be true; the engine works out the rows, refuses what cannot hold, and proves what it built.
It is not there yet, and it is getting there brick by brick. Each release adds things you can declare instead of programming, and a brick is laid only when it passes three tests: it can be declared in a few lines of YAML, it is refused before generation when it contradicts another declaration, and it is re-checked on the rows afterwards by code that did not write them.
Every brick is something you declare instead of code. Drawn from misata/registry.py, the list a contract test holds the code to, so the wall cannot claim a brick the engine does not have.
One fact, two ways. What a script has to do to make a fact true, and what you write instead:
The fact | In a generator script | In Misata |
January revenue is 180,000.00 | draw amounts, sum them, rescale, round, chase the last cent |
|
web is half of every month's revenue | rescale inside each month and channel, then repair the monthly totals you just broke |
|
every order has a real customer | sample ids from the parent table and keep both in step |
|
some churned customers were active first | branch on status, write timestamps in order, null the rest, count by hand |
|
1% of transfers form laundering patterns, in a set mix | build each ring and fan by hand, then prove the background has no cycle of its own |
|
the trial balance is zero | post both legs of every entry and reconcile at the end | a |
What still takes code, and where each one stands:
Still scripted by hand | Where it stands |
The expected output of logic Misata cannot invert: window functions, custom SQL, business rules |
|
Correlations you can only describe by example |
|
Free text with a voice of its own | text is generated from grammars and agrees with its row; prose that reads as written is not declarable yet |
Version histories (SCD2) and inventory trajectories | generated to balance, not yet declared step by step |
Documents, images and audio | not started |
LIMITATIONS.md keeps the full list. When a line leaves this table, it is because the brick that replaces it has passed all three tests.
The evidence
The Gauntlet: 13 tables and 136 SQL assertions run by DuckDB. The Faker script ties wherever a fact is about one column at a time and loses wherever columns, rows or tables have to agree. Source, rerun with python -m benchmarks.gauntlet.
A gradient-boosted classifier tries to tell generated rows from real ones; mean of five seeds. Without seeing a real row, a declared schema beats SDV trained on the real orders. On taxi trips SDV wins: blind fares are a miss. Source, numbers in summary.json.
Claim | Measured | Reproduce |
Valid by construction | 0 violations of keys, CHECK, UNIQUE, NOT NULL and self-reference trees on five DDL schemas. A per-column Faker script: 15,014 to 50,416 per schema. SDV's multi-table model trained on valid data: 3,055 to 5,557, and it refuses two of the five |
|
Conformance | 294 SQL assertions in three suites, all held: the Gauntlet 136, the Warren 110, the Ledger 48 |
|
Reproducible | identical fingerprints on Linux, macOS and Windows |
|
Scale | 10,000,000 rows across 14 tables in 36.3 s at 0.78 GB peak on an Apple M1, every foreign key checked afterwards |
|
What you can declare
Each declaration has a guarantee stated so you could test it, a list of the columns it owns, a cost and a refusal. LANGUAGE.md is the reference. All 25 declaration kinds are checked for feasibility before a row exists and re-checked on the rows afterwards; the ones marked ✓ are also in the DuckDB certificate.
Declare | What holds | Certificate |
| a measure's total per period, to the cent | ✓ |
| the share of rows flagged per period, to the nearest row | ✓ |
| each group's share of a measure inside every period | ✓ |
| debits equal credits per entry, and the trial balance is zero | ✓ |
| opening plus movements equals closing, per component | ✓ |
relationships, | no orphans, no childless parent, no key crossing a tenant | ✓ |
| no row breaks the rule | ✓ |
| a status implies its whole history: the right timestamps set, in order, and the rest null | ✓ |
| no cycle outside a planted case; each ring, fan and chain at its exact count | ✓ |
roll-ups, | parents equal their children, inventory balances, versions tile a timeline | |
| dirt at exact counts, with an answer key | |
| cohort curves, joint margins, a declared clock, logs that agree with status |
Underneath any declaration, foreign keys resolve by construction (parents are built before children), text agrees with its row, money is skewed, timestamps have a daily rhythm and a few customers place most of the orders, so the data looks like a business before you declare anything. A sentence picks one of 18 story domains, from SaaS and fintech to healthcare, logistics and streaming, each with its tables, keys and calibrated distributions.
Pick your entry point
You have | Call | Notes |
A sentence |
| fastest start; print the tables or |
YAML or a dict |
| every declaration holds, or it refuses |
SQL DDL |
| NOT NULL, UNIQUE, composite keys, CHECK ranges and enums, self-references |
A live database |
| introspects, inserts in one transaction, never truncates unless you pass |
A dbt project |
| fixtures from |
Prisma or Django |
| |
More rows than memory |
| yields |
A pipeline whose output must hit a number |
| drives inputs through your real dbt or Python pipeline to a declared outcome, within a stated tolerance |
A dataset to share |
| re-verifies, then uploads the data with its spec, certificate and verifier |
Real rows to imitate |
| fitted to real rows; not anonymous |
Pass a seed every time. The same seed is the same data.
Twelve recipes
Each is a folder with the schema, the commands, and the check that proves the
declaration held. tools/stranger.py --clean runs every command on every page
from a freshly built wheel in a clean virtualenv before each release, so the
numbers on the pages are what you will see.
Recipe | For | Proof |
app developers, coding agents | 22 invariants from three | |
analytics engineers | a dbt test that catches the last-day-of-month bug | |
founders, data leads | 291,000 rows of partitioned Parquet, 80 invariants | |
sales engineers, PMs | churned and healthy accounts, a few whales; realism 0.96 | |
AI labs, eval teams | text-to-SQL answers verified on three rotated databases | |
agent builders | the sandbox and the grader agree row for row | |
platform engineers | hot keys and a daily curve, keys checked before replay | |
risk and ML teams | an acyclic background and every ring at its declared count | |
finance engineering, audit | two fiscal years, 52 invariants, trial balance zero | |
hiring teams, course authors | a different answer key per candidate, each verified | |
regulated teams | staging data from production DDL, never production rows | |
DX, API and SDK teams | nested JSONL whose ids resolve across files |
A status that implies its history
Declare the state machine once and every row's timestamps follow from its status. From the demo tenant:
stateDiagram-v2
direction LR
[*] --> trialing
trialing --> active
trialing --> churned
active --> past_due
active --> churned
past_due --> churnedlifecycles:
- name: subscription
table: subscriptions
state_column: status
start_column: started_at
initial: trialing
states:
- {name: trialing}
- {name: active, timestamp: activated_at}
- {name: past_due, timestamp: past_due_at}
- {name: churned, timestamp: churned_at, terminal: true}
transitions:
- [trialing, active]
- [trialing, churned]
- [active, past_due]
- [active, churned]
- [past_due, churned]
weights: {trialing: 0.07, active: 0.6, past_due: 0.07, churned: 0.26}Of 1,200 subscriptions, exactly 720 are active, 312 churned, 84 past due and 84 still trialing: weights are counts, allocated by largest remainder, not probabilities. Every past-due row has an activation date and a past-due date, in that order and after it started; no active row has a churn date. The certificate checks both, row by row. A state reachable several ways splits its rows across every route: of the 312 churned, 156 left during the trial, 78 after being active and 78 after falling past due.
The demo tenant's 1,200 subscriptions, grouped by which timestamps are set. Six routes, and no row outside them. Drawn by readme_charts.py from the recipe's own YAML.
When it says no
$ misata explain bad.yaml
Generation would refuse: 1 conflict(s).
1 declaration cannot be satisfied together:
1. [orders.channel] group_shares on amount
declared shares sum to 1.500 (web=0.6, app=0.6, store=0.3); a share of a whole cannot exceed 1.0
→ Suggestion: scale the shares so they sum to 1.0, or drop a group. Misata will not renormalise them for you, because the result would be a specification you did not write
Nothing was generated. Change the declarations each conflict names; its remedy says how.misata explain prints the planned rows, what each declaration will write,
how many invariants the certificate will carry and every conflict, without
generating anything. Every command takes --json and prints one envelope;
exit code 3 means the declarations cannot all hold and nothing was written.
With a coding agent
The agent designs the schema, Misata does the arithmetic, and DuckDB checks it. An agent cannot certify its own output; this is how it gets an answer it did not write.
claude mcp add misata -- uvx --from "misata[mcp]" misata-mcp # Claude Code
misata mcp install --client all # Cursor, Windsurf, Claude DesktopFifteen tools: generate_from_schema, generate_dataset, explain_schema,
validate_yaml, inspect_schema, preview_story, list_domains,
validate_domain, seed_database, create_sandbox, query_sandbox,
solve_outcome, attest_dataset, audit_dataset and check_realism.
AGENTS.md tells an agent which entry point fits which job and
which claims the evidence supports.
What it is not
Misata imitates nothing unless you ask it to. It does not learn a joint
distribution from your data. If you need a statistical twin of a specific
private table, use a differentially private synthesizer with a stated
epsilon. mimic fits to real rows and is not anonymous.
It is exact for what can be declared (sums, rates, shares, roll-ups,
ledgers, keys, lifecycles) and not for arbitrary SQL. A model built on a
window function or business logic Misata cannot invert still gets coherent,
key-valid inputs, and you write the expected output. misata solve closes
part of that gap by driving inputs through your real pipeline to a declared
outcome within a stated tolerance, and the certificate says which tolerance.
Priors are English-first and US-leaning on money, and rates round to whole rows. LIMITATIONS.md has the full list and wins any argument with the rest of the docs.
Imperative | Inferential | Declarative | |
You give it | code that emits values | real data to fit | facts that must hold |
It guarantees | nothing after the fact | resemblance, approximately | the facts exactly, or a refusal |
Foreign keys | your problem | per table fine, across tables fragile | by construction |
Needs real data | no | yes | no |
Examples | Faker, Mockaroo, LLM seed scripts | SDV, learned synthesizers | Misata |
Cite
If Misata helps your work, cite the software. GitHub's Cite this repository button reads the same metadata from CITATION.cff.
@software{rasin_misata,
title = {Misata: declarative synthetic data},
author = {Rasin, Muhammed},
url = {https://github.com/rasinmuhammed/misata}
}Contribute
git clone https://github.com/rasinmuhammed/misata && cd misata
uv sync --all-extras && uv run pytest -q
python tools/stranger.py --clean # every documented command, from the built wheelA capability earns a place only if it can be declared and verified. The
conformance suites in benchmarks/ are the contract: write the assertion
first, watch it fail, then make it pass. MIT licensed.
Available Tools
15 toolsattest_datasetAttest a dataset against its schemaAIdempotent
Prove a written dataset holds what its schema declared, in a standard format.
Recomputes every invariant the schema implies (outcome-curve totals, rate
anchors, group shares, ledger identities, foreign keys, unique columns)
with DuckDB against the files, and pins each file by SHA-256. Writes
attestation.intoto.json (an in-toto v1 Statement that cosign and
GitHub's actions/attest accept), attestation.dsse.json and
verify.py into dataset_dir. Anyone can rerun python verify.py
with only duckdb installed.
Use it after generate_from_schema with the same schema and seed, and
report result to the user: PASSED means every declared property
holds in the files on disk.
Args:
dataset_dir: Folder with one <table>.csv or <table>.parquet
per table (the output_dir of generate_from_schema).
schema: The same schema dict passed to generate_from_schema.
seed: The seed used to generate, recorded in the Statement.
max_invariants: How many invariants to include in the response.
Returns:
{"ok", "result", "invariants_held", "invariants_total", "failures", "subjects", "files", "invariants"}.
| Name | Required | Description | Default |
|---|---|---|---|
| seed | No | ||
| schema | Yes | ||
| dataset_dir | Yes | ||
| max_invariants | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by naming exactly which files are written into dataset_dir (attestation.intoto.json, attestation.dsse.json, verify.py), which is the real side effect behind readOnlyHint=false. It also discloses interoperability (cosign, actions/attest) and the runtime dependency of the emitted verifier (duckdb only), and the idempotentHint=true claim is consistent with re-running against the same schema and seed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then mechanics, then Args/Returns; every paragraph earns its place. Minor waste in the Returns block, which restates keys that the existing output schema already declares.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full call contract for a 4-param tool with a nested, free-form schema object: provenance of each argument, the write side effects, and the interpretation of the PASSED/FAILED result. Since an output schema exists, the return-value coverage is more than sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the load, and it documents all four parameters in an Args block. It adds meaning the schema cannot: dataset_dir layout (one `<table>.csv`/`.parquet` per table, matching generate_from_schema's output_dir), that schema must be the same dict, that seed is recorded in the Statement, and that max_invariants caps the response payload.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: recomputes schema-implied invariants with DuckDB against the files and pins each file by SHA-256, producing in-toto/DSSE attestations. The artifact list makes the output concrete. It never distinguishes itself from the close sibling `audit_dataset`, so an agent must infer the difference between auditing and attesting.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit sequencing ("Use it after generate_from_schema with the same schema and seed") and tells the agent what to do with the result ("report `result` to the user: PASSED means every declared property holds"). No exclusion against `audit_dataset` or other validation siblings, but the precondition is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
audit_datasetAudit a dataset for reader-visible contradictionsARead-onlyIdempotent
Score a folder of CSVs for the contradictions a human reader would catch.
This is Misata's coherence audit run on data that already exists — data an agent generated in an earlier step, data a user built by hand, or the output of some other tool. It checks, among other things:
timestamps that run backwards (shipped before ordered, resolved before opened),
derived columns that do not reconcile with their inputs (
total!=quantity * unit_price),geographic fields that disagree (city / state / postcode / country),
near-constant columns (98% one value — a distribution tell),
filler text and out-of-scale numerics.
A score of 100 is clean. Below ~85 usually means the schema is missing
realism structure, not that individual rows need patching: add
__correlations__, profiles, time_series, a __state_machine__,
or an __outcome_curves__ declaration and regenerate.
Args:
dataset_dir: Directory containing one CSV per table (e.g. the
output_dir returned by generate_from_schema).
top_findings: Max findings to include in the response (default 20).
Returns:
{"score": 0-100, "clean": bool, "counts": {...}, "findings": [...]}.
| Name | Required | Description | Default |
|---|---|---|---|
| dataset_dir | Yes | ||
| top_findings | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations (readOnly, openWorld, idempotent, non-destructive) already cover the safety profileestr; the description adds real behavioral context on top: what kinds of contradictions it detects, that scores below ~85 indicate schema issues rather than data issues, and the recommended remediation path. It also specifies the top_findings cap and the return shape. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but each section earns its place: the opening sentence states the operation, the bulleted list gives the agent concrete detection categories, the score-interpretation paragraph is actionable, and the parameter/return details are compact. The multi-line structure with bullets and monospace examples is readable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description explains what this audit is for, when it is meant to be run (on already-generated data), how to interpret the 0-100 score, and what to do next (add realism structures). It avoids duplicating the output schema but explains the score semantics and the folder format. Minor gap: it does not explicitly say that a clean score means no action is needed, but the score interpretation and remediation advice cover the essential behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is effectively 0% for both parameters (one has only a type and a default, the other only a type), so the description carries the burden. It adequately explains 'dataset_dir' (one CSV per table, the output_dir of generate_from_schema) and 'top_findings' (max findings, default 20). That covers both parameters even though the schema itself has descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Score a folder of CSVs' with a specific verb and resource. It explicitly enumerates the types of contradictions detected (timestamps, reconciliation, geography, near-constant columns, filler text), which gives the agent a precise picture of what this tool does and distinguishes it from generation/schema tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when to use this tool: on data that already exists, whether agent-generated or hand-built. It also tells the agent what the findings mean and how to respond — add structure declarations instead of patching data — which acts as an implicit exclusion for fix-data workflows. Sibling context (generate_from_schema) reinforces the routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_realismCheck a dataset for the tells of synthetic dataARead-onlyIdempotent
Find the statistical shapes that make a dataset look generated.
Where audit_dataset finds contradictions, this finds shapes real data
almost never has, with no real data to compare against: money spread
evenly from min to max, every customer with about the same number of
orders, perfectly balanced categories, flat weekday or hour-of-day
profiles, timestamps piled up at midnight, placeholder values
(@example.com, John Doe), emails unrelated to names, small name pools,
templated or repetitive free text, prose with a tiny vocabulary, review
text whose tone ignores its rating, descriptions unrelated to their
titles, tables with no nulls at all. Works on data from any generator,
including a script you wrote.
Fix a finding in the schema, not the rows: lognormal for money, a curve or
weights for time, sampling on foreign keys, null_rate or
__missingness__ for optional fields. Pass skip for tells that are
intended (a randomised A/B split is balanced on purpose).
Args:
dataset_dir: Directory with one CSV per table (the output_dir from
generate_from_schema).
skip: Check names to leave out, e.g. ["too_clean"].
Returns:
{"score": 0-1, "passed": bool, "counts": {...}, "tells": [...]},
each tell with its check, table, column, status and evidence.
| Name | Required | Description | Default |
|---|---|---|---|
| skip | No | ||
| dataset_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and non-destructive, so the safety profile is covered. The description adds genuinely useful behavioural context: it works on data from any generator including hand-written scripts, requires no reference dataset, and its findings should be fixed in the schema (lognormal, sampling, null_rate) rather than in rows.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and the sibling contrast before the long enumeration of tells. The tells list is verbose but each entry is a distinct detectable pattern that informs what the tool reports; the fix-a-finding and skip guidance are dense and value-bearing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still orients the agent with the return shape (score, passed, counts, tells with check/table/column/status/evidence). Combined with the usage routing, remediation hints and parameter definitions, nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the load. It defines dataset_dir as 'Directory with one CSV per table (the output_dir from generate_from_schema)' and skip as check names to omit, with a concrete example (["too_clean"]). Both parameters gain meaning absent from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('find the statistical shapes that make a dataset look generated') and immediately differentiates itself from the sibling audit_dataset by contrasting contradictions vs. shape anomalies. The enumerated tells make the scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternative ('Where audit_dataset finds contradictions, this finds shapes...') and states the precondition (no real data to compare against). It also tells the agent when to pass skip ('tells that are intended, a randomised A/B split is balanced on purpose') and even routes remediation to the schema rather than the rows.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_sandboxCreate an instant sandbox databaseAIdempotent
Create and seed a real, isolated SQLite sandbox database for testing.
Perfect for AI coding agents: spins up a queryable database with realistic, referentially intact tables (0 orphan foreign keys) so you can test SQL queries, analytics logic, or application code immediately without touching a real database.
Args: domain: Pre-built domain template ('saas', 'ecommerce', 'fintech', 'healthcare'). story: Plain-English description (e.g. 'A restaurant with tables, bookings, and guests'). schema: Explicit schema dict if you want exact column control. rows: Base row count (default: 100). Transactions scale proportionally. seed: Random seed for 100% reproducible results (default: 42). db_path: Target SQLite file path (default: '.misata/sandbox.db').
Returns: Dictionary with db_url, db_path, table summaries, DDL, and sample verification queries.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| seed | No | ||
| story | No | ||
| domain | No | ||
| schema | No | ||
| db_path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false, openWorldHint=false, and idempotentHint=true, so safety and repeatability are partly covered. The description usefully adds that seeded data has '0 orphan foreign keys' (referential integrity) and that the result is reproducible via a default seed, and discloses the default write path '.misata/sandbox.db'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose followed by Args and Returns sections, which is well organized and every element is informative. There is mild promotional padding ('Perfect for AI coding agents') and the narrative benefit paragraph could be trimmed, but nothing is truly wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter creation tool with annotations covering the safety profile and an output schema covering return values, the description supplies purpose, all parameter meanings, and a return summary. The remaining gap is guidance on how it differs from the many sibling generation/seed tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema provides only titles and defaults. The description compensates fully: it names the four built-in domains, explains 'story' as plain English, clarifies 'schema' as an explicit dict for column control, notes rows scaling, and explains seed reproducibility (default 42) and db_path default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Create and seed a ... SQLite sandbox database') and adds the distinguishing traits of being real, isolated, and for testing. It does not, however, differentiate itself from close siblings like seed_database, generate_dataset, or create_from_schema, so an agent cannot route confidently on description alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear usage context: 'test SQL queries, analytics logic, or application code immediately without touching a real database,' which tells the agent when this is the right tool. There are no explicit exclusions or named alternatives despite several overlapping siblings (seed_database, generate_dataset, generate_from_schema).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_schemaExplain what a schema will generateARead-onlyIdempotent
Show what generate_from_schema would do with a schema, without generating.
Call it before generate_from_schema on a schema you designed: it is
cheap, and it catches the mistakes that would otherwise surface after a
long run. Returns each table's planned row count and approximate memory,
the declarations and the columns each one writes, any column two
declarations both write, every outcome curve's period plan and warnings,
and the invariants attest_dataset will check on the output. When
will_generate is false, conflicts names each contradiction with
the arithmetic and a remedy; fix those in the schema and call again.
Args: schema: The schema dict you would pass to generate_from_schema. seed: The seed you would generate with. max_invariants: How many invariants to include in the response.
Returns:
{"ok", "will_generate", "total_rows", "estimated_bytes", "tables", "relationships", "declarations", "writers", "overlaps", "conflicts", "conformance", "invariants", "invariants_total"}.
| Name | Required | Description | Default |
|---|---|---|---|
| seed | No | ||
| schema | Yes | ||
| max_invariants | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), but the description adds substantive context: it is a dry run, it is cheap, it reports planned row counts, estimated memory, overlapping writers and conflicts with arithmetic plus a remedy. It also explains the failure path (will_generate=false → fix schema → call again), which no annotation conveys.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose before any detail, and most sentences carry real information (cost, failure handling). The trailing 'Returns:' block largely duplicates the output schema, which is the main non-earning element.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-param, nested-object, read-only dry-run tool this is nearly complete: motivation, cost, output summary and the conflict-remediation loop are all present. The only redundancy is restating return keys that the output schema already defines.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the burden, and it does: schema is 'the schema dict you would pass to generate_from_schema', seed is 'the seed you would generate with', and max_invariants is 'how many invariants to include'. It lacks format details or notes on defaults/nulls, which keeps it below a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Show what generate_from_schema would do with a schema, without generating') and explicitly frames itself as the dry-run counterpart to the sibling generate_from_schema. An agent can select it over its siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly prescribes when to call it ('before generate_from_schema on a schema you designed'), gives the rationale ('it is cheap, and it catches the mistakes that would otherwise surface after a long run'), and describes the remediation loop when will_generate is false. This is textbook when-and-why guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_datasetGenerate a dataset from a sentenceA
Generate a synthetic dataset from a story and write it to disk as CSV files.
Returns the output directory, file paths, row counts per table, and a small sample of rows for each table so the agent can show the user what was produced without loading every row into context.
Args: story: Plain-English description of the dataset. rows: Default row count for the primary table. seed: Optional random seed (same seed → byte-identical output). output_dir: Where to write CSVs. Defaults to a fresh temp dir. sample_rows: Number of rows from each table to include in the response (max 50).
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| seed | No | ||
| story | Yes | ||
| output_dir | No | ||
| sample_rows | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond the annotations. It states that the tool writes CSV files to disk, returns output directory and file paths, and includes row counts and sample rows. It also discloses determinism: 'same seed → byte-identical output.' These details are not present in the annotations (readOnlyHint false, destructiveHint false) and valuable for the agent to anticipate side effects. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured. The opening sentence states purpose, followed by a clear list of return values, then a bulleted Args section. Every sentence earns its place, and the use of a list for parameters improves readability. There is no redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has 5 parameters, an output schema, and complex behavior (file writing, determinism). The description explicitly mentions return values (output directory, file paths, row counts, sample rows), addresses parameter defaults, and explains the sample_rows cap. It is complete for an agent to use effectively without further documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no property descriptions (coverage 0%), so the description carries the full burden. It includes an Args section that explains each of the 5 parameters: story, rows, seed, output_dir, and sample_rows, adding meaning like 'Defaults to a fresh temp dir' and 'max 50'. This fully compensates for the schema's lack of descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action: 'Generate a synthetic dataset from a story and write it to disk as CSV files.' It specifies the resource (dataset from a story) and distinguishes it from siblings like generate_from_schema, which focuses on schema-driven generation. The verb 'generate' and the context 'from a story' are specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool: when you have a plain-English story to convert into a dataset. It also explains that it returns sample rows and file paths, which is helpful for the agent to show results. However, it does not explicitly mention alternatives (e.g., 'use generate_from_schema if you have a schema') or state when NOT to use it, leaving a slight gap in decision-making guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_from_schemaGenerate a dataset from a schemaAIdempotent
Generate a dataset from a schema you design. This is the primary Misata tool.
DIVISION OF LABOUR You (the agent) design what the data should look like — the tables, columns, business rules, and declared targets. Misata handles the hard guarantees: every FK resolves, every rollup reconciles to the cent, every declared outcome curve is hit exactly, every seed produces byte-identical output. The response includes a per-relationship integrity proof.
SCHEMA FORMAT {table_name: {column_name: spec, ...}, ...}
TABLE-LEVEL KEYS (inside a table dict) "rows": 5000 Per-table row count; overrides the global rows arg. Always set this — one global count rarely fits all tables. "constraints" List of row-level business rules (see CONSTRAINTS below). "correlations" List of pairwise Pearson targets (see CORRELATIONS below). "state_machine" Markov terminal-state assignment (see STATE MACHINE below).
COLUMN TYPES integer, float, decimal Numeric. string Short categorical or free text. text Long free text (descriptions, notes). email, phone, url, uuid Semantic strings; always valid format. date, datetime Temporal; realistic granularity applied automatically. boolean True/False with declared probability. object (json) Nested object: {"type": "object", "fields": {"email": "email", "age": {"type": "integer", "min": 18}, "tags": {"type": "list", "items": "string"}}}. Optional: "optional": [...], "optional_rate". list (array) {"type": "list", "items": , "min_items": 0, "max_items": 5, "unique_items": true, "sorted": true}. Values are JSON text.
COLUMN SPEC KEYS (inside a column dict) primary_key: true Auto-incremented PK; column excluded from CSV output. foreign_key: {table, column} Child FK; referential integrity guaranteed + verified. min / max Numeric or date bounds. decimals: 2 Decimal places for float output. unique: true All values in the column are distinct. nullable: true Allow nulls (default true). enum: [...] Categorical choices. Add probabilities: [...] for weights; omit for realistic Zipf-shaped rank frequencies. probabilities: [...] Weights for enum choices; must sum to 1.0.
DISTRIBUTIONS (float / integer columns) distribution: normal Also: lognormal, uniform, exponential, gamma (shape, scale), beta (a, b), poisson (lambda), binomial (n, p), power_law (alpha). mean / std Normal params. Can be a scalar OR a per-row parent-entity lookup: mean: {formula: "@patients.hba1c_baseline"} The FK is resolved per-row so each child row's distribution is anchored to its parent's value. Use this for longitudinal data where within-entity variation should be modelled separately from between-entity variation. mu / sigma Lognormal params (mu and sigma are of log(x)). min / max Hard clamps applied after sampling. Use lognormal for money, file sizes, session durations — anything right-skewed and strictly positive. Use normal for measurements.
DERIVED COLUMNS formula: "quantity * unit_price" Row-level arithmetic; pandas eval syntax. formula: "hours * @employees.rate" Cross-table via FK: @parent_table.column. rollup: {from_table, fk, agg, column} Parent column that EXACTLY reconciles with child rows under JOIN. agg: sum/count/mean/ max/min. Add where: {col: val} to filter. RULE: use rollup (not formula) for any parent column that summarises child rows. Rollups are closed-form exact; formulas cannot cross the FK boundary correctly.
CODE-STYLE STRINGS pattern: "SKU-\d{5}" Single pattern expanded per row. pattern: ["A/\d{5}", "\d{6}"] List: one shape drawn per row. pattern_weights: [0.7, 0.3] Weights for pattern list (optional). Supported tokens: \d (digit), [A-Z] (uppercase letter), [a-z] (lowercase), literal chars, {n} repeat count. Example: "[A-Z]{2}-\d{4}" → "AB-3721".
TEXT SEMANTICS text_type: person_name Always beats column-name inference. Options: person_name, email, company, city, country, postal_code, phone, url, description, username, product_name, review_text, address, job_title. Dates: appointment times snap to 15-min business-hours grids; signups follow waking-hour rhythms; machine events keep sub-second precision. Names, genders, and emails are generated jointly and always agree.
STRATIFIED DISTRIBUTIONS (profiles) Use when different subgroups need different distributions for the same column. profiles: [ {when: "arm == 'placebo'", distribution: normal, mean: -0.35, std: 0.50}, {when: "arm == 'high_dose'", distribution: normal, mean: -1.25, std: 0.55}, ] Rows that match no profile get the column's top-level distribution. The when expression is a pandas eval string; reference any already-generated column in the same table. Always list profiles after the columns they reference.
INFORMATIVE MISSINGNESS (MAR) null_when: "dropout == False" Null this column when expression is true. missing_if: Missing-At-Random tied to a predictor column. predictor: hba1c_baseline relationship: higher_increases_probability # or lower_increases_probability base_rate: 0.05 # null probability at predictor median max_rate: 0.40 # null probability at predictor extreme Use null_when for status-conditional nulls (dropout_visit is null when not dropped out). Use missing_if when missingness is correlated with an observed variable.
EXACT INCIDENCE CONTROL exact_incidence: Hit the declared count exactly (not approximately). mode: exact rate: 0.22 # exactly floor(n * 0.22) rows become True group_by: arm # optional: apply per group rates: {placebo: 0.15, high_dose: 0.55} # per-group exact rates Use exact_incidence instead of probability on boolean columns when the user states a precise rate that must hold in the data, not just on average.
WITHIN-ENTITY TIME SERIES (longitudinal autocorrelation) time_series: Re-writes a column to have AR1 autocorrelation entity_id: patient_id within each entity group. order_by: visit_number model: AR1 # AR1 | linear_trend | random_walk | mean_reversion phi: 0.72 # autocorrelation coefficient (AR1 only) noise_std: 0.30 anchor_column: hba1c_baseline # starting value (column in the same table) trend: slope_mean: -0.08 # mean drift per step slope_std: 0.02 # per-entity slope variability Required for any longitudinal dataset (clinical visits, IoT sensors, user sessions). Without it every row is independent and the data fails any time-series test.
CONSTRAINTS (table-level constraints list) {"type": "inequality", "column_a": "visit_date", "operator": ">=", "column_b": "enroll_date", "action": "cap"} Enforces column_a OP column_b. action: "cap" (snap column_a to column_b) or "drop" (remove violating rows). Works on dates and numerics. {"type": "col_range", "low_column": "min_price", "column": "price", "high_column": "max_price", "action": "cap"} Keeps low_column <= column <= high_column. {"type": "max_per_group", "group_by": "user_id", "max_count": 3} Limits rows per group value. {"type": "unique_combination", "columns": ["user_id", "product_id"]} No duplicate (col_a, col_b) pairs. Use constraints for any business rule that must hold on every row: visit_date >= enrollment_date, price > cost, resolution_day > onset_day.
CORRELATIONS (table-level correlations list) [{"col_a": "bmi", "col_b": "systolic_bp", "r": 0.41}] Enforced via Iman-Conover (rank reordering): preserves each column's marginal distribution while hitting the declared Pearson r exactly. Declare correlations for any pair of measurements that co-vary in the real domain (bmi/bp, income/spending, tenure/salary). Also supports full matrix syntax: correlations: matrix: columns: [hba1c, glucose, bmi] values: hba1c: [1.00, 0.65, 0.28] glucose: [0.65, 1.00, 0.22] bmi: [0.28, 0.22, 1.00]
ICC CLUSTER EFFECTS (parent table cluster_effect) cluster_effect: affects_table: visits affects_columns: hba1c: icc: 0.18 # intraclass correlation coefficient sd_total: 1.5 # total standard deviation; sd_between = sqrt(icc)*sd_total systolic_bp: sd_between: 8.0 # supply sd_between directly if preferred Applies per-parent-entity random intercepts to the named child columns. Required for multi-site or multi-centre designs — without it all sites look identical and any ICC statistical test will detect the synthetic origin. icc: 0.10-0.30 is typical for clinical measurements across sites.
STATE MACHINE (table-level state_machine) state_machine: state_column: patient_status initial_state: enrolled transitions: enrolled: {on_treatment: 0.97, screen_failure: 0.03} on_treatment: {completed: 0.77, dropout: 0.23} Assigns one terminal state to every row by following the Markov chain. States with no outgoing transitions are terminal. Use for any process with defined states: clinical trial statuses, customer lifecycle, order fulfilment stages, support ticket resolution.
SCHEMA-LEVEL DIRECTIVES (top-level keys, siblings of the tables)
outcome_curves Declare aggregate targets the engine hits EXACTLY. [{"table": "orders", "column": "amount", "time_column": "order_date", "time_unit": "month", "value_mode": "absolute", "start_date": "2024-01-01", "avg_transaction_value": 120.0, "curve_points": [ {"month": 1, "target_value": 50000.0}, {"month": 6, "target_value": 110000.0}, {"month": 12, "target_value": 200000.0} ]}] ALWAYS use this when the user states what a number should sum to per period: "revenue grows from $50k to $200k", "Q4 spike", "10x growth". avg_transaction_value drives row count per period; set it to roughly the median row value for that column.
rate_curves Per-period rate targets for boolean/categorical columns. [{"table": "transactions", "column": "is_fraud", "time_column": "transaction_date", "rate_points": [ {"period": "2024-01", "rate": 0.02}, {"period": "2024-Q4", "rate": 0.05} ]}] Use when fraud rate, churn rate, or conversion rate changes over time.
group_shares Exact shares of a measure across a categorical column. [{"table": "orders", "measure": "amount", "group_column": "plan", "shares": {"Starter": 0.2, "Pro": 0.5, "Enterprise": 0.3}}] The measure sums to those proportions per group, exactly. Paired with an outcome_curves on the same table+measure, the split holds inside every declared period. Use for any "A is 40% of revenue, B is 35%..." statement.
waterfalls Movements that reconcile to declared running balances. [{"table": "mrr_movements", "starting_value": 100000, "points": [{"period": "2026-01", "ending_value": 106000}, ...], "inflow_shares": {"new": 0.7, "expansion": 0.3}, "outflow_shares": {"churn": 1.0}}] Use for MRR bridges, cash-flow statements, any "opening + inflows - outflows = closing" ledger that has to tie out.
stock_flows Per-unit inventory identity: closing = opening + received
shipped, enforced for every SKU across every period. Use for warehouse / inventory data where stock levels must be internally consistent.
lifecycles A state machine with legal transitions (stricter than a table-level state_machine: illegal jumps are impossible, not just unlikely). [{"name": "order_flow", "table": "orders", "state_column": "status", "start_column": "placed_at", "initial": "placed", "states": [{"name": "placed"}, {"name": "paid"}, {"name": "shipped"}, {"name": "delivered"}, {"name": "refunded", "terminal": true}], "transitions": [["placed","paid"],["paid","shipped"], ["shipped","delivered"],["delivered","refunded"]]}]
missingness Why a value is missing, conditionally (schema-level MNAR). [{"table": "contacts", "column": "notes", "rate": 0.75, "else_rate": 0.05, "when_column": "is_active", "when_op": "==", "when_value": false}] The null rate is exact per branch. Use when missingness itself carries signal a cleaning step should be tested against.
processes How each case moves through steps over time, written out as an event-log table (one row per event: case key, step, activity, timestamp). Use for support tickets, claims, onboarding funnels, order fulfilment, anything where the user wants an event log, a process-mining dataset, rework loops or realistic step durations. [{"name": "ticket_flow", "cases_table": "tickets", "case_key": "ticket_id", "start_column": "opened_at", "initial": "opened", "transitions": {"opened": {"triaged": 1.0}, "triaged": {"resolved": 0.85, "escalated": 0.15}, "escalated": {"resolved": 1.0}, "resolved": {"closed": 0.9, "reopened": 0.1}, "reopened": {"triaged": 1.0}}, "dwell": {"opened": {"distribution": "lognormal", "mu": 0, "sigma": 0.8, "unit": "hours"}}, "final_state_column": "status"}] A state with no transitions row is terminal. Each row sums to 1. The event table is named "_events". Structure is exact and audited; path shares and durations are drawn from the declaration.
DIRTY DATA ON PURPOSE (exact counts, so a test has a known number to find) duplicates [{"table": "contacts", "count": 60}] typos [{"table": "contacts", "column": "city", "count": 120}] outliers [{"table": "orders", "column": "amount", "count": 40}] Each injects exactly that many defects, leaving primary/unique/foreign keys intact. Use when the user is building or testing a data-quality or cleaning pipeline.
preset Use-case defaults: "demo" (dates end today, clean), "test" (<=200 rows, fixed seed), "load" (x10 rows), "ml" (declared nulls/outliers/typos/duplicates, keys protected), "eval" (current dates, modest dirt). Declarations always win.
domain Domain hint for post-generation validation.
"domain": "clinical_trial" # or "clinical", "financial", "fintech"
When set, generate_from_schema runs domain validation automatically and
returns it as domain_validation in the response — no second call
needed. Built-in ranges: HbA1c 4-14 %, BMI 10-80, systolic BP 60-260,
age 0-130, glucose 2-40, cholesterol 1-20, hemoglobin 3-25 for clinical;
price >= 0, discount 0-1, rate -1 to 100 for financial.
There are ~24 schema-level declarations in total. The ones above cover the common cases; for the rest (retention cohorts, DAG edges, closure tables, graph motifs, time grids, bitemporal history) fetch https://misata.studio/docs/reference/declarations.md and check the exact key before inventing one.
DESIGN RULES — follow these to get the best result in one pass
Always set rows per table. A fintech schema with customers=2000, accounts=4000, transactions=50000 is far better than 1000 everywhere.
Every child table needs a FK column pointing to its parent PK. Without it orphan rows are generated and the integrity proof will fail.
Use lognormal for money, file sizes, response times (right-skewed, strictly positive). Use normal for measurements (height, score, temp).
Declare correlations for any pair that co-varies in the real domain. Generated data with an identity correlation matrix is the clearest synthetic-data tell there is.
Use exact_incidence instead of probability when the user states a precise rate. "3% fraud" with probability: 0.03 gives ~3% on average; exact_incidence gives exactly 3%.
Use rollup (not formula) for any parent column that must reconcile with child rows. customers.total_spent generated independently of orders will never match; a rollup makes it exact.
Use outcome_curves any time the user mentions a revenue shape, a growth trajectory, a seasonal pattern, or a specific period total. It is the single feature most likely to be forgotten and most visible when absent.
Use profiles when two groups need different distributions. A clinical trial where all arms share one HbA1c distribution is statistically wrong and the difference will be caught by any summary table.
For longitudinal data (visits, sessions, sensor readings), add time_series to the key measurement columns. Independent rows fail every autocorrelation test and are visually obvious when plotted.
Add state_machine to any entity that moves through a process. An order table with no status progression is not realistic order data. When the user wants the steps themselves (an event log, durations, loops), declare processes instead.
Typos are errors. An unknown distribution name or a misspelled parameter (lamda, mena) is rejected with a "did you mean" suggestion. Read the error and fix the key rather than dropping the parameter.
After generating, call check_realism on the output_dir and fix what it flags: uniform money, every customer with the same number of orders, flat hour or weekday profiles, emails unrelated to names, no nulls.
Args: schema: Dict of table defs plus optional schema-level directives. rows: Default row count for tables without rows. seed: Random seed (same seed → byte-identical output on any machine). output_dir: Where to write CSVs. Omit to use a fresh temp dir. sample_rows: Rows per table to include in the JSON response (max 50).
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| seed | No | ||
| schema | Yes | ||
| output_dir | No | ||
| sample_rows | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare idempotentHint=true and readOnlyHint=false, and the description goes well beyond them: it states the seed produces byte-identical output on any machine, that CSVs are written to output_dir (or a fresh temp dir when omitted), that the response carries a per-relationship integrity proof, and that __domain__ triggers automatic domain validation returned as domain_validation with no second call. It also discloses error behaviour — unknown distributions or misspelled keys are rejected with a 'did you mean' suggestion.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very long, but for a tool whose main argument is an undocumented free-form DSL the bulk is reference material rather than padding, and it is organised under clear headers with the purpose and division of labour front-loaded. It also wisely defers the remaining ~24 declarations to a docs URL instead of enumerating everything. Some 'use X for Y' lines restate the same right-skew guidance more than once.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still names the key return payloads (per-relationship integrity proof, domain_validation), covering residuals the schema alone would not explain. Combined with the schema-format spec, schema-level directives, and design rules, an agent has everything needed to invoke this in one pass, including which sibling to call afterwards.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does so: the trailing Args block defines all five parameters, including non-obvious semantics such as seed → byte-identical output across machines, output_dir omitted → fresh temp dir, and sample_rows being capped at 50. It also supplies the entire format spec for the free-form schema dict, which no structured field conveys.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Generate a dataset from a schema you design') and even lays out the division of labour between agent and engine, so the agent knows exactly what it gets back (a dataset plus an integrity proof). The one gap is sibling differentiation: with a sibling literally named generate_dataset, the text never explains how this differs from it, only calling itself 'the primary Misata tool'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage guidance is unusually rich and conditional — 'Use lognormal for money', 'use exact_incidence instead of probability when the user states a precise rate', 'use rollup (not formula) for any parent column that must reconcile', plus a 12-point design-rules list. It also routes the agent to a sibling ('After generating, call check_realism on the output_dir'). What it lacks is explicit selection guidance against the other generate/preview siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
inspect_schemaInspect the schema behind a storyARead-only
Return the full schema (tables, columns, relationships) for a story without generating data.
Heavier than preview_story — includes every column with its type and
distribution params. Use when the user wants to see the structure they'll
get, or to author a misata.yaml file from a natural-language seed.
Args: story: Plain-English description of the dataset. rows: Default row count for the primary table.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| story | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and non-destructive; the description builds on this by noting it does not generate data and by explaining the type of output (every column with type and distribution params). It stops short of detailing performance implications beyond 'heavier' or clarifying idempotent behavior, but adds meaningful context beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly written, starting with a clear one-sentence purpose, followed by a comparative detail, use cases, and a compact Args list. Every sentence earns its place with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only inspection tool with two parameters and a documented output schema, the description covers the what, when, and parameters, and even notes the lack of data generation. It could go further by describing error scenarios or output format specifics, but these are already captured by the output schema and annotations, making it adequately complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description must compensate, and it does via an Args section that explains `story` as 'Plain-English description of the dataset' and `rows` as 'Default row count for the primary table.' This adds clear meaning beyond the bare types, though it could elaborate on how changing `rows` affects its behavior. The high coverage shift justifies a score above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Return the full schema (tables, columns, relationships) for a story without generating data,' using a specific verb and resource scope. It goes beyond a generic statement by explicitly contrasting with `preview_story` ('Heavier than') and providing concrete use cases, making its purpose unmistakable and distinctive.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly notes this tool is 'Heavier than `preview_story`' and provides two direct use cases: showing the structure the user will get and authoring a `misata.yaml` file from a seed. This gives an agent clear when-to-use guidance and signals an alternative, even if it doesn't mention explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_domainsList built-in domainsARead-onlyIdempotent
List the 18 built-in business domains Misata can generate from natural language.
Each domain has trigger keywords and a sample story you can pass to
preview_story or generate_dataset. Use this when the user asks
"what kinds of data can you generate?" or to suggest a story format.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds useful context beyond annotations by revealing that the result contains 18 domains, each with trigger keywords and a sample story, which the agent can pass to preview_story or generate_dataset.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the core action in the first sentence. The subsequent sentences add useful behavioral and usage context without unnecessary fluff, though it could have been slightly tighter by merging the first two sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is sufficient for a parameterless list tool: it names the exact output scope, explains what each returned domain contains, gives intended usage triggers, and references downstream consumer tools. The output schema and annotations cover the remaining structural and safety aspects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, and the schema coverage is effectively 100% because there is no input to document. There is nothing for the description to add about parameter syntax or meaning, so the baseline score for a zero-parameter tool applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a specific verb+resource: 'List the 18 built-in business domains Misata can generate from natural language.' This clearly distinguishes the tool from the generative siblings by indicating it is a read-only catalog of available domains.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use this tool: 'Use this when the user asks "what kinds of data can you generate?" or to suggest a story format.' It also mentions downstream tools like preview_story or generate_dataset, but it does not explicitly address when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preview_storyPreview how a story is interpretedARead-only
Inspect what Misata would generate from a story — without generating any rows.
Returns the detected domain, confidence, near-misses, locale, scale, and a preview of the tables that would be produced. Use this to confirm interpretation before committing to a (potentially large) generation.
Args: story: Plain-English description of the dataset. rows: Default row count for the primary table (affects preview only).
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| story | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds context: it clarifies no rows are generated, that rows affects preview only, and lists returned fields (domain, confidence, near-misses, locale, scale, tables). No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: a one-sentence purpose, a list of returned items, a usage note, and an Args section. It is concise with no redundant text and front-loads the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params, output schema exists), the description covers purpose, usage, parameters, and return values. It provides sufficient context for an agent to understand when and how to invoke it, without needing to rely on the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must clarify parameters. It provides Args: 'story: Plain-English description of the dataset' and 'rows: Default row count for the primary table (affects preview only).' This fully compensates for missing schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Inspect what Misata would generate from a story — without generating any rows.' This uses a specific verb (inspect) and resource (story interpretation) and differentiates from sibling generation tools like generate_dataset and seed_database.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use: 'Use this to confirm interpretation before committing to a (potentially large) generation.' It implies the alternative is to generate, but does not name the exact sibling tools. Still, the guidance is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_sandboxQuery the sandbox databaseARead-onlyIdempotent
Execute a read-only SQL query against the sandbox database.
Allows AI coding agents to verify SQL queries, test aggregations, or inspect data in the sandbox directly without opening external terminals.
Args: query: SQL SELECT query to execute. db_path: Optional path to the database (defaults to '.misata/sandbox.db'). limit: Max rows to return (default: 100).
Returns: Dict with columns, rows (as list of dicts), row_count, and execution status.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| db_path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint=false, and destructiveHint=false, and the description's 'read-only' claim is consistent with them. It adds value beyond annotations by disclosing the default database location and the default row cap, plus the fact that no external terminal is needed. It does not say what happens if a non-SELECT statement is submitted, which is the remaining behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then a rationale sentence, then clearly labeled Args and Returns sections. Every element is relevant, though the rationale sentence is slightly verbose and the Returns block partly duplicates the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-param, read-only sandbox query tool with annotations and a declared output schema, the definition covers purpose, use cases, all parameters, defaults, and return shape — so an agent can call it correctly. The only omission is error/enforcement behavior for invalid or non-read-only SQL, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and largely does so: it defines query as the SQL SELECT to execute, db_path as an optional path defaulting to '.misata/sandbox.db', and limit as the max rows with a default of 100. This covers all three parameters with meaning and defaults, though it omits any syntax note such as whether multi-statement or mutating SQL is rejected.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource — 'Execute a read-only SQL query against the sandbox database' — plus the scope constraint (read-only, sandbox). This is immediately distinguishable from siblings like inspect_schema, seed_database, or create_sandbox.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete use cases ('verify SQL queries, test aggregations, or inspect data in the sandbox directly without opening external terminals'), which tells the agent when this tool is the right pick over running an external shell. It stops short of naming alternatives (e.g., inspect_schema for structure) or stating exclusions, so it is clear context without explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
seed_databaseSeed a real databaseADestructive
Fill a live Postgres or SQLite database with realistic, connected data, read from the database's own schema.
Reads the tables, columns, and foreign keys directly from the target database, generates data that respects them, inserts parents before children, then queries the database back to confirm every foreign key resolves. No schema file and no ORM are needed: a connection string is enough.
SAFETY — this is the only Misata tool that writes to a user's database:
It plans by default. With
apply=False(the default) nothing is written; you get the table list, insert order, existing row counts, and what would be inserted. Show that plan to the user.Only call again with
apply=Trueafter the user has seen the plan and agreed. Never passapply=Trueon a first call.If any target table already has rows, the write is refused unless the user chooses
truncate=True(wipe and reseed) orappend=True(keep existing rows, seed only empty tables, and draw foreign keys from the rows already there). Never guess between these.truncate=TrueDESTROYS existing data. Only use it on a throwaway development database and only when the user explicitly asks.
Args:
db_url: Connection string, e.g. postgresql://localhost/myapp_dev
or sqlite:///dev.db.
rows: Base row count; reference and transaction tables scale from it.
apply: False (default) plans only. True performs the write.
truncate: Wipe target tables (children first) before seeding.
append: Keep populated tables and seed only the empty ones.
tables: Optional allow-list of table names to seed.
skip_tables: Tables to leave untouched (migrations, auth, etc.).
seed: Random seed; the same seed reproduces the same data.
Returns:
A plan (applied: false) or a result with per-table row counts and
a per-relationship integrity proof (integrity.verified).
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | ||
| seed | No | ||
| apply | No | ||
| append | No | ||
| db_url | Yes | ||
| tables | No | ||
| truncate | No | ||
| skip_tables | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the annotations by detailing the destructive nature (truncate=True destroys data), the write behavior, and the safety flow (plan first, then apply). It transparently discloses side effects and the conditions under which writes are allowed, adding crucial context that annotations alone do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Although lengthy, the description is well-structured with clear sections (summary, safety, args) and every sentence adds value. It avoids redundancy and uses formatting (bold, bullet points) to improve readability, making it efficient despite its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 8 parameters and output schema, the description thoroughly covers all aspects: parameter usage, safety considerations, and the return value (plan vs result with integrity verification). It is complete and self-contained, leaving no critical gaps for an agent to misuse the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, but the description's Args section explains every parameter in detail, including examples, defaults, and how they interact (e.g., rows scaling, tables/skip_tables filtering, apply vs truncate/append). This fully compensates for the missing schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: filling a live Postgres or SQLite database with realistic, connected data based on the database's own schema. It distinguishes itself from sibling tools like generate_from_schema by emphasizing that no schema file or ORM is needed, and it is the only tool that writes to a database.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use this tool (to populate a database) and differentiates it from alternatives by noting it is the only one that writes. It also provides clear instructions on the safe default (apply=False) and when to use truncate/append, making it obvious when to call it versus other tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
solve_outcomeSolve outcome curves to hit a pipeline's targetsARead-onlyIdempotent
Find outcome-curve values that make SQL metrics over the data hit targets.
Use it when the number that matters is computed from the generated
tables rather than declared on them: net revenue after refunds, revenue
after a fee, a ratio of two tables. Each query runs in DuckDB over the
generated tables and returns two columns, the period and the value, one
row per period. Each target names a metric, the table.column outcome
curve that moves it (the lever, which must have exact per-period
values), and the value per period. Set direction: "inverse" when a
larger lever lowers the metric, as refunds lower net revenue.
Nothing is written. On success, replace each lever curve's
curve_points in your schema with levers[lever], then generate as
usual; attest_dataset will confirm the curves hold.
Args:
schema: The schema dict, with an outcome curve per lever.
queries: Metric name to DuckDB query, e.g. {"net": "SELECT date_trunc('month', ordered_at), SUM(amount) * 0.97 FROM orders GROUP BY 1"}.
targets: [{"metric", "lever", "values": {"2025-01": 70000}, "direction"?}].
tolerance: Relative tolerance per period, e.g. "0.5%".
max_iterations: Generate-and-query rounds allowed, at most 40.
seed: Seed used for every round.
Returns:
{"ok", "converged", "reason", "message", "iterations", "best_iteration", "levers", "steps"}. reason is one of
converged, max_iterations, max_seconds, diverging, unresponsive,
infeasible, pipeline_error; message says what to change when it
is not converged.
| Name | Required | Description | Default |
|---|---|---|---|
| seed | No | ||
| schema | Yes | ||
| queries | Yes | ||
| targets | Yes | ||
| tolerance | No | 1% | |
| max_iterations | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it discloses the DuckDB execution model, a 40-iteration cap, per-period tolerance semantics, inverse-lever behavior, the full reason-code set, and the exact success workflow including replacing curve_points before regeneration. The one redundant line ('Nothing is written') is consistent with annotations rather than contradictory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then usage, then args and returns in a predictable structure. It is somewhat prose-heavy and repeats the annotation-backed 'Nothing is written', but nearly every sentence carries useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is complex with nested objects and zero schema description coverage. The description compensates fully by covering inputs, execution behavior, convergence/failure reasons, and the downstream workflow; the output schema makes a deeper return-value explanation unnecessary, though the summary of keys is a bonus.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the full burden and does so: it explains schema, queries (with a worked DuckDB example), targets including metric/lever/values/direction, tolerance format ('0.5%'), the max 40 iterations, and seed reuse across rounds.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: find outcome-curve values so that SQL metrics over generated data hit targets. It explicitly distinguishes itself from declared-metric workflows and from siblings like attest_dataset, which only confirm results.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-to-use rule ('when the number that matters is computed from the generated tables rather than declared on them') with concrete examples, and names attest_dataset as the post-step. There is no explicit when-not-to-use section, but the alternative workflow is strongly implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_domainValidate a dataset against domain rulesARead-onlyIdempotent
Flag values that are physiologically or financially impossible for a domain.
Where audit_dataset checks internal consistency, this checks values
against what the outside world allows. Built-in ranges include, for
clinical / clinical_trial: HbA1c 4-14%, BMI 10-80, systolic BP
60-260, age 0-130, glucose 2-40, cholesterol 1-20, hemoglobin 3-25; for
financial / fintech: price >= 0, discount 0-1, rate -1 to 100.
Use after generating a dataset in a regulated or measurement-heavy domain, or when the user asks "is this data plausible for a real clinic / bank?".
Args:
dataset_dir: Directory containing one CSV per table.
domain: One of clinical_trial, clinical, financial,
fintech.
Returns:
{"passed": bool, "errors": [...], "warnings": [...]}. passed
is True when there are no ERROR-level findings.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | ||
| dataset_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds significant behavioral context beyond that: the exact output structure (passed, errors, warnings), the meaning of 'passed', and the built-in domain ranges. It also clarifies that it does not check internal consistency, preventing misinterpretation. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: a one-sentence summary, a clarifying contrast, domain-specific ranges, usage guidance, and a clean Args/Returns section. It is front-loaded with the core purpose and every sentence serves a distinct function. No fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having an output schema, the description still details the return format and the logic for 'passed'. It covers parameter semantics, domain values, file structure, and usage timing. For a tool with only two parameters and a well-defined output schema, this is complete and leaves no ambiguity for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the full burden. It explains dataset_dir as 'Directory containing one CSV per table' and domain as one of four enumerated values. This fully compensates for the schema's lack of descriptions, giving the agent everything needed to populate both parameters correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Flag values that are physiologically or financially impossible for a domain.' It immediately contrasts with the sibling audit_dataset, distinguishing its purpose clearly. The specific built-in ranges reinforce the scope, making the tool's function unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use: 'after generating a dataset in a regulated or measurement-heavy domain' and when the user asks about plausibility. It also names the alternative audit_dataset and differentiates by checking 'internal consistency' vs 'outside world' values. This gives the agent clear routing criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_yamlValidate a misata.yamlARead-onlyIdempotent
Validate a misata.yaml document at two levels.
Runs both checks in sequence:
Structural — the published JSON Schema (correct field types, required fields, enum values). Catches typos and shape errors.
Semantic —
misata.validate_schema(probabilities sum to 1.0, every foreign_key has a matching Relationship, no cycles, outcome curves reference real columns, etc.). These are the rules that would crash generation; the error messages include suggested fixes.
Use this when an agent has authored or edited a misata.yaml on the
user's behalf and wants to confirm it parses and will actually
generate before invoking generate_dataset.
Args: yaml_text: The full contents of a misata.yaml file as a string.
Returns:
{"valid": true} if both checks pass; otherwise
{"valid": false, "errors": [...], "stage": "structural"|"semantic"}
with the layer that failed first.
| Name | Required | Description | Default |
|---|---|---|---|
| yaml_text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description significantly enriches the annotations (readOnlyHint, idempotentHint) by detailing the two-step execution (structural then semantic), giving examples of semantic rules, and specifying the exact return format including the 'stage' of failure. It doesn't mention any rate limits or auth needs, hence not a 5, but it provides strong context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely well-structured and concise for the complexity it handles. It uses markdown headers for the two validation levels, a 'Use this when' section for guidance, and clearly formatted Args and Returns blocks. Every sentence provides valuable information without unnecessary verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema and detailed annotations, the description perfectly complements them. It explains the two types of validation, the order of execution, and what happens on failure. This is complete for an agent to understand the tool's behavior, when to use it, and what to expect in return.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 0% (no 'description' field in the schema for the parameter), the description explicitly documents the 'yaml_text' parameter: 'The full contents of a misata.yaml file as a string.' This fully compensates for the schema's lack of description, so while it increases transparency, the schema handles the variable type.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool validates a 'misata.yaml' document at two distinct levels (structural and semantic). It uses a specific verb+resource pattern and the detailed explanation of the two checks distinguishes it from sibling tools like 'validate' on other resources or 'inspect_schema'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool: 'Use this when an agent has authored or edited a misata.yaml on the user's behalf...'. It also clearly defines the alternative by mentioning 'before invoking generate_dataset', which is a sibling tool, and contrasts parsing with semantic validation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.9.8- Added
attest_dataset - Added
explain_schema - Added
solve_outcome
1 tool update
v0.1.12- Added
check_realism
2 tool updates
v0.1.11- Added
create_sandbox - Added
query_sandbox
2 tool updates
v0.1.9- Added
audit_dataset - Added
validate_domain
7 tool updates
v0.1.0- First observed
generate_dataset - First observed
generate_from_schema - First observed
inspect_schema - First observed
list_domains - First observed
preview_story - First observed
seed_database - First observed
validate_yaml
TDQS
Scored across 15 tools
There are several overlapping clusters: generate_dataset/generate_from_schema/create_sandbox all produce datasets, preview_story/inspect_schema both inspect a story before generation, and audit_dataset/check_realism/validate_domain all assess dataset quality. The very detailed descriptions usually explain the boundaries, but an agent can still easily misselect within these groups.
All tools use snake_case and are verb-first or verb-resource names, such as list_domains, generate_from_schema, validate_yaml, and query_sandbox. The pattern is predictable throughout, with no camelCase or chaotic conventions.
Fifteen tools fit a rich synthetic-data lifecycle spanning discovery, previewing, schema design, generation, validation, auditing, attestation, sandboxing, and live DB seeding. Each tool maps to a recognizable stage rather than feeling redundant or excessive.
The surface covers the full workflow from domain discovery and story preview through schema explanation, generation, YAML validation, statistical/domain auditing, attestation, sandbox creation/querying, and live database seeding. Obvious lifecycle gaps are hard to identify for a synthetic-data generation server.
Maintenance
Related MCP Connectors
Generate realistic, FK-consistent synthetic test data for your databases from your AI assistant.
Generate realistic relational test data — 156 field types, 22 locales, JSON/CSV/SQL, free previews.
Interactive data visualization and executive PDF dashboards for ChatGPT, Claude, and Cursor.
Privacy-safe synthetic financial data for LatAm fintech, AI agents, testing and ML.
Related MCP Servers
- AlicenseBqualityDmaintenanceGenerates realistic mock data using Faker.js for database seeding, API testing, and development environments. Supports person/company data, custom patterns, multi-locale generation, and structured datasets with referential integrity.460 npm7MIT
- AlicenseNot gradedqualityDmaintenanceEnables creating interactive data visualizations from natural language queries using DuckDB for local databases or Databricks for enterprise data warehouses. Supports multiple chart types, CSV imports, SQL queries, and automatic statistical analysis through Claude Desktop.19MIT
- FlicenseNot gradedqualityDmaintenanceGenerates realistic, context-aware synthetic data for AI agents to populate databases, mock APIs, and create test scenarios without exposing real PII.10 npm3-
- AlicenseAqualityDmaintenanceGenerates realistic, referentially-coherent test data (SQL INSERTs, JSON, or CSV) from your database schema, resolving foreign keys and respecting constraints. Paste CREATE TABLE DDL or a JSON schema and get ready-to-run seed data with valid relationships.213 npmMIT