StatsPAI
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| STATSPAI_MCP_HTTP_TOKEN | No | Bearer token required when using statspai-mcp --transport http and binding any address other than the default 127.0.0.1:8765. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
StatsPAI MCP — agent-native causal inference & econometrics.
Recommended workflow:
detect_design (or pass design= explicitly) to identify the study shape.
preflight + recommend on the data to surface design problems and pick an estimator.
Fit with as_handle=true so you get a result_id you can chain into downstream tools.
audit_result(result_id=...) to enumerate missing robustness checks; for each, call the suggest_function it emits.
honest_did_from_result / sensitivity_from_result for design-specific sensitivity (no need to ferry betas / sigma).
For any next_calls item, dispatch it directly only when ready=true; when ready=false, fill missing_arguments first.
bibtex(keys=[...]) for verified citations — never invent references; paper.bib is the single source of truth.
Economist migration helpers: use prompts/list for stata_command_workflow, r_command_workflow, and cross_language_command_check. For cross-software evidence, read statspai://parity/track-a-summary; it summarizes committed artifacts only and is not a live Stata/R execution.
Data handling: load_data(data_path=... | data_records=[...] | data_csv='...') returns a data_id; pass data_id to any tool instead of re-sending the file. transform_data(data_id=..., operations=[...]) filters / reshapes / winsorises / imputes and returns a new handle whose lineage rides in every result's data_provenance; describe_data profiles a handle; statspai://data/{id} reads it. Lost a data_id or result_id? statspai://handles lists the ones the server still holds.
Data provenance: tools/call responses that load data include data_provenance. Local files carry size, mtime, and SHA-256; remote URLs are sanitized and not re-hashed; inline tables are hashed; handles carry their lineage.
Token economy: pass detail='minimal' on cheap sub-step calls; default 'agent' carries violations + next_steps. Inline plots arrive as image content blocks for vision-capable clients.
Every tool takes the same data / handle / output arguments (data_path, data_id, data_records, data_csv, data_columns, data_sample_n, result_id, as_handle, max_output_bytes, detail); their schemas carry one clause each and statspai://arguments has the full reference. data_columns / data_sample_n are accepted by every tool but listed only on the data tools. detail is 'minimal' (estimate only), 'standard' (+ diagnostics, coefficients) or 'agent' (default; + violations, next steps); as_handle defaults to false.
Server runtime: StatsPAI 1.43.0 on Python 3.12.16 at /opt/venv/bin/python (installed package). describe_function and preflight replies repeat this as server_runtime; statspai doctor in a shell lists the other interpreters and their StatsPAI versions.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| completions | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| auditA | Reviewer-grade audit on a result. Returns the literature checklist (parallel-trends test, honest-DID, Bacon decomposition, placebo, balance, ...) with status per item and the concrete suggest_function to call to fill any missing high-importance check. |
| audit_resultA | Reviewer-grade audit of a fitted result (result_id from an as_handle=true call): every robustness check the literature expects for the design, with status 'passed|failed|missing|not_applicable' and a suggest_function for each missing one. not_applicable checks (an overid test on a just-identified IV) carry a 'reason' and are left out of n_total. |
| bacon_decompositionA | Goodman-Bacon (2021) decomposition: breaks the two-way fixed-effects DID estimator into its 2x2 comparison weights. Reveals whether treated-vs-treated comparisons (which can have negative weights) dominate the estimate. Run this before trusting a TWFE-DID point estimate. Validation: certified parity evidence. |
| bibtexA | Return verified BibTeX entries from paper.bib (StatsPAI's single source of truth for citations). Pass one or more bib keys (e.g. 'callaway2021difference'). NEVER invent citations -- call this tool instead. Unknown keys return an empty entry plus a list of close matches. |
| briefB | One-line brief of a fitted result (estimand, estimate, SE, CI, N). Same output as brief_result. |
| brief_resultA | Return the one-line agent-friendly brief for a fitted result. Uses sp.brief(). Useful when an agent wants to summarise a chained workflow without paying for the full JSON payload again. |
| call_functionA | Run ANY registered StatsPAI function by name with keyword arguments -- the escape hatch for the ~1,200 functions that are not individually listed as tools. |
| callaway_santannaA | Staggered DID (Callaway-Sant'Anna 2021): group-time ATT with doubly-robust, IPW, or regression-adjusted estimators. Robust to heterogeneous treatment effects where TWFE fails. Requires a cohort column g (first-treatment period; 0 = never-treated). Validation: certified evidence with scoped limitations. Known limitations: clustervars accepts a cluster that varies within unit only with panel=False (repeated cross-sections, as Stata csdid without ivar()); on a panel the influence functions are per unit. |
| causalB | End-to-end causal workflow: diagnose -> recommend estimator -> fit -> run robustness -> return result. The one-shot entry point that lets an agent analyse a dataset in a single call without orchestrating stages itself. |
| check_identificationA | Design-level identification diagnostics: bad controls, overlap, cohort sizes, IV first-stage F, clustering. Run BEFORE fitting any estimator to surface design problems. |
| cross_validateA | Cross-validate ONE estimand across INDEPENDENT engines (StatsPAI, pyfixest, linearmodels, DoubleML, R's fixest, Stata) and report whether they agree (AGREE / PARTIAL / DISAGREE / INSUFFICIENT). Use this to honour the cross-package reproducibility rule: trust a number only when >=2 independent implementations reproduce it. Needs a data_path. |
| describe_dataA | Profile a dataset (data_id, data_path or inline data): shape, dtypes, missing counts, head, numeric summary and -- for a handle -- the lineage of transforms that produced it. |
| describe_functionA | Full machine-readable metadata for one registered StatsPAI function: JSON-Schema parameters (types, defaults, enums), assumptions, pre-conditions, failure modes, alternatives, validation tier and evidence notes, plus the accepted keyword aliases. Read this before calling a function that is not in the listed tools. |
| detect_designA | Auto-detect the study design (panel / cross-section / RD / IV-style) from column shapes and types. Returns the guessed design plus the columns that drove the inference. Call this BEFORE recommend() when the user pastes a CSV with no context. |
| didA | Difference-in-differences dispatcher. 2x2 (two periods, 0/1 treat) when id is omitted; with id, a 0/1 indicator on a multi-period panel is converted to first-treatment cohorts and Callaway-Sant'Anna runs. Pass method= to force '2x2', 'cs', 'sa', 'bjs', 'sdid' or 'ddd'. Validation: validated evidence tier (known-truth, reference, external-parity, or Monte Carlo artifact). |
| dmlA | Double/debiased machine learning (Chernozhukov et al. 2018) with cross-fitting: partially linear (plr), interactive (irm, binary treatment), and the IV versions (pliv, iivm). Treatment effect under selection on observables with flexible nuisance models. Validation: certified evidence with scoped limitations. Known limitations: external_predictions, store_oof, and observation_ids are Python-only and absent from JSON/MCP inputs; external records accept no dict, JSON string, or file path; store_oof=True retains individual-level records for get_oof() and get_residuals() in memory only; ordinary serialization omits them; Retained IRM needs at least 10 rows per treatment arm in each training fold or raises DataInsufficient instead of fallback; internal explicit fold_indices require n_rep=1, while external repeated IRM records are allowed when the explicit partition is equivalent for every repeat. |
| ebalanceB | Hainmueller (2012) entropy balancing. Targets the ATT by exactly balancing covariate means across treatment groups. No propensity-score model specification needed. Validation: certified parity evidence. |
| feolsB | OLS with high-dimensional fixed effects (R fixest / Stata reghdfe syntax): 'y ~ x1 + x2 | unit + year'. IV as 'y ~ x | fe | d ~ z'. vcov: 'iid', 'hetero', or {'CRV1': 'cluster_col'} (two-way: 'a + b'). Validation: certified parity evidence. |
| from_rA | Translate a single R / fixest / felm / did expression to a verified StatsPAI tool-call payload. Returns the same shape as from_stata. Supported callables: feols / felm / lm / att_gt / did. Pass ONE expression -- no assignment, no piping. Validation: validated evidence tier (known-truth, reference, external-parity, or Monte Carlo artifact). |
| from_stataA | Translate a single Stata command to a verified StatsPAI tool-call payload. Returns |
| honest_didA | Rambachan-Roth (2023) 'honest' DID sensitivity analysis. Operates on a fitted event-study / DID result: pass |
| honest_did_from_resultB | Rambachan-Roth (2023) honest CIs on a fitted DID / event-study result; betas and sigma are read off the result. Validation: validated evidence tier (known-truth, reference, external-parity, or Monte Carlo artifact). |
| interpret_resultA | Natural-language interpretation of a fitted result (result_id): the estimate, its uncertainty and what the design does / does not identify, grounded in the result's own numbers. Uses the client's model via MCP sampling when advertised (no API key); otherwise returns a deterministic structured brief, never an invented narrative. |
| ivA | Instrumental-variables dispatcher: 2SLS, LIML, Fuller or GMM via method=, with first-stage, weak-IV (effective F) and endogeneity diagnostics. Formula 'y ~ x + (d ~ z1 + z2)'. Validation: certified parity evidence. |
| ivregA | 2SLS instrumental-variables regression with first-stage F diagnostics; classical SEs unless robust=. Formula syntax: 'y ~ x_exog + (d_endog ~ z_instrument)'. Validation: certified parity evidence. |
| load_dataA | Load a dataset into the server and get a data_id handle. Source: data_path (file or URL), data_records (JSON rows) or data_csv (CSV text). Returns the handle plus shape, dtypes, missing counts, the first rows and a numeric summary. Pass data_id to any later tool instead of re-sending the file; chain transform_data to filter / reshape / winsorise / impute and get a new handle whose lineage is recorded in every result's data_provenance. |
| matchA | Matching estimator dispatcher (ATT by default): nearest-neighbour on the propensity score or Mahalanobis distance, Abadie-Imbens nnmatch, CEM, optimal / full matching, kernel, radius, ... via method=. Returns balance diagnostics. Validation: certified evidence with scoped limitations. Known limitations: greedy nearest-neighbour matching without replacement is order-dependent: the m_order convention can differ across packages and materially moves the estimate (>5x spread on MatchIt::lalonde with Mahalanobis distance). m_order='data' and 'closest' reproduce MatchIt exactly; m_order='farthest' is StatsPAI's own dynamic rule and is not MatchIt-equivalent; bias_correction=True follows a different convention from Matching::Match's BiasAdjust: StatsPAI regresses on the full covariate vector with unweighted OLS over all controls, the reference regresses on the matching variables weighted by match counts, so bias-corrected estimates can differ from it by about 0.1%. The uncorrected estimate and its Abadie-Imbens standard error are exact. |
| pipeline_didA | End-to-end DID workflow: preflight -> did/CS estimator -> audit -> honest-DID sensitivity -> bacon decomposition -> brief. Returns one markdown report + the primary result_id. Use this when the user pastes a DID dataset and asks 'is the effect real?' -- the pipeline runs every diagnostic the literature expects. |
| pipeline_ivA | End-to-end IV workflow: ivreg -> first-stage F (effective + Olea-Pflueger) -> Anderson-Rubin CI -> e-value. Returns one markdown report + result_id. |
| pipeline_rdA | End-to-end RD workflow: rdrobust -> rdplot (PNG image) -> rddensity (McCrary) -> rdsensitivity (bandwidth). Returns one markdown report + result_id + an image content block. |
| plot_from_resultA | Render a fitted result's diagnostic plot (event study, rdplot, synth gap, balance, ROC) as a PNG image block. Optional edits restyle it with the data locked. |
| preflightA | Run pre-fit identification checks for a chosen method on a DataFrame. Verdict in {PASS, WARN, FAIL}. ALWAYS call this before fitting on an unfamiliar dataset to surface design problems (overlap, cohort sizes, IV first-stage F, running-variable density at the cutoff). |
| rdrobustA | Sharp or fuzzy regression-discontinuity with robust bias-corrected CIs (Calonico-Cattaneo-Titiunik 2014). Use fuzzy= for IV-style fuzzy RD. Validation: certified evidence with scoped limitations. Known limitations: the weighted rbc bootstrap is not supported -- passing weights= with bootstrap='rbc' raises MethodIncompatibility; R-parity certification applies only to the configurations enumerated by sp.validation_scope(function='rdrobust') -- the default native mserd / triangular / p=1 / nn path (Track A 06), a manual bandwidth, and the weighted rows -- other selectors, kernels and vce choices are pinned for sp.rdbwselect or not at all for this entry point. |
| recommendA | Method advisor: given a dataset + research question, recommends a ranked list of estimators with reasoning, precondition checks, and a full suggested workflow. This is the first call an agent should make if it doesn't know which estimator to run. Supports DAG input, mediator / proxy / principal-strata variables, and optional resampling-stability verification. |
| regressA | Fit an OLS regression; classical SEs unless robust= or cluster=. Input is a Wilkinson-style formula like 'y ~ x1 + x2'. Use this for baseline specifications or covariate-adjusted RCT analyses. Validation: certified parity evidence. |
| route_estimatorA | Route a research question to estimator calls without data. Give the family (did / iv / rd / matching / ml_causal / qte / dynamic_panel) and answers to its decision questions; get the matching registered functions with example calls, why each is right, the assumptions it adds and the guide section to read, plus the unanswered questions and the one that narrows the choice most. Call with no answers to see the questions. The full guide is readable at statspai://guide/{family}. |
| sdidA | Synthetic difference-in-differences (Arkhangelsky et al. 2021): unit and time weights, one treated unit or block. Long panel; placebo / bootstrap / jackknife SEs. Validation: certified parity evidence. |
| search_functionsA | Search the StatsPAI function registry by task keywords or a short phrase (e.g. 'staggered adoption event study', 'weak instrument robust CI'). Returns ranked matches with one-line descriptions, category and validation tier. Use it when no listed tool fits, then describe_function for the parameters and call_function to run it. |
| sensitivityB | Unified sensitivity analysis for observational causal estimates -- supports Oster (2019) delta/R-max, Cinelli-Hazlett (2020) omitted-variable bias bounds, and E-values (VanderWeele-Ding 2017). Tells the agent how strong an unobserved confounder would have to be to overturn the result. Validation: certified parity evidence. |
| sensitivity_from_resultA | Sensitivity of a cached fit (result_id). 'evalue' (default): E-value from the estimate. 'oster' (delta / R-max) and 'cinelli_hazlett' (OVB bounds) refit OLS of y on treat + controls on the fit's data: from a regress formula (name the term with treat) or passed as y / treat / controls. 'auto': sensitivity dashboard. |
| spec_curveA | Specification-curve analysis (Simonsohn et al. 2020): enumerates every combination of model choices the user declares defensible, runs them all, and returns the sign/magnitude distribution. Use when an agent needs to report robustness across a researcher-degree-of-freedom multiverse. Validation: validated evidence tier (known-truth, reference, external-parity, or Monte Carlo artifact). |
| sun_abrahamA | Sun-Abraham (2021) interaction-weighted event study for staggered adoption (Stata eventstudyinteract, fixest sunab). Cohort column g = first-treatment period, 0 / NaN never treated. Validation: certified parity evidence. |
| synthA | Synthetic control (Abadie et al.) and its variants through one entry: classic SCM with placebo inference, synthetic DiD, augmented / penalized SCM, generalized SC (gsynth), staggered adoption and more via method=. Panel in long format, one treated unit (staggered: a treatment column instead). Validation: certified evidence with scoped limitations. Known limitations: Classical SCM certification is specification-specific: ADH/Synth parity requires passing the same special_predictors recipe; the default outcome-only V=I path is a documented Kaul-style convention; Default native classical SCM can differ from Synth on Basque-style panels by a documented local-optimum convention (the outer V optimisation has multiple near-equivalent minima); use backend='synth' or canonical special_predictors when exact R parity is required. |
| transform_dataA | Derive a new dataset from a data_id (or data_path / inline data) by applying |
| vcov_from_resultA | Standard errors of a cached fit (result_id) under another vce: re-runs the fit's own call with only vce= changed, so the SEs equal a direct refit. One vce returns the new result; a list returns a side-by-side table with the ratio to the fitted SE. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| audit_did_result | Run a DID estimator on a CSV, surface the estimate, and walk through every reviewer-checklist gap. Uses pipeline_did to consolidate preflight + estimate + audit + honest-DID + Bacon into one call. |
| audit_iv_result | End-to-end IV workflow: 2SLS + first-stage F + Anderson-Rubin CI + e-value sensitivity, all wrapped in pipeline_iv. |
| audit_rd_result | End-to-end RD workflow: rdrobust + rdplot (image content) + density test + bandwidth sensitivity via pipeline_rd. |
| design_then_estimate | Given an unfamiliar CSV, auto-detect the study design, recommend an estimator, run it with diagnostics. |
| robustness_followup | Take an existing fitted result handle and run all high-importance follow-up sensitivities the audit identifies as missing. |
| paper_render | Compose a paper-style memo from a fitted result handle: estimate, diagnostics, robustness, BibTeX. The output is a ready-to-paste markdown section. |
| compare_methods | Run two or more estimators on the same data and compare conclusions side by side. |
| policy_evaluation | Causal-forest-driven policy evaluation: fit causal_forest, summarise CATE, evaluate a candidate policy. |
| synth_full | End-to-end Synthetic Control workflow: synth fit + placebo + synthdid + permutation. |
| decompose_inequality | RIF / FFL / Oaxaca-Blinder decomposition of an outcome gap. |
| stata_command_workflow | Translate one Stata command, run the matched StatsPAI tool on the supplied data, then audit the fitted result. Use when a user pastes commands such as reghdfe, csdid, rdrobust, ivreg2, synth, psmatch2, or teffects workflows. |
| r_command_workflow | Translate one R / fixest / felm / did expression, run the matched StatsPAI tool on the supplied data, then audit the result. Use for users migrating R code into the MCP loop. |
| cross_language_command_check | Compare one Stata command and one R expression through StatsPAI's translators before fitting. This is a cheap guard against Stata/R snippets targeting different estimands or covariance conventions. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| StatsPAI estimator catalog | Markdown list of every registered StatsPAI estimator with its description and a pointer to the per-function agent-card URI pattern. |
| StatsPAI tool index (machine-readable) | JSON array of {name, description} entries. Read this once during session setup to enumerate available tools. |
| StatsPAI result output schema | JSON Schema for the agent-facing result envelope returned by every tools/call (estimate / std_error / conf_int / method / diagnostics / violations / next_steps / citations / error …). Each tool's outputSchema points here for the full field-by-field reference. |
| StatsPAI common tool arguments | Full reference for the data / handle / output arguments every tool accepts (data_path, data_id, inline tables, sampling, result_id, as_handle, max_output_bytes, detail). Tool schemas carry one clause per argument; this is the long form. |
| StatsPAI live handles | The data_id / result_id handles this server still holds, newest first, with shape, source, producing tool and replay call. Read it to recover handles lost to context compaction instead of reloading or refitting. |
| StatsPAI Track A parity summary | Machine-readable summary of committed Python/R/Stata parity evidence: strictness-tier counts, module ids, Stata commands, and convention notes where available. This summarizes artifacts; it is not a live external Stata/R run. |
TDQS
Scored across 45 tools
Descriptions work hard to cross-reference each other (e.g., brief says 'Same output as brief_result'; honest_did points to honest_did_from_result), but several pairs genuinely overlap: brief/brief_result, audit/audit_result, sensitivity/sensitivity_from_result, iv vs ivreg, and honest_did vs honest_did_from_result. The advisory cluster (detect_design, check_identification, preflight, recommend, route_estimator, causal) is also hard to separate without reading ordering hints, though the descriptions do provide them.
Mostly snake_case, but two conventions coexist: verb_noun for plumbing (load_data, transform_data, search_functions, plot_from_result) and bare estimator/package names for methods (did, iv, dml, synth, match, sdid, feols, ivreg, rdrobust, ebalance). The result-accessor suffix is also inconsistent, mixing '_result' (brief_result, audit_result) with '_from_result' (honest_did_from_result, sensitivity_from_result, vcov_from_result, plot_from_result).
45 individually listed tools is heavy for any single server, and several slots are redundant duplicates (brief vs brief_result, audit vs audit_result, sensitivity vs sensitivity_from_result) rather than earned surface. The search_functions/describe_function/call_function escape hatch already covers the ~1,200-function registry, so the long tail of listed estimator tools is partly unnecessary.
Coverage of the causal-inference lifecycle is strong: data load/transform/profile, design detection and preflight, estimators across DID/IV/RD/matching/DML/synth, robustness and sensitivity, pipelines, plotting, interpretation, and citation lookup. The main gap is state management — there is no way to list existing data_ids or result_ids, or to delete/export them, which forces agents to carry handles out-of-band.