# Occam

> Finds the simplest equation consistent with your data. SINDy and PySR symbolic regression via MCP.

- name: fit.occam/occam
- version: 0.1.1
- connection class: R0 (autonomous)
- trust: 72/100 flags: no-repository
- quality: 88/100 (good)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/fit.occam%2Foccam
- tools: https://api.protogrid.dev/v1/servers/fit.occam%2Foccam/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "occam": {
      "type": "http",
      "url": "https://occam.fit/mcp/"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 100
- freshness: 45
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-100% -stale-202d -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 88/100 (good)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-11-25; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 93 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 3 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 4 of 4 tools declare readOnlyHint or destructiveHint
- pass `tools.directory_hints`: every tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint
- pass `tools.token_cost`: about 4,320 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 100 (weight 15)

- pass `stability.changes`: 3 tool changes in 30 days
- pass `stability.rug_pull`: no tool changed its meaning under the same name

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 4, about 4,320 tokens to load them all
- tool set hash: 4a9550f37aeccf7405b6b96a04ef5185
- tools last changed: 2026-09-24T13:52:59.642Z
- badge: [![protogrid quality](https://protogrid.dev/badge/fit.occam/occam.svg)](https://protogrid.dev/servers/fit.occam/occam)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-09-24 `pysr_uncertainty` changed (inputSchema)
- 2026-09-24 `pysr_run` changed (description, inputSchema)
  - before: Evolutionary Symbolic Regression (PySR). Discovers algebraic equations y = f(x1, x2, ...) from feature/target data. Returns a Pareto front ranked by the complexity/accuracy tradeoff. Slower than SINDy (10-60s); searches often terminate early on convergence. For differential equations from time series, use sindy_run instead. Pricing: free tier up to 100 rows × 8 features, 60s timeout. Beyond that, $0.25 + $0.03 per 100 extra rows + $0.01 per extra feature squared, timeout up to 300s (5 min), via x402 (USDC on Base) or MPP/Stripe. MPP/Stripe adds a flat $0.35 per-transaction fee (Stripe processing), so the MPP challenge amount in a `payment_required` response is $0.35 higher than the x402 amount for the same base price; x402 gets the lower rate. Omit `payment` for free-tier requests; paid requests without a valid credential receive a `payment_required` result with pricing and accepted schemes. Full pricing: occam://pricing Advisory limits: jobs over 50,000 rows or 20 features are accepted but may not converge; response carries a top-level `warning`. Operators: fixed supported set only — custom operators (e.g. 'inv(x) = 1/x') are rejected. Unary: sin, cos, tan, exp, log, log2, log10, sqrt, abs, sinh, cosh, tanh. Binary: +, -, *, /, ^. See also prompt `supported_operators`. Loss metric: `loss` (in `pareto_front[].loss` and `best_loss`) is mean squared error between model prediction and `y` on the full training set — not RMSE, and not normalized by Var(y). A threshold appropriate for one dataset scales with y's magnitude, so set `loss_threshold` with that in mind (e.g. for y values near 1.0, 1e-6 is a tight fit; for y near 1000, the equivalent is 1.0). Early termination: set `loss_threshold` to stop at your noise floor. The server also stops when the search stalls (<1% improvement in the last third of the budget); disable with `stall_detection=false`. Response `stop_reason` is one of: loss_threshold, stall, timeout, natural. If `feature_names` is supplied, its length must equal the number of columns in `X`; a mismatch is rejected with a validation error. Follow-up: call `pysr_uncertainty` with a chosen expression and the same dataset for bootstrap confidence intervals on its fit constants and optional prediction bands. Rate limit: 10 requests/hour per IP, 200/hour global, max queue depth 20 (shared with sindy_run and pysr_uncertainty). Response (success) includes `pareto_front[]` (each with `complexity`, `loss`, `expression`, `expression_latex`), `best_expression`, `best_expression_latex`, `best_loss`, `best_complexity`, `stop_reason`, `elapsed_seconds`, `queue_seconds` (>0 = server saturated; use as backoff signal), optional `warning`, optional `_meta` (MPP receipt). Full response and payment-required schemas: occam://tool-schemas Example request: X=[[0.0], [1.0], [2.0], [3.0]], y=[1.0, 3.0, 5.0, 7.0], feature_names=["x"], max_complexity=10, timeout_seconds=15 Policy: occam://privacy-policy — Citation: occam://citation-info
  - after: Evolutionary Symbolic Regression (PySR). Discovers algebraic equations y = f(x1, x2, ...) from feature/target data. Returns a Pareto front ranked by the complexity/accuracy tradeoff. Slower than SINDy (10-60s); searches often terminate early on convergence. For differential equations from time series, use sindy_run instead. Pricing: free tier up to 100 rows × 8 features, 60s timeout. Beyond that, $0.25 + $0.03 per 100 extra rows + $0.01 per extra feature squared, timeout up to 300s (5 min), via x402 (USDC on Base) or MPP/Stripe. MPP/Stripe adds a flat $0.35 per-transaction fee (Stripe processing), so the MPP challenge amount in a `payment_required` response is $0.35 higher than the x402 amount for the same base price; x402 gets the lower rate. Omit `payment` for free-tier requests; paid requests without a valid credential receive a `payment_required` result with pricing and accepted schemes. Full pricing: occam://pricing Advisory limits: jobs over 50,000 rows or 20 features are accepted but may not converge; response carries a top-level `warning`. Operators: fixed supported set only — custom operators (e.g. 'inv(x) = 1/x') are rejected. Unary: sin, cos, tan, exp, log, log2, log10, sqrt, abs, sinh, cosh, tanh. Binary: +, -, *, /, ^. See also prompt `supported_operators`. Loss metric: `loss` (in `pareto_front[].loss` and `best_loss`) is mean squared error between model prediction and `y` on the full training set — not RMSE, and not normalized by Var(y). A threshold appropriate for one dataset scales with y's magnitude, so set `loss_threshold` with that in mind (e.g. for y values near 1.0, 1e-6 is a tight fit; for y near 1000, the equivalent is 1.0). Early termination: set `loss_threshold` to stop at your noise floor. The server also stops when the search stalls (<1% improvement in the last third of the budget); disable with `stall_detection=false`. Response `stop_reason` is one of: loss_threshold, stall, timeout, natural. If `feature_names` is supplied, its length must equal the number of columns in `X`; a mismatch is rejected with a validation error. Follow-up: call `pysr_uncertainty` with a chosen expression and the same dataset for bootstrap confidence intervals on its fit constants and optional prediction bands. Rate limit: 10 requests/hour per IP, 200/hour global, max queue depth 20 (shared with sindy_run and pysr_uncertainty). Response (success) includes `pareto_front[]` (each with `complexity`, `loss`, `expression`, `expression_latex`), `best_expression`, `best_expression_latex`, `best_loss`, `best_complexity`, `stop_reason`, `elapsed_seconds`, `queue_seconds` (>0 = server saturated; use as backoff signal), optional `warning`, optional `_meta` (MPP receipt). Full response and payment-required schemas: occam://tool-schemas Example request: X=[[0.0], [1.0], [2.0], [3.0], [4.0]], y=[1.0, 3.0, 5.0, 7.0, 9.0], feature_names=["x"], max_complexity=10, timeout_seconds=15 Policy: occam://privacy-policy — Citation: occam://citation-info
- 2026-09-24 `sindy_run` changed (inputSchema)

Full history: https://api.protogrid.dev/v1/servers/fit.occam%2Foccam/changes

## Remotes

- https://occam.fit/mcp/ (streamable-http, auth none, reachable true, uptime30d 1)

## Packages

_none_

## Tools (4)

- `feature_request`: Request a feature that Occam doesn't support yet.

    Use this when you need a capability that Occam doesn't currently
    offer. Requests are logged and used to prioritize development.

    Rate limit: 5 requests/hour per IP, 50/hour global — stricter than
    the compute tools' 10/hour to prevent log flooding. Descriptions
    longer than 500 characters are truncated.
    
- `pysr_run`: Evolutionary Symbolic Regression (PySR).

    Discovers algebraic equations y = f(x1, x2, ...) from feature/target
    data. Returns a Pareto front ranked by the complexity/accuracy
    tradeoff. Slower than SINDy (10-60s); searches often terminate early
    on convergence. For differential equations from time series, use
    sindy_run instead.

    Pricing: free tier up to 100 rows × 8 features, 60s timeout. Beyond
    that, $0.25 + $0.03 per 100 extra rows + $0.01 per extra feature
    squared, timeout up to 300s (5 min), via x402 (USDC on Base) or
    MPP/Stripe. MPP/Stripe adds a flat $0.35 per-transaction fee (Stripe
    processing), so the MPP challenge amount in a `payment_required`
    response is $0.35 higher than the x402 amount for the same base
    price; x402 gets the lower rate. Omit `payment` for free-tier
    requests; paid requests without a valid credential receive a
    `payment_required` result with pricing and accepted schemes. Full
    pricing: occam://pricing

    Advisory limits: jobs over 50,000 rows or 20 features are accepted
    but may not converge; response carries a top-level `warning`.

    Operators: fixed supported set only — custom operators (e.g.
    'inv(x) = 1/x') are rejected. Unary: sin, cos, tan, exp, log, log2,
    log10, sqrt, abs, sinh, cosh, tanh. Binary: +, -, *, /, ^.
    See also prompt `supported_operators`.

    Loss metric: `loss` (in `pareto_front[].loss` and `best_loss`) is
    mean squared error between model prediction and `y` on the full
    training set — not RMSE, and not normalized by Var(y). A threshold
    appropriate for one dataset scales with y's magnitude, so set
    `loss_threshold` with that in mind (e.g. for y values near 1.0,
    1e-6 is a tight fit; for y near 1000, the equivalent is 1.0).

    Early termination: set `loss_threshold` to stop at your noise floor.
    The server also stops when the search stalls (<1% improvement in the
    last third of the budget); disable with `stall_detection=false`.
    Response `stop_reason` is one of: loss_threshold, stall, timeout,
    natural.

    If `feature_names` is supplied, its length must equal the number of
    columns in `X`; a mismatch is rejected with a validation error.

    Follow-up: call `pysr_uncertainty` with a chosen expression and the
    same dataset for bootstrap confidence intervals on its fit constants
    and optional prediction bands.

    Rate limit: 10 requests/hour per IP, 200/hour global, max queue
    depth 20 (shared with sindy_run and pysr_uncertainty).

    Response (success) includes `pareto_front[]` (each with `complexity`,
    `loss`, `expression`, `expression_latex`), `best_expression`,
    `best_expression_latex`, `best_loss`, `best_complexity`, `stop_reason`,
    `elapsed_seconds`, `queue_seconds` (>0 = server saturated; use as
    backoff signal), optional `warning`, optional `_meta` (MPP receipt).
    Full response and payment-required schemas: occam://tool-schemas

    Example request:
      X=[[0.0], [1.0], [2.0], [3.0], [4.0]], y=[1.0, 3.0, 5.0, 7.0, 9.0],
      feature_names=["x"], max_complexity=10, timeout_seconds=15

    Policy: occam://privacy-policy — Citation: occam://citation-info
    
- `pysr_uncertainty`: Bootstrap confidence intervals for the numeric constants of a
    frozen expression, plus optional prediction bands on an x-grid.

    Typical flow: call pysr_run, pick an expression from the response
    (best_expression or a pareto_front entry), pass it back here with
    the same dataset to get CIs on its fit constants.

    Returns frequentist bootstrap confidence intervals, not Bayesian
    credible intervals — posterior inference over expression structures
    is an open research problem. This tool freezes the expression
    chosen by the caller and bootstraps only its numeric constants;
    uncertainty about *which* expression is correct is not quantified.

    Bootstrap semantics:
      - If y_sigma is supplied, uses parametric bootstrap
        (y_b = y + Normal(0, y_sigma)). CI reflects user-stated
        measurement noise.
      - Otherwise uses residual bootstrap: fit once, resample residuals.
        CI reflects estimated-from-residuals noise.

    Only Float constants in the expression become free parameters.
    Integers stay structural (the 2 in x**2 is a function-class choice,
    not a fit constant). Expressions with no Float constants
    (e.g. "x + y") will be rejected with a validation error.

    Expression grammar: the `expression` string is parsed by sympy.
    Accepted operators are the same set pysr_run emits: unary `sin`,
    `cos`, `tan`, `exp`, `log`, `log2`, `log10`, `sqrt`, `abs`, `sinh`,
    `cosh`, `tanh`; binary `+`, `-`, `*`, `/`, `^` (or `**`). Whitespace
    and parenthesization are free. Every free symbol in the expression
    must correspond to an entry in `feature_names` — an unrecognised
    symbol is silently treated as a fresh sympy Symbol and the fit will
    fail downstream rather than reject early. Parse failures (syntax
    errors, malformed operators) surface as tool errors.

    If `feature_names` is supplied, its length must equal the number of
    columns in `X`; a mismatch is rejected with a validation error.

    Pricing: always free, regardless of dataset size. This tool has no
    `payment` parameter and is never subject to the x402/Stripe gate.
    Large bootstrap jobs still count against the shared rate limit
    below, so budget `n_resamples` accordingly.

    Rate limit: 10 requests/hour per IP, 200/hour global, max queue
    depth 20 (shared with sindy_run and pysr_run).
    
- `sindy_run`: Sparse Identification of Nonlinear Dynamics (SINDy).

    Recovers governing differential equations (dx/dt = f(x)) from time
    series data. Returns human-readable sparse expressions. Fast (seconds).
    For algebraic y = f(x) relationships without time structure, use
    pysr_run instead.

    Pricing: free tier up to 100 rows and 8 variables. Beyond that,
    $0.05 + $0.01 per 100 extra rows + $0.01 per extra variable squared,
    via x402 (USDC on Base) or MPP/Stripe. MPP/Stripe adds a flat $0.35
    per-transaction fee (Stripe processing), so the MPP challenge amount
    in a `payment_required` response is $0.35 higher than the x402 amount
    for the same base price; x402 gets the lower rate. Omit `payment`
    for free-tier requests; paid requests without a valid credential
    receive a `payment_required` result with pricing and accepted schemes.
    Full pricing table as structured JSON: occam://pricing

    Advisory limits: jobs over 500,000 rows or 50 variables are accepted
    but may not converge within the time budget; the response carries a
    top-level `warning` the agent should surface and treat as tentative.

    If `feature_names` is supplied, its length must equal the number of
    data columns; a mismatch is rejected with a validation error.

    Rate limit: 10 requests/hour per IP, 200/hour global, max queue
    depth 20 (shared with pysr_run and pysr_uncertainty).

    Response (success) includes `equations[]` (each with `variable`,
    `equation`, `expression`, `expression_latex`, `r2`), `library_terms`,
    `nonzero_terms`, `elapsed_seconds`, `canonical_match` (dict with
    `system`, `form`, `variable_map`, `parameter_map`, `confidence` if
    the discovered system matches one of Lorenz / Lotka-Volterra /
    Van der Pol / Duffing; `null` otherwise), optional `warning`,
    optional `_meta` (MPP receipt on paid calls). Full response and
    payment-required schemas: occam://tool-schemas

    Example request:
      data=[[1.0, 0.0], [0.95, -0.31], [0.81, -0.59]], t=[0.0, 0.1, 0.2],
      feature_names=["x", "y"], poly_degree=2, threshold=0.1

    Policy: occam://privacy-policy — Citation: occam://citation-info
    
