Skip to main content
Glama

pysr_run

Read-only

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

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
XYes2D array of input features. Each row is an observation, each column is a feature. Minimum 5 rows. Free tier: 100 rows, 8 features. Paid tier: up to 50,000 rows, 20 features.
yYesTarget values, one per row of X.
paymentNoPayment credential. Accepts either a JSON object or a JSON-encoded string (FastMCP's transport pre-parses strings whose field annotation is non-bare-`str` into objects, so the object form is canonical; the string form is accepted for legacy callers). Required when the dataset exceeds the free tier (100 rows, 8 variables). Omit for free-tier requests. For x402: {"transaction":"0x...","network":"...","priceToken":"..."}. For MPP/Stripe: {"challenge":{...},"payload":"..."}. For prepaid API key: {"scheme":"prepaid","api_key":"occ_live_...","request_id":"<optional uuid>"}.
populationsNoNumber of evolutionary populations for the search. Default 15, max 20.
feature_namesNoNames for each variable/feature column. Defaults to x0, x1, ...
loss_thresholdNoOptional early-stop threshold on the best loss found. If set, the search terminates as soon as any Pareto-front member reaches a loss at or below this value, even if the timeout has not been reached. Useful when you know your noise floor. Default: None (no user threshold; the search runs until the stall detector or timeout).
max_complexityNoMaximum expression tree size. Higher allows more complex expressions. Default 20, max 25.
stall_detectionNoWhen true (default), the server stops the search early if the best loss has not improved by more than 1% during the last third of the time budget. This reclaims compute once the search has converged. Set to false only if you want the search to run for the full timeout regardless of progress.
timeout_secondsNoWall clock time limit in seconds. Free tier: max 60. Paid tier: max 300 (5 minutes). Default 60.
unary_operatorsNoAllowed unary operators, drawn from the fixed supported set: sin, cos, tan, exp, log, log2, log10, sqrt, abs, sinh, cosh, tanh. Custom operators (e.g. 'inv(x) = 1/x') are NOT supported — only the names listed are accepted. Default: sin, cos, exp, log, sqrt. Pass [] for none.
binary_operatorsNoAllowed binary operators, drawn from the fixed supported set: +, -, *, /, ^. Custom operators are NOT supported. Default: +, -, *, /. Pass [] for none.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
warningNo
best_lossNo
stop_reasonNo
pareto_frontNo
queue_secondsNo
best_complexityNo
best_expressionNo
elapsed_secondsNo
best_expression_latexNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • changedInput schema / properties / X / description
      Previous value: -"2D array of input features. Each row is an observation, each column is a feature. Free tier: 100 rows, 8 features. Paid tier: up to 50,000 rows, 20 features."New value: +"2D array of input features. Each row is an observation, each column is a feature. Minimum 5 rows. Free tier: 100 rows, 8 features. Paid tier: up to 50,000 rows, 20 features."
    • addedInput schema / properties / X / examples
      Added value: +[
      +  [
      +    [
      +      0
      +    ],
      +    [
      +      1
      +    ],
      +    [
      +      2
      +    ],
      +    [
      +      3
      +    ],
      +    [
      +      4
      +    ]
      +  ]
      +]
    • addedInput schema / properties / X / minItems
      Added value: +5
    • addedInput schema / properties / y / examples
      Added value: +[
      +  [
      +    1.02,
      +    2.97,
      +    5.01,
      +    7.03,
      +    8.98
      +  ]
      +]
    • addedInput schema / properties / y / minItems
      Added value: +5
  2. Changed2 schema fields changed
    • changedInput schema / properties / payment / anyOf
      Previous value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "type": "object"
      +  },
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / payment / description
      Previous value: -"Payment credential as a JSON string. Required when the dataset exceeds the free tier (100 rows, 8 variables). Omit for free-tier requests. For x402: {\"transaction\":\"0x...\",\"network\":\"...\",\"priceToken\":\"...\"}. For MPP/Stripe: {\"challenge\":{...},\"payload\":\"...\"}."New value: +"Payment credential. Accepts either a JSON object or a JSON-encoded string (FastMCP's transport pre-parses strings whose field annotation is non-bare-`str` into objects, so the object form is canonical; the string form is accepted for legacy callers). Required when the dataset exceeds the free tier (100 rows, 8 variables). Omit for free-tier requests. For x402: {\"transaction\":\"0x...\",\"network\":\"...\",\"priceToken\":\"...\"}. For MPP/Stripe: {\"challenge\":{...},\"payload\":\"...\"}. For prepaid API key: {\"scheme\":\"prepaid\",\"api_key\":\"occ_live_...\",\"request_id\":\"<optional uuid>\"}."
  3. Changed1 schema field changed
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$defs": {
      +    "PySRParetoEntry": {
      +      "additionalProperties": true,
      +      "properties": {
      +        "complexity": {
      +          "title": "Complexity",
      +          "type": "integer"
      +        },
      +        "expression": {
      +          "title": "Expression",
      +          "type": "string"
      +        },
      +        "expression_latex": {
      +          "anyOf": [
      +            {
      +              "type": "string"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "title": "Expression Latex"
      +        },
      +        "loss": {
      +          "title": "Loss",
      +          "type": "number"
      +        }
      +      },
      +      "required": [
      +        "complexity",
      +        "loss",
      +        "expression",
      +        "expression_latex"
      +      ],
      +      "title": "PySRParetoEntry",
      +      "type": "object"
      +    }
      +  },
      +  "additionalProperties": true,
      +  "properties": {
      +    "best_complexity": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Best Complexity"
      +    },
      +    "best_expression": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Best Expression"
      +    },
      +    "best_expression_latex": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Best Expression Latex"
      +    },
      +    "best_loss": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Best Loss"
      +    },
      +    "elapsed_seconds": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Elapsed Seconds"
      +    },
      +    "pareto_front": {
      +      "anyOf": [
      +        {
      +          "items": {
      +            "$ref": "#/$defs/PySRParetoEntry"
      +          },
      +          "type": "array"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Pareto Front"
      +    },
      +    "queue_seconds": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Queue Seconds"
      +    },
      +    "stop_reason": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Stop Reason"
      +    },
      +    "warning": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "title": "Warning"
      +    }
      +  },
      +  "title": "PySRRunResult",
      +  "type": "object"
      +}
  4. Changed2 schema fields changed
    • changedInput schema / properties / binary_operators / description
      Previous value: -"Allowed binary operators. Options: +, -, *, /, ^. Default: +, -, *, /."New value: +"Allowed binary operators, drawn from the fixed supported set: +, -, *, /, ^. Custom operators are NOT supported. Default: +, -, *, /. Pass [] for none."
    • changedInput schema / properties / unary_operators / description
      Previous value: -"Allowed unary operators. Options: sin, cos, tan, exp, log, log2, log10, sqrt, abs, sinh, cosh, tanh. Default: sin, cos, exp, log, sqrt."New value: +"Allowed unary operators, drawn from the fixed supported set: sin, cos, tan, exp, log, log2, log10, sqrt, abs, sinh, cosh, tanh. Custom operators (e.g. 'inv(x) = 1/x') are NOT supported — only the names listed are accepted. Default: sin, cos, exp, log, sqrt. Pass [] for none."
  5. Changed4 schema fields changed
    • changedInput schema / properties / X / description
      Previous value: -"2D array of input features. Each row is an observation, each column is a feature. Max 1,000 rows, 10 features."New value: +"2D array of input features. Each row is an observation, each column is a feature. Free tier: 100 rows, 8 features. Paid tier: up to 50,000 rows, 20 features."
    • addedInput schema / properties / payment
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Payment credential as a JSON string. Required when the dataset exceeds the free tier (100 rows, 8 variables). Omit for free-tier requests. For x402: {\"transaction\":\"0x...\",\"network\":\"...\",\"priceToken\":\"...\"}. For MPP/Stripe: {\"challenge\":{...},\"payload\":\"...\"}.",
      +  "title": "Payment"
      +}
    • changedInput schema / properties / timeout_seconds / description
      Previous value: -"Wall clock time limit in seconds. Default 60, max 60."New value: +"Wall clock time limit in seconds. Free tier: max 60. Paid tier: max 300 (5 minutes). Default 60."
    • changedInput schema / properties / timeout_seconds / maximum
      Previous value: -60New value: +300
  6. Changed2 schema fields changed
    • addedInput schema / properties / loss_threshold
      Added value: +{
      +  "anyOf": [
      +    {
      +      "exclusiveMinimum": 0,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Optional early-stop threshold on the best loss found. If set, the search terminates as soon as any Pareto-front member reaches a loss at or below this value, even if the timeout has not been reached. Useful when you know your noise floor. Default: None (no user threshold; the search runs until the stall detector or timeout).",
      +  "title": "Loss Threshold"
      +}
    • addedInput schema / properties / stall_detection
      Added value: +{
      +  "default": true,
      +  "description": "When true (default), the server stops the search early if the best loss has not improved by more than 1% during the last third of the time budget. This reclaims compute once the search has converged. Set to false only if you want the search to run for the full timeout regardless of progress.",
      +  "title": "Stall Detection",
      +  "type": "boolean"
      +}
  7. Added

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=false, but the description adds substantial behavioral context: early termination via loss_threshold and stall detection, the exact definition of the loss metric (MSE not RMSE, not normalized), response stop_reason values, rate limits, and restrictions on custom operators. No contradiction with annotations; instead, it layers crucial operational details on top.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear sections (pricing, advisory limits, operators, loss metric, early termination, follow-up, rate limits, response, example). Every paragraph adds essential information; there is no fluff or redundancy. It could be slightly more compact, but given the number of distinct operational aspects it must cover, the length is justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is exhaustive for a tool with 11 parameters, an output schema, and payment complexity. It covers pricing, rate limits, operator constraints, loss semantics, stop reasons, pagination/queue hints, example request, and response fields (including optional warning and _meta). The follow-up tool and full schema links are provided. An agent has everything needed to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (baseline 3), but the description goes well beyond schema descriptions. For example, it explains that loss_threshold scales with y's magnitude, that feature_names length must match X columns or be rejected, that unary/binary operators are restricted to a fixed set with custom operators rejected, and that payment accepts three distinct forms. This meaningfully compensates for any ambiguity in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('discovers algebraic equations'), resource ('from feature/target data'), and method ('evolutionary symbolic regression (PySR)'). It explicitly contrasts with a sibling ('For differential equations from time series, use sindy_run instead'), making it easy to distinguish from other tools without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear when-to-use guidance: it names the alternative `sindy_run` for differential equations and tells the user to use `pysr_uncertainty` for follow-up confidence intervals. It also details conditions for free vs. paid tiers and how to handle payment-required responses, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources