Skip to main content
Glama
getsimba-ai

Simba MCP Server

Official
by getsimba-ai

Create Model

create_model

Create and start fitting a new Bayesian Marketing Mix Model.

Instructions

Create and start fitting a new Bayesian Marketing Mix Model.

This queues an async model fit and returns immediately with a model_hash. Use get_model_status to poll for progress until status is 'complete'.

Priors are calculated automatically using smart defaults based on cost shares, industry benchmarks, and channel-type detection. You can override individual channels via the priors parameter.

Args: uploaded_file_id: The file ID returned by upload_data. date_column: Name of the date column in the CSV. kpi_column: Name of the KPI/dependent variable column. hierarchy_column: Name of the brand/segment column (must have exactly 1 unique value). channels: List of channel definitions, each with keys: name, activity_column, spend_column. Example: [{"name": "TV", "activity_column": "tv_grps", "spend_column": "tv_spend"}] multiplier_column: Column to convert KPI to revenue. Defaults to kpi_column. control_columns: Non-media control variable column names (e.g. ["price", "distribution"]). total_media_effect: Controls prior strength. Either an industry name for a benchmark ("FMCG"=6%, "Retail"=9%, "TelCo"=30%, "Financial Services"=19%, "E-Commerce"=22%, "Other"=12%) or a custom decimal like "0.15" meaning "I believe all media drives 15% of my KPI". Default "Other". priors: Optional per-channel prior overrides. Each dict should have "channel" matching a channels[].name, plus any fields to override: distribution, mean, sd, lower, upper, transform, adstock_type, effect_period. Only specified fields are overridden; the rest use smart defaults. Adstock-kernel fields: half_life_lower/half_life_upper (carryover half-life bounds in periods — preferred over the legacy decay_lower/decay_upper), theta_mean/theta_sd (peak-lag prior, adstock_type="delayed" only), dual_weight_mean/dual_weight_sd (long-term/slow-component share prior, adstock_type="dual_geometric" only). SATURATION ANCHOR — state it ONCE, in exactly one of three mutually exclusive forms (two in one override -> 400 "state the saturation prior once"): (1) half_marginal_mean/half_marginal_sd — CANONICAL for saturation_type="generalized_log" (rejected on other families): the activity level where MARGINAL returns have halved, finite at every curvature (#632). sat_shape_mean MUST accompany the pair in the same override (#672) — the fold pairs your coefficient with the stated curvature, so omitting it is a 400, never a silent default. (2) half_saturation_mean/half_saturation_sd — the 50%-of-maximum point in activity units, for the single-parameter families (tanh/michaelis_menten/ negative_exponential). Do NOT use it for generalized_log near-log work: it overflows below sat_shape_mean 0.00097657 and is rejected with a 400 — precisely the regime that family exists for. (3) alpha_sd + scalars — legacy internal coordinates, accepted for backward compat. Curvature (generalized_log only): sat_shape_mean/sat_shape_sd — small values are near-logarithmic, 1.0 is michaelis_menten. COEFFICIENT in a human coordinate (generalized_log only, #671): effect_at_avg_mean/effect_at_avg_sd — the effect share at the channel's AVERAGE activity, as FRACTIONS (mean in (0, 0.95], sd > 0; 0.2 means 20%). Folded server-side into mean/sd at the row's operating point with the same arithmetic as the dashboard. Requires sat_shape_mean in the same override; cannot be combined with mean/sd ("state the coefficient prior once") or with half_saturation_*. Stating half_marginal_* + effect_at_avg_* + sat_shape_mean together is the full (x*, E, k) triple — the recommended generalized_log elicitation, since only beta*k is identified and raw beta spans orders of magnitude. VERIFY what was applied via get_model's model_config.priors_resolved: rows carry the FOLDED mean/sd/scalars/alpha_sd, and overridden_fields lists the field names you sent. UNKNOWN KEYS ARE REJECTED with a 400 naming the field (#630); they used to be dropped silently, fitting a hybrid of the override and the smart defaults. Common misses: "beta"/"beta_mean" -> mean, "beta_sd" -> sd, "sat_shape" -> sat_shape_mean. "name" and "parameter" are rejected too — they identify the smart-prior row the override merges onto. trend: Enable dynamic baseline trend component. seasonality: Enable automatic seasonality detection. The prior sigma on the Fourier coefficients is chosen for the link (#534): 0.5 under link="log", 10 under "identity". The coefficients live on the link's scale, so the additive default would admit e^10x seasonal amplitude on a multiplicative model. likelihood: Likelihood function: "normal" (default), "lognormal", "logit", "studentt", "poisson", "negativebinomial", or "quantile". saturation_type: Diminishing-returns curve family applied to media: "tanh" (default), "michaelis_menten", "negative_exponential", or "generalized_log" (two-parameter Box-Cox/power-log family 1 - (1+x/K)^(-shape); tune per channel via the sat_shape_mean/sat_shape_sd prior fields). transform_order: "adstock_first" (default: carryover accumulates, then saturates) or "saturation_first" (each period's spend saturates, then the effect spreads over time through the normalized adstock kernel). link: Model Form. "identity" (default) fits an additive model — components add on the outcome scale. "log" fits a multiplicative model — components add on the log scale and media effects are percentage lifts. Under the removal_lift attribution convention (the API default), contributions then include an Overlap reconciliation column; the other conventions (aumann_shapley — the dashboard default for multiplicative models since #509 — shapley, and proportional_normalized) allocate the interaction across components and close exactly WITHOUT an Overlap column (see get_model_results). channel_groups: Optional adstock groups: [{"name": ..., "channels": [...], "share_saturation": bool}]. Member channels tie their carryover parameters (decay/theta/dual-weight — plus saturation when share_saturation is true) to one shared value, e.g. grouping channels into shared "Long"/"Short" carryover classes. Members are channels[].name values; each group needs >= 2 members; groups must be disjoint; and tied members must have identical adstock_type/effect_period/bound overrides (the API rejects divergent groups at request time). control_reference: Control attribution reference points (#452), multiplicative models (link="log") only: maps control column names (plus optional "default") to "auto" | "absent" | "average" | "lowest" | "highest" — which counterfactual "remove this control" means in the contributions. "absent" measures against the variable at zero (legacy behavior; honest only when zero is observed). "average"/"lowest"/"highest" reference the control at its observed mean/min/max — use for controls that never approach zero (price indices, distribution levels), where a zero counterfactual produces unbounded contributions and a negative Base. "auto" detects per control whether zero is inside the observed data range. Example: {"default": "auto", "relative_price": "average", "promo_flag": "absent"}. Omit entirely to keep every control at "absent" (byte-identical legacy output). Unknown control names/modes are rejected at request time; any value other than "absent" requires link="log". The fit reports the resolution in model_config.control_references (see get_model_results). name: Display name for the created model, honoured verbatim (#575). Falls back to a generated API_MMM{brand}{hash} string when omitted. Either way the model starts unsaved — invisible to list_models unless include_unsaved=true — until save_model files it into a project. currency: The model's money currency, as an uppercase code (GBP, USD, EUR, CAD, AUD, NZD, CHF, SGD, HKD, JPY, KWD, BHD or OMR). Leave empty when unknown: money then prints as bare numbers, and the owner can declare it later with rename_model, without a refit. Never guess one. operating_margin: Scalar operating margin as a decimal fraction in (0, 1], e.g. 0.18 = 18%. Mutually exclusive with operating_margin_column (the API 400s when both are given). Storing a margin unlocks the financials results section and lets run_optimizer(objective="profit") use it automatically instead of requiring forward_margin on every call. operating_margin_column: Name of a column in the uploaded CSV holding a per-date margin series. The column may be uniformly in fractions (0, 1] OR uniformly in percentages (1, 100] — the API detects the unit and normalizes percentages; mixed units are rejected. Same unlocks as operating_margin; the column must exist in the uploaded file. CAUTION: the API reads the margin keys from the REQUEST ROOT — a margin placed inside a config dict is silently ignored (no error), and the model fits marginless. attribution: Attribution convention for the contribution decomposition, resolved at fit time: "removal_lift" (the API default; one-at-a-time removal — multiplicative models then emit the Overlap column), "aumann_shapley" (the dashboard default for multiplicative models since #509), "shapley", or "proportional_normalized". Any value other than "removal_lift" requires link="log" (the API rejects it on additive models). The non-removal conventions allocate the interaction across components and close exactly WITHOUT an Overlap column. To reconcile with a dashboard-built multiplicative model, use "aumann_shapley". annual_discount_rate: Annual discount rate (decimal >= 0, e.g. 0.08) used by the display-time financial bridge and cohort ledger PV discounting. Display-time only — does not change the fit. sampler: MCMC sampler overrides, e.g. {"n_samples": 2000, "tune": 1500, "chains": 4, "cores": 2, "target_accept": 0.95}. STRICTLY validated: unknown keys inside sampler are rejected with a 400 naming the field; cores must be 1-8. Only the keys you send are overridden. reporting_kernel: Reporting-kernel class override (#450) for the cohort_ledger section's forward allocation. Shape: {"classes": {...}, "channel_classes": {...}} — ONLY those two top-level keys are accepted (anything else, e.g. "mode", 400s with the unknown key named). channel_classes names channels by channels[].name or activity_column, validated at request time. Affects only how the cohort_ledger allocates effects over the horizon — not the fit, and not the contributions / channel_summary decompositions. (The related "complete" / "in_window" choice is a separate cohort_horizon QUERY parameter on the results endpoint, not part of this config.)

control_priors: Optional root-level control slope overrides. Each entry names a selected control_columns column with "control", plus transform (N, DM, STA, DDM, LOG), distribution (normal, inversegamma, truncatednormal, halfnormal), mean/sd/lower/upper as applicable. LOG is log(x/mean(x)); STA divides by sample sd without centering. Priors are in transformed units; changing transform does not convert coefficients. Nonempty overrides require backend capability version 1; unsupported or unavailable checks stop before creating a model.

calibration: Optional lift-test calibration: likelihood observations the fit must respect. Either {"tests": [{"test_id": ..., "version"?, "channel"?, "confirm_kpi"?}]} (recorded tests from list_incrementality_tests, each derived against THIS model's data), or {"units": "revenue" | "response", "observations": [{channel, x, delta_x, delta_y, sigma}]} for rows you derived yourself. If any test can't calibrate this model, nothing is created: the error has code "calibration_refused" and tests gives each test's reason. Preview a test's row with get_incrementality_test(model_hash=...). The derived rows calibrate this fit only; the model does not keep a link to the tests. To keep that lineage (the test then lists the model under used_by and can't be deleted), build through a study recipe or a recipe draft that references the tests.

Returns the model_hash for status polling.

Input Schema

NameRequiredDescriptionDefault
linkNoidentity
nameNo
trendNo
priorsNo
samplerNo
channelsYes
currencyNo
kpi_columnYes
likelihoodNonormal
attributionNo
calibrationNo
date_columnYes
seasonalityNo
channel_groupsNo
control_priorsNo
control_columnsNo
saturation_typeNotanh
transform_orderNoadstock_first
hierarchy_columnYes
operating_marginNo
reporting_kernelNo
uploaded_file_idYes
control_referenceNo
multiplier_columnNo
total_media_effectNoOther
annual_discount_rateNo
operating_margin_columnNo

Output Schema

NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.18.0
    • addedInput schema / properties / currency
      Added value: +{
      +  "default": "",
      +  "title": "Currency",
      +  "type": "string"
      +}
  2. Changed1 schema field changedv0.12.0
    • addedInput schema / properties / calibration
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "description": "Calibrate the fit with lift-test likelihood observations, in exactly one form: {tests: [{test_id, version?, channel?, confirm_kpi?}]} (1-50 recorded tests, each derived against this model's own data), or {units: 'revenue' | 'response', observations: [{channel, x, delta_x, delta_y, sigma, sigma_low?, sigma_high?}]} (1-200 rows you derived yourself). If any test can't calibrate this model the call fails with calibration_refused and a reason per test in `tests`; check a test first with get_incrementality_test(test_id, model_hash=...) on a saved model built on the same data.",
      +      "properties": {
      +        "observations": {
      +          "items": {
      +            "properties": {
      +              "channel": {
      +                "type": "string"
      +              },
      +              "delta_x": {
      +                "type": "number"
      +              },
      +              "delta_y": {
      +                "type": "number"
      +              },
      +              "sigma": {
      +                "exclusiveMinimum": 0,
      +                "type": "number"
      +              },
      +              "sigma_high": {
      +                "exclusiveMinimum": 0,
      +                "type": "number"
      +              },
      +              "sigma_low": {
      +                "exclusiveMinimum": 0,
      +                "type": "number"
      +              },
      +              "x": {
      +                "type": "number"
      +              }
      +            },
      +            "required": [
      +              "channel",
      +              "x",
      +              "delta_x",
      +              "delta_y",
      +              "sigma"
      +            ],
      +            "type": "object"
      +          },
      +          "maxItems": 200,
      +          "minItems": 1,
      +          "type": "array"
      +        },
      +        "tests": {
      +          "items": {
      +            "additionalProperties": false,
      +            "description": "A recorded test by reference; the row is derived against the model's own data.",
      +            "properties": {
      +              "channel": {
      +                "description": "Model activity column to calibrate; default: the test's model_channel.",
      +                "type": "string"
      +              },
      +              "confirm_kpi": {
      +                "description": "Assert the test's outcome is the model's KPI when their names differ (recorded in the steps).",
      +                "type": "boolean"
      +              },
      +              "test_id": {
      +                "type": "string"
      +              },
      +              "version": {
      +                "description": "Default: the current version.",
      +                "minimum": 1,
      +                "type": "integer"
      +              }
      +            },
      +            "required": [
      +              "test_id"
      +            ],
      +            "type": "object"
      +          },
      +          "maxItems": 50,
      +          "minItems": 1,
      +          "type": "array"
      +        },
      +        "units": {
      +          "enum": [
      +            "revenue",
      +            "response"
      +          ],
      +          "type": "string"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Calibration"
      +}
  3. Changed5 schema fields changedv0.5.0
    • addedInput schema / properties / channels / items / description
      Added value: +"Media channel binding. Exact activity-column keys identify channels in result/optimizer calls."
    • addedInput schema / properties / channels / items / properties
      Added value: +{
      +  "activity_column": {
      +    "type": "string"
      +  },
      +  "name": {
      +    "type": "string"
      +  },
      +  "spend_column": {
      +    "type": "string"
      +  }
      +}
    • addedInput schema / properties / channels / items / required
      Added value: +[
      +  "name",
      +  "activity_column",
      +  "spend_column"
      +]
    • addedInput schema / properties / control_priors
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "additionalProperties": true,
      +        "description": "Optional override for a selected control column. Values and priors use transformed units; discover backend support first.",
      +        "properties": {
      +          "control": {
      +            "type": "string"
      +          },
      +          "distribution": {
      +            "examples": [
      +              "normal",
      +              "inversegamma",
      +              "truncatednormal",
      +              "halfnormal"
      +            ],
      +            "type": "string"
      +          },
      +          "lower": {
      +            "type": "number"
      +          },
      +          "mean": {
      +            "type": "number"
      +          },
      +          "sd": {
      +            "type": "number"
      +          },
      +          "transform": {
      +            "description": "N unchanged; DM divide by variable mean; STA scale by sample SD without centering; DDM divide by variable mean within hierarchy; LOG log(x/mean(x)). Backend validates applicability.",
      +            "examples": [
      +              "N",
      +              "DM",
      +              "STA",
      +              "DDM",
      +              "LOG"
      +            ],
      +            "type": "string"
      +          },
      +          "upper": {
      +            "type": "number"
      +          }
      +        },
      +        "required": [
      +          "control"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Control Priors"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "additionalProperties": true,
      +  "title": "create_modelDictOutput",
      +  "type": "object"
      +}
  4. First observedv0.3.2

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare readOnlyHint=false, openWorldHint=true, idempotentHint=false, destructiveHint=false; the description adds substantial context beyond that — the model starts unsaved and is invisible to list_models until save_model, priors are auto-computed with overridable smart defaults, many inputs are strictly validated with named 400s, and calibration failure is atomic (calibration_refused). This is rich behavioral disclosure well past the annotation baseline.

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?

Front-loaded correctly (purpose, async/return contract, then a structured Args block), and most of the length is justified by 27 undocumented parameters. However, the density of inline issue references (#632, #672, #671, #630, #575, #452, #450, #534, #509) and verbatim error-string details is noise that hurts scanability, keeping it from a 5.

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?

Given an output schema exists, return-value explanation is optional, yet the description still specifies the model_hash return and points to get_model_status. For a highly complex, high-stakes mutation tool with 0% schema coverage, the description supplies everything needed to invoke it correctly, including validation, mutual exclusions, and error semantics.

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 description coverage is 0%, so the description carries the full burden — and it does, documenting all 27 parameters with meaning, defaults, accepted value sets, mutual-exclusion rules (operating_margin vs operating_margin_column), and non-obvious pitfalls (margin keys read from request root, unknown prior keys rejected). It adds far more than the bare 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?

Opens with a specific verb+resource: 'Create and start fitting a new Bayesian Marketing Mix Model.' This is clearly distinguishable from siblings like create_var_model or create_study_recipe, and the async-fit framing tells the agent exactly what class of operation this is.

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

Usage Guidelines4/5

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

Explicitly states the workflow: queues an async fit, returns a model_hash, and directs the agent to get_model_status to poll until 'complete'. The calibration section also hints that building through a study recipe is the alternative when lineage must be preserved. It stops short of an explicit 'use this vs. create_var_model/study recipes' routing statement, so a 4 rather than 5.

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

Deploy Server

Other Tools