# io.github.mrnh/rigor-mcp (pypi · rigor-mcp)

Verified statistical inference for AI agents: hypothesis tests, sequential testing, power.

- Trust score: 66/100 (medium)
- Change this week: −2
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-21

## Components

- pypi · `rigor-mcp`: 66/100 (this document), [markdown](https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp.md), [page](https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp)

## Channel facts

- Registry: `pypi`
- Package: `rigor-mcp`
- Version: `0.5.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-21.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs setuptools.build_meta at install time, a recognised native-build step with no shell scripting around it.
  - 1 of 29 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 45/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 3 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 71/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 6513 tokens (~176/item across 37 items; 37 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 83/100
  - Stability observed for 25 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (22% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 37 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 37 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the io.github.mrnh/rigor-mcp server?

io.github.mrnh/rigor-mcp runs locally as a PyPI package, launched with uvx rigor-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add mrnh-rigor-mcp -- uvx rigor-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "mrnh-rigor-mcp": {
      "command": "uvx",
      "args": [
        "rigor-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "mrnh-rigor-mcp": {
      "command": "uvx",
      "args": [
        "rigor-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add mrnh-rigor-mcp -- uvx rigor-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "mrnh-rigor-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "rigor-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add mrnh-rigor-mcp --command uvx --arg rigor-mcp
```

### Hermes

```yaml
mcp_servers:
  mrnh-rigor-mcp:
    command: "uvx"
    args: ["rigor-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "mrnh-rigor-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "rigor-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add mrnh-rigor-mcp -t stdio -c uvx -a rigor-mcp
```

### Other

```json
{
  "mcpServers": {
    "mrnh-rigor-mcp": {
      "command": "uvx",
      "args": [
        "rigor-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-19 (score 66, −3)

- [functional] Stability: pass → 0.77

### 2026-09-17 (score 69, 0)

- [security] Stability: 0.97 → pass
- [functional regression] Schema quality: 5247 → 6513
- [functional] Package version: 0.3.0 → 0.5.0

### 2026-09-16 (score 69, +1)

No change was recorded against any check on this day. Stability & Change Management went from 93 to 97. That category is still filling its 30-day observation window: 28 days of observed history at the previous scan, 29 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-14 (score 68, −14)

- [security regression] Malware scan: pass → unverified

### 2026-09-12 (score 82, +1)

No change was recorded against any check on this day. Stability & Change Management went from 80 to 83. That category is still filling its 30-day observation window: 24 days of observed history at the previous scan, 25 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-11 (score 81, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-10 (score 66, +1)

No change was recorded against any check on this day. Stability & Change Management went from 73 to 77. That category is still filling its 30-day observation window: 22 days of observed history at the previous scan, 23 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-09 (score 65, −15)

- [security regression] Malware scan: pass → unverified

## MCP tools (37)

### `one_sample_t_test` (~109 tokens)

Test whether a sample's mean differs from a hypothesized value mu0.
Returns the t-statistic, degrees of freedom, two-tailed p-value, a
confidence interval for the mean, and any assumption warnings.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `data` (array, required): the sample; one number per observation
- `mu0` (number, required): the hypothesized population mean to test the sample against

### `two_sample_t_test` (~115 tokens)

Test whether two independent samples have different means. Defaults
to Welch's t-test (does not assume equal variances); pass
equal_var=true for the classic pooled-variance test.

Input parameters:

- `a` (array, required): first independent sample
- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `b` (array, required): second independent sample
- `equal_var` (boolean): assume equal population variances (classic pooled-variance test) instead of Welch's test

### `paired_t_test` (~180 tokens)

Test whether the mean difference between paired observations (e.g.
before/after measurements on the same subjects, or matched pairs) is
zero. a[i] and b[i] must be the two measurements of the same pair --
use two_sample_t_test instead if the two samples are independent
(different subjects in each group). Returns the t-statistic, degrees
of freedom (n-1), two-tailed p-value, a confidence interval for the
mean difference, a citation, and assumption warnings.

Input parameters:

- `a` (array, required): first measurement of each pair, e.g. 'before'
- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `b` (array, required): second measurement of each pair, e.g. 'after' -- same length and pairing order as a

### `one_proportion_z_test` (~189 tokens)

Test whether an observed proportion (successes out of n) differs
from a hypothesized proportion p0 -- e.g. "is this coin fair (p0=0.5)
given 55 heads in 100 flips?" Uses the normal approximation, which
degrades for small n or p0 near 0 or 1; a warning is included when
that assumption looks shaky. Returns the z-statistic, two-tailed
p-value, a confidence interval for the true proportion, a citation,
and warnings.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `n` (integer, required): total number of trials/observations
- `p0` (number, required): the hypothesized true proportion to test against, in [0, 1]
- `successes` (integer, required): number of successes observed

### `two_proportion_z_test` (~147 tokens)

Test whether two independent proportions differ -- the standard test
behind comparing conversion rates between two groups (e.g. an A/B
test). Returns the z-statistic, two-tailed p-value, a confidence
interval for the difference in proportions, a citation, and
warnings.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `n1` (integer, required): total observations in group 1
- `n2` (integer, required): total observations in group 2
- `successes1` (integer, required): successes observed in group 1
- `successes2` (integer, required): successes observed in group 2

### `chi_square_goodness_of_fit` (~155 tokens)

Test whether observed category counts match an expected
distribution -- e.g. "are these six days-of-week signup counts
evenly distributed, or skewed towards weekends?" Returns the
chi-squared statistic, degrees of freedom (len-1), p-value, a
citation, and a warning if any expected count is below 5 (the usual
threshold below which this approximation gets unreliable).

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `expected` (array, required): expected count per category, same length and category order as observed; does not need to sum to the same total
- `observed` (array, required): observed count per category

### `chi_square_independence` (~151 tokens)

Test whether the row and column variables of a contingency table
are independent (e.g. "does group membership relate to outcome?").
Returns the chi-squared statistic, degrees of freedom, p-value, a
citation, and a warning if any expected cell count is below 5
(consider cramers_v afterwards for effect size).

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `table` (array, required): contingency table as a list of rows, each a list of raw counts (not proportions), e.g. [[treated_success, treated_failure], [control_success, control_failure]] for a 2x2 table

### `one_way_anova` (~172 tokens)

Test whether three or more independent groups have different
means -- e.g. comparing average order value across three marketing
channels. A significant result means at least one group differs from
the others, not which one -- follow up with pairwise
two_sample_t_test calls (correcting for multiple comparisons via
bonferroni_correction or benjamini_hochberg_correction) to find
which. Returns the F-statistic, between/within degrees of freedom,
p-value, a citation, and a warning if within-group df is small.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `groups` (array, required): one list of observations per group; at least 3 groups, each with at least 2 observations

### `levene_test` (~166 tokens)

Test whether two or more groups have equal population variances
(homogeneity of variance) -- use this to decide equal_var for
two_sample_t_test, or to sanity-check one_way_anova's
equal-variance assumption. Uses the Brown-Forsythe variant
(deviations from each group's median), more robust to non-normal
data than the original mean-based Levene's test. Returns the same
shape as one_way_anova (it's computed as one internally, on
absolute deviations from each group's median).

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `groups` (array, required): one list of observations per group; at least 2 groups, each with at least 2 observations

### `fisher_exact_test` (~180 tokens)

Test whether the row and column variables of a 2x2 contingency
table are independent -- exact (via the hypergeometric distribution
over all tables with the same margins), unlike
chi_square_independence's chi-squared approximation. Use this
instead whenever chi_square_independence warns an expected cell
count is below 5, or whenever the sample is small. 2x2 tables only.
Returns the sample odds ratio as ``statistic`` (can be inf/0 for a
zero cell), a two-tailed p-value, a citation, and warnings.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `table` (array, required): 2x2 contingency table as [[a, b], [c, d]], raw non-negative integer counts

### `mcnemar_test` (~237 tokens)

Test whether two paired proportions are equal -- e.g. the same
subjects' yes/no answers before and after an intervention, or two
raters' calls on the same items. Use this instead of
two_proportion_z_test whenever the "two groups" are actually the
same subjects measured twice; two_proportion_z_test assumes
independent groups and gets the standard error wrong for paired
data. Yates continuity-corrected chi-squared, 1 df -- use
mcnemar_exact_test instead when there are few discordant pairs
(this warns when there are). Returns that chi-squared statistic, a
p-value, and a confidence interval for the difference in marginal
proportions.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `table` (array, required): 2x2 table as [[a, b], [c, d]]: a/d are pairs that agree both times, b/c are the discordant pairs (b: positive then negative, c: negative then positive) -- raw non-negative integer counts

### `mcnemar_exact_test` (~161 tokens)

Exact version of mcnemar_test: an exact binomial test (p=0.5) on
the discordant pairs instead of the chi-squared approximation -- the
small-sample-safe alternative mcnemar_test's own warning points to,
the same relationship fisher_exact_test has to
chi_square_independence. ``statistic`` is b-c (the raw
discordant-pair imbalance); the p-value is two-tailed.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `table` (array, required): 2x2 table as [[a, b], [c, d]], same layout as mcnemar_test -- raw non-negative integer counts

### `cohens_d` (~144 tokens)

Standardized mean difference between two samples (pooled SD).
Use alongside two_sample_t_test, which tells you whether a
difference is significant but not how large it is. Rough guidance:
\~0.2 small, ~0.5 medium, ~0.8 large -- context-dependent. Returns
{"value": float or null, "warnings": [...]}. value is null only
when both samples have zero variance and unequal means, where the
effect size is mathematically infinite -- see the warning for which
direction, and report the raw mean difference instead in that case.

Input parameters:

- `a` (array, required): first sample
- `b` (array, required): second sample

### `cohens_h` (~165 tokens)

Effect size for a difference between two proportions (Cohen,
1988), via the arcsine-square-root transform -- more appropriate
than a raw percentage-point difference since it stabilizes variance
across the full [0, 1] range. p1 and p2 are interchangeable (the
sign of the result just indicates direction); use alongside
two_proportion_z_test, which tells you whether a difference is
significant but not how large it is. Returns a float (can be
negative); rough guidance: ~0.2 small, ~0.5 medium, ~0.8 large.

Input parameters:

- `p1` (number, required): a proportion in [0, 1]
- `p2` (number, required): a proportion in [0, 1]

Output parameters:

- `result` (number)

### `cramers_v` (~195 tokens)

Effect size for a chi-squared test of independence (Cramer, 1946),
normalized to [0, 1] regardless of table shape so it's comparable
across tables of different sizes, unlike the raw chi-squared
statistic. Call after chi_square_independence, passing its
statistic and the same table's n/rows/cols. Returns a float in
[0, 1]; rough guidance for a 2x2 table: ~0.1 small, ~0.3 medium,
\~0.5 large -- the threshold shifts for larger tables.

Input parameters:

- `chi2_statistic` (number, required): the chi-squared statistic from chi_square_independence on the same table
- `cols` (integer, required): number of columns in the table
- `n` (integer, required): total number of observations in the table
- `rows` (integer, required): number of rows in the table

Output parameters:

- `result` (number)

### `eta_squared` (~121 tokens)

Effect size for a one-way ANOVA: proportion of total variance
explained by group membership. Use alongside one_way_anova, which
tells you whether groups differ but not how much of the variance
that accounts for. Rough guidance: ~0.01 small, ~0.06 medium, ~0.14
large. Biased upward for small samples -- prefer omega_squared when
that matters. Returns a float in [0, 1].

Input parameters:

- `groups` (array, required): one list of observations per group; at least 2 groups

Output parameters:

- `result` (number)

### `omega_squared` (~85 tokens)

Effect size for a one-way ANOVA, less biased than eta_squared for
small samples since it subtracts out the variance explained by
chance alone. Use alongside one_way_anova. Can be slightly negative
when the true effect is near zero -- that's expected, not an error.

Input parameters:

- `groups` (array, required): one list of observations per group; at least 2 groups

Output parameters:

- `result` (number)

### `rank_biserial_correlation` (~174 tokens)

Effect size for a Mann-Whitney U test. Call after mann_whitney_u,
passing its statistic and the two sample sizes. Positive means
sample 1's values tend to exceed sample 2's; negative means the
reverse; 0 is no tendency either way. Returns a float in [-1, 1];
rough guidance mirrors Cohen's d: ~0.1 small, ~0.3 medium, ~0.5
large.

Input parameters:

- `n1` (integer, required): size of the first sample passed to mann_whitney_u
- `n2` (integer, required): size of the second sample passed to mann_whitney_u
- `u1_statistic` (number, required): the statistic returned by mann_whitney_u (U for the first sample passed to it)

Output parameters:

- `result` (number)

### `pearson_correlation` (~203 tokens)

Test for a *linear* association between two paired variables --
e.g. "does hours studied predict test score?" statistic is r itself
(in [-1, 1]), not a t-statistic. Returns r, df (n-2), a two-tailed
p-value (H0: r=0), a confidence interval for r via the Fisher
z-transform, a citation, and warnings. Use spearman_correlation
instead if the relationship may be monotonic but not linear, or if
outliers shouldn't dominate the result. Use simple_linear_regression
instead for the actual slope (units of y per unit of x), not just
the strength of association.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `x` (array, required): first variable, one value per observation
- `y` (array, required): second variable, same length and pairing order as x

### `spearman_correlation` (~131 tokens)

Test for a *monotonic* association between two paired variables,
via the Pearson correlation of their ranks -- doesn't assume
linearity and is far less sensitive to outliers' exact magnitude
than pearson_correlation. Same return shape as pearson_correlation
(statistic is rho itself, in [-1, 1]).

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `x` (array, required): first variable, one value per observation
- `y` (array, required): second variable, same length and pairing order as x

### `simple_linear_regression` (~162 tokens)

Fit y = intercept + slope * x by ordinary least squares -- single
predictor only. Reports the slope (change in y per unit of x), the
intercept, R^2 (proportion of y's variance explained by x), and a
significance test + confidence interval for the slope (H0:
slope=0). Use pearson_correlation instead if you only need the
strength of a linear association, not its actual units/magnitude.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `x` (array, required): the predictor variable, one value per observation
- `y` (array, required): the outcome variable, same length and pairing order as x

### `mann_whitney_u` (~170 tokens)

The non-parametric alternative to two_sample_t_test -- use when
that test's own small-n warning makes a normal-theory result
suspect, or the data is ordinal/skewed. Tests whether values from
sample a are systematically larger or smaller than values from
sample b, by ranking the combined data rather than assuming normal
populations. statistic is U for sample a; pair with
rank_biserial_correlation for a standardized effect size. Returns
the same result shape as the parametric tests (statistic, p_value,
citation, warnings).

Input parameters:

- `a` (array, required): first independent sample
- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `b` (array, required): second independent sample

### `wilcoxon_signed_rank` (~163 tokens)

The non-parametric alternative to paired_t_test -- use when that
test's own small-n warning makes a normal-theory result suspect.
Tests whether the median of the paired differences is zero, by
ranking the absolute differences rather than assuming they're
normally distributed. Pairs with a zero difference are dropped (and
counted in a warning), the standard procedure. statistic is T =
min(W+, W-).

Input parameters:

- `a` (array, required): first measurement of each pair, e.g. 'before'
- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `b` (array, required): second measurement of each pair, e.g. 'after' -- same length and pairing order as a

### `kruskal_wallis` (~130 tokens)

The non-parametric alternative to one_way_anova -- use when that
test's own small-df warning makes a normal-theory result suspect.
Tests whether all groups are drawn from the same distribution, by
ranking the combined data rather than assuming normal populations.
A significant result means at least one group differs, not which
one -- same caveat as one_way_anova.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `groups` (array, required): one list of observations per group; at least 2 groups

### `sample_size_for_two_sample_t_test` (~124 tokens)

How many observations per group are needed to detect a given
Cohen's d with a two-sample t-test at the target power. Returns a
continuous value and a rounded-up integer to actually use.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `effect_size_d` (number, required): the Cohen's d you want to be able to detect
- `target_power` (number): desired probability of detecting the effect if it's real; 0.8 is the conventional target

### `power_for_two_sample_t_test` (~176 tokens)

Statistical power to detect a given Cohen's d with n_per_group
observations per group, using a two-sample t-test. Power is the
probability of correctly detecting a real effect of this size at
the given alpha; a design with low power means a non-significant
result would be inconclusive rather than good evidence the effect
doesn't exist. Use sample_size_for_two_sample_t_test instead to
solve for n given a target power. Returns a float in [alpha, 1].

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `effect_size_d` (number, required): the Cohen's d you want to be able to detect
- `n_per_group` (number, required): planned (or actual) observations per group

Output parameters:

- `result` (number)

### `sample_size_for_one_sample_t_test` (~157 tokens)

How many observations are needed to detect a given Cohen's d with
a one-sample (or paired) t-test at the target power. Use for
paired_t_test too -- a paired t-test is a one-sample t-test on the
differences, so the same power formula applies. Returns a
continuous value and a rounded-up integer to actually use.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `effect_size_d` (number, required): the Cohen's d you want to be able to detect
- `target_power` (number): desired probability of detecting the effect if it's real; 0.8 is the conventional target

### `power_for_one_sample_t_test` (~150 tokens)

Statistical power to detect a given Cohen's d with n observations,
using a one-sample (or paired) t-test. Use for paired_t_test too --
it's a one-sample t-test on the differences, so the same power
formula applies. Use sample_size_for_one_sample_t_test instead to
solve for n given a target power. Returns a float in [alpha, 1].

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `effect_size_d` (number, required): the Cohen's d you want to be able to detect
- `n` (number, required): planned (or actual) number of observations

Output parameters:

- `result` (number)

### `sample_size_for_two_proportion_test` (~134 tokens)

How many observations per group are needed to detect a difference
between two proportions (e.g. conversion rates) at the target power.
p1 and p2 are interchangeable -- only their difference matters.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `p1` (number, required): a proportion in [0, 1]
- `p2` (number, required): a proportion in [0, 1]
- `target_power` (number): desired probability of detecting the effect if it's real; 0.8 is the conventional target

### `power_for_two_proportion_test` (~174 tokens)

Statistical power to detect a difference between two proportions
(e.g. two conversion rates) with n_per_group observations in each
group, using a two-proportion z-test. p1 and p2 are interchangeable
(only their difference matters) -- e.g. current vs. new conversion
rate. Use sample_size_for_two_proportion_test instead to solve for n
given a target power. Returns a float in [alpha, 1].

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `n_per_group` (number, required): planned (or actual) observations per group
- `p1` (number, required): a proportion in [0, 1]
- `p2` (number, required): a proportion in [0, 1]

Output parameters:

- `result` (number)

### `bonferroni_correction` (~78 tokens)

Adjust a batch of p-values for multiple comparisons, controlling
the family-wise error rate. Conservative; use when any false positive
among the batch is costly.

Input parameters:

- `alpha` (number): family-wise significance level to control; default 0.05
- `p_values` (array, required): the batch of p-values to adjust

### `benjamini_hochberg_correction` (~83 tokens)

Adjust a batch of p-values for multiple comparisons, controlling
the false discovery rate. Less conservative than Bonferroni; the
standard choice when testing many hypotheses at once.

Input parameters:

- `alpha` (number): false discovery rate to control; default 0.05
- `p_values` (array, required): the batch of p-values to adjust

### `recommend_test` (~436 tokens)

Not sure which rigor tool fits your question? Answer a few
characteristics of the data and get back which tool to call, why,
what to call instead if this test's assumptions look shaky, and
what to run alongside it (an effect size, a power calculation, a
natural follow-up). Every test in this package already documents
this guidance in its own docstring for the sibling comparisons it
knows about -- this tool exists so you don't have to have already
read every other tool's docstring to find the one relevant
cross-reference. Pure decision logic, no statistics computed here.

Input parameters:

- `checked_repeatedly` (boolean): will this result be checked more than once as data accumulates (e.g. a live experiment's dashboard) rather than analyzed once against a pre-committed sample size? routes to a peeking-safe sequential_…
- `n_groups` (integer): 1 = one sample vs. a hypothesized value; 2 = two groups/conditions; 3+ = three or more groups. Ignored when testing_association=true.
- `outcome_type` (string, required): what kind of thing is being compared/measured: "continuous" (means), "proportion" (rates), "count_or_category" (category counts / contingency tables), or "rank_or_ordinal" (ordinal data -- always rou…
- `paired` (boolean): for n_groups=2 (continuous/rank_or_ordinal/proportion): were the same subjects measured twice, rather than two independent groups?
- `small_or_skewed` (boolean): is the sample small, visibly skewed, or outlier-heavy? nudges toward the non-parametric alternative
- `testing_association` (boolean): this is "does x relate to/predict y" for two continuous or ranked variables, not a group comparison -- routes to correlation/regression instead
- `two_categorical_variables` (boolean): for outcome_type="count_or_category": testing association between two categorical variables (a contingency table) rather than counts against an expected distribution?

### `sequential_two_sample_mean_test` (~329 tokens)

Always-valid test of whether two groups' means differ, safe to
call again after every new observation in either group -- unlike
two_sample_t_test, which needs a sample size decided in advance and
gives no such guarantee if checked repeatedly and stopped at the
first significant look (that repeated-checking failure mode is
exactly what inflates false positives; see naive_peeking_inflation
for a demonstration). Use this instead of two_sample_t_test whenever
a result will be (or already has been) checked more than once as
data accumulates, e.g. monitoring a live experiment. Returns the
current effect estimate, its standard error, the mixture likelihood
ratio and always-valid p-value, and assumption warnings. tau does
not need to be exact -- reuse the minimum-detectable-effect you'd
otherwise plug into sample_size_for_two_sample_t_test.

Input parameters:

- `a` (array, required): first group's observations so far -- can be re-checked as more come in
- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `b` (array, required): second group's observations so far, same units as a
- `equal_var` (boolean): assume equal population variances (pooled) instead of Welch's, same meaning as two_sample_t_test's equal_var
- `tau` (number, required): mixing prior's standard deviation over the true mean difference, in a/b's own units -- e.g. the smallest difference worth caring about. Not a threshold; see the tool's docstring

### `sequential_two_proportion_test` (~281 tokens)

Always-valid test of whether two proportions (e.g. two conversion
rates in a live A/B test) differ, safe to call again after every new
observation in either group -- the sequential-monitoring counterpart
to two_proportion_z_test. Use this instead whenever the result will
be checked more than once before the experiment ends, which is the
normal case for a live dashboard rather than a one-shot analysis.
p1 and p2 are interchangeable (only their difference matters). tau
does not need to be exact -- reuse the minimum-detectable-effect
you'd otherwise plug into sample_size_for_two_proportion_test.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `n1` (integer, required): observations so far in group 1
- `n2` (integer, required): observations so far in group 2
- `successes1` (integer, required): successes (e.g. conversions) observed so far in group 1
- `successes2` (integer, required): successes observed so far in group 2
- `tau` (number, required): mixing prior's standard deviation over the true proportion difference -- e.g. 0.02 for 'I mainly care about a 2-point-or-larger swing'. Not a threshold; see the tool's docstring

### `naive_peeking_inflation` (~199 tokens)

Demonstrates, by simulation, why sequential_two_sample_mean_test /
sequential_two_proportion_test exist: the actual false-positive rate
of checking an *ordinary* fixed-sample test (two_sample_t_test,
two_proportion_z_test, ...) after every new observation and stopping
the first time it clears alpha, versus the alpha actually intended.
Call this to show a skeptical stakeholder concretely what "just
peek at the dashboard and stop early" costs before recommending the
always-valid alternative. Returns the estimated true false-positive
rate, its Monte Carlo standard error, and a citation.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `n_looks` (integer, required): how many times the result gets checked as data accumulates
- `trials` (integer): Monte Carlo trials -- higher is more precise but slower; the result reports its own standard error

### `pairwise_group_comparisons` (~387 tokens)

Run every pairwise comparison across 2+ groups and correct for
multiple comparisons in one call, instead of orchestrating
k*(k-1)/2 separate two_sample_t_test/mann_whitney_u calls plus a
separate correction call by hand -- and forgetting the correction
is one of the most common real mistakes this package exists to
prevent. The natural follow-up after a significant
one_way_anova/kruskal_wallis result: pass the same groups here to
find *which* group(s) differ, not just whether any do. Returns
every pair's statistic, raw p-value, whether it's still significant
after correction, and an effect size, plus the correction method's
citation and warnings.

Input parameters:

- `alpha` (number): significance level for the test (and any confidence interval); default 0.05
- `correction` (string): "bh" (Benjamini-Hochberg, less conservative, default), "bonferroni" (more conservative), or "none" (raw p-values, e.g. if correcting elsewhere)
- `equal_var` (boolean): only used when test="t_test": assume equal population variances (pooled) instead of Welch's test, same meaning as two_sample_t_test's equal_var
- `groups` (array, required): one list of observations per group; at least 2 groups
- `labels`: optional name per group, same length and order as groups; carried through to each comparison for readability
- `test` (string): "t_test" (two_sample_t_test per pair, reports cohens_d) or "mann_whitney" (mann_whitney_u per pair, reports rank_biserial_correlation) -- match whichever you used for the overall group comparison (on…

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp#diagnostics

## Score history

- 2026-09-21: 66
- 2026-09-20: 66
- 2026-09-19: 66
- 2026-09-18: 69
- 2026-09-17: 69
- 2026-09-16: 69
- 2026-09-15: 68
- 2026-09-14: 68
- 2026-09-13: 82
- 2026-09-12: 82
- 2026-09-11: 81
- 2026-09-10: 66
- 2026-09-09: 65
- 2026-09-08: 80
- 2026-09-07: 80
- 2026-09-06: 79
- 2026-09-05: 79
- 2026-09-04: 78
- 2026-09-03: 78
- 2026-09-02: 77
- 2026-09-01: 77
- 2026-08-31: 76
- 2026-08-30: 76
- 2026-08-29: 75
- 2026-08-28: 75
- 2026-08-27: 74
- 2026-08-26: 74
- 2026-08-25: 72
- 2026-08-24: 72
- 2026-08-23: 71

## Common questions

### What is the io.github.mrnh/rigor-mcp server?

io.github.mrnh/rigor-mcp is listed in the public MCP registry as io.github.mrnh/rigor-mcp. Verified statistical inference for AI agents: hypothesis tests, sequential testing, power. This page covers its PyPI package (rigor-mcp).

### Is the io.github.mrnh/rigor-mcp server safe to use?

io.github.mrnh/rigor-mcp scores 66 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 21 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.mrnh/rigor-mcp server expose?

io.github.mrnh/rigor-mcp exposes 37 tools: one_sample_t_test, two_sample_t_test, paired_t_test, one_proportion_z_test, two_proportion_z_test, and 32 more. Their descriptions and schemas cost roughly 6,513 tokens of context every time the server is loaded.

### Is the io.github.mrnh/rigor-mcp server still maintained?

io.github.mrnh/rigor-mcp is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the io.github.mrnh/rigor-mcp server under?

io.github.mrnh/rigor-mcp declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/rigor-mcp/
- Socket report: https://socket.dev/pypi/package/rigor-mcp
- Repository: https://github.com/mrnh/rigor
- Changelog RSS feed: https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp.json
- HTML version of this page: https://verifymcp.io/servers/mrnh-rigor-mcp/rigor-mcp
