Developer docs

    Populous MCP developer guide

    Use the Populous MCP server to plan, launch, monitor, and analyze simulations from AI clients.

    The Populous MCP server lets AI clients plan, launch, monitor, and inspect Populous simulations through a structured tool interface.

    Use the MCP server when an AI client needs to turn a user request, audience, and supporting context into a Populous simulation without manually building every resource in the web app. The current server surface is the v2 plan workflow:

    ToolWhen to use
    getWorkflowGuideStart here for current workflow guidance.
    startWebsiteLiveSignInOnly for private/logged-in website tests.
    completeWebsiteLiveSignInComplete private website sign-in after browser login.
    uploadStimulusOnly when the user supplied local files/images.
    listStimuliOnly after uploadStimulus.
    requestPlanBuild the plan before launch.
    bindAssetOnly for explicit saved population reuse.
    runSimulationLaunch the approved plan.
    getSimulationStatusMonitor run progress.
    getSimulationAnalysisFetch the compact analysis for normal answers.
    getSimulationArtifactManifestInspect available large artifacts.
    querySimulationArtifactFilter or page through large artifacts server-side.
    getSimulationResultsFetch the structured result payload.
    getSimulationResultsCsvDownloadCreate a raw CSV export link.

    The MCP server URL for ChatGPT and Claude is:

    https://run.populous.app/mcp

    Tools read authentication from the MCP connection's bearer token. Do not ask the user for a token inside tool arguments.

    How Populous simulations work

    A Populous simulation has three core resources:

    1. Population: the synthetic audience to simulate.
    2. Experiment: the task, survey, website test, behavior test, or stimulus the audience should evaluate.
    3. Simulation run: the execution that connects one or more populations to an experiment and returns results.

    The v2 MCP flow creates a temporary plan first. requestPlan compiles the user's description and any supplied context into an internal plan, returns a plan_token, and exposes a slot manifest. runSimulation later executes that stored plan exactly as built and bound.

    Plan tokens are in-memory server state, not durable saved resources. If a plan_token is unknown or expired, call requestPlan again.

    Quickstart

    Standard launch workflow

    Use this flow for open-ended user requests, including questions, audiences, websites, documents, images, scenarios, business decisions, product ideas, and exploratory prompts.

    getWorkflowGuide
    requestPlan
    runSimulation
    getSimulationStatus
    getSimulationAnalysis
    getSimulationResults

    Workflow:

    1. Call getWorkflowGuide once so the client has the current tool sequence in context.
    2. Call requestPlan with a specific description and any structured context or stimulus references.
    3. Review the returned summary, status, and slots.
    4. If the user explicitly wants to reuse a saved population, call listPopulations and then bindAsset.
    5. Call runSimulation with the plan_token.
    6. Poll getSimulationStatus until the run is complete.
    7. Call getSimulationAnalysis for the compact summary, verdict, and findings.
    8. Call getSimulationResults when you need the structured result payload, getSimulationArtifactManifest and querySimulationArtifact when large table-like artifacts need server-side filtering, or getSimulationResultsCsvDownload when you need a raw CSV export.

    runSimulation does not accept runtime overrides. If the plan is wrong, fix population reuse with bindAsset or call requestPlan again with clearer description and context.

    Local files, images, PDFs, or documents

    If the user wants to include local files as context or respondent-visible stimulus, upload before planning:

    getWorkflowGuide
    uploadStimulus
    User uploads files through upload_url
    listStimuli
    requestPlan
    runSimulation
    getSimulationStatus
    getSimulationAnalysis
    getSimulationResults

    One uploadStimulus session can hold multiple files. Do not create one upload session per file.

    Use stimulus_ids on requestPlan only when every file in the upload session should be shown to simulated respondents. If some files are planning-only context and others are respondent-visible stimulus, call listStimuli and pass explicit file references through planning_context_items and simulation_stimulus_items.

    The planner needs stimulus before requestPlan so it can choose the right test type, mode, and arm mapping. Stimulus cannot be attached later through bindAsset.

    Private or logged-in websites

    If respondents need to test a page behind login, complete the live sign-in flow before planning:

    getWorkflowGuide
    startWebsiteLiveSignIn
    User opens login_link and signs in
    completeWebsiteLiveSignIn
    requestPlan
    runSimulation
    getSimulationStatus
    getSimulationAnalysis

    Pass the returned website_connection_id on the respondent-visible URL item sent to requestPlan, such as simulation_stimulus_urls=[{url, login_url, website_connection_id}]. Populous restores that authenticated browser session before the website run.

    Use listWebsiteConnections only when the user asks to inspect or reuse a saved website connection. Use cancelWebsiteLiveSignIn to cancel a pending sign-in flow.

    Read-only discovery

    Use discovery tools only when the user explicitly asks to inspect saved resources, prior runs, or reuse an existing resource.

    getWorkflowGuide
    listPopulations
    listExperiments
    listSimulations

    Do not list saved populations or experiments speculatively before launch. The default path is fresh build from the plan.

    MCP server capabilities

    AreaToolsPurpose
    Workflow guidancegetWorkflowGuideReturns the supported v2 launch sequence, slot rules, scenarios, and pitfalls.
    Planning and launchrequestPlan, bindAsset, runSimulationConvert user intent into a temporary plan, optionally bind explicit population reuse slots, and launch the run.
    Assets and stimuliuploadStimulus, listStimuliCreate upload sessions, confirm uploaded files, and pass durable file references into planning.
    Private websiteslistWebsiteConnections, startWebsiteLiveSignIn, completeWebsiteLiveSignIn, cancelWebsiteLiveSignInReuse, create, complete, or cancel authenticated browser sessions for logged-in website tests.
    Read-only discoverylistPopulations, listExperiments, listSimulationsInspect saved populations, saved experiments, and prior simulation runs.
    Monitoring and resultsgetSimulationStatus, getSimulationAnalysis, getSimulationResults, getSimulationArtifactManifest, querySimulationArtifact, getSimulationResultsCsvDownloadTrack a run, fetch compact analysis, inspect structured results and artifacts, and create filtered CSV download links.

    Current exposed tools:

    getWorkflowGuide
    requestPlan
    bindAsset
    runSimulation
    uploadStimulus
    listStimuli
    listWebsiteConnections
    startWebsiteLiveSignIn
    completeWebsiteLiveSignIn
    cancelWebsiteLiveSignIn
    listPopulations
    listExperiments
    listSimulations
    getSimulationStatus
    getSimulationResults
    getSimulationAnalysis
    getSimulationArtifactManifest
    querySimulationArtifact
    getSimulationResultsCsvDownload

    Older guide names such as planSimulation, runFromBrief, getAssetUploadLink, listSessionAssets, uploadSimAssets, getSimulationSetup, getSimulationStimuli, getPopulationStats, and importSimulation are not exposed by the current MCP server.

    Tool reference

    Workflow guidance

    getWorkflowGuide

    Call this once at the start of a new MCP session. It returns the canonical v2 workflow, slot-kind rules, common scenarios, and tool-ordering pitfalls.

    Use it when:

    • A new MCP session starts.
    • A client needs to confirm the current launch workflow.
    • You are debugging a bad tool sequence.

    Planning and launch

    requestPlan

    Use requestPlan as the entry point for most user requests. It asks Populous to compile a simulation plan from a natural-language description.

    It returns:

    • plan_token: temporary token used by bindAsset and runSimulation.
    • status: usually ready, or a status such as needs_stimulus if required slots are unsatisfied.
    • slots: the plan's resource manifest.
    • summary: short reviewable summary of the planned run.

    Call it with a concrete description of what the user wants to learn. The planner chooses the test type and mode from the description plus any supplied context or stimulus. Do not decide observe vs intervene yourself; the slot manifest reflects the planner's decision.

    Useful inputs include:

    • description: required natural-language request.
    • stimulus_ids: upload session ids from uploadStimulus; use only when the entire upload session is respondent-visible stimulus.
    • planning_context_items: background docs, notes, links, or files that should inform planning but should not be shown directly to respondents.
    • simulation_stimulus_items: files, screenshots, ads, PDFs, mockups, URLs, or text that respondents should actually see or interact with.
    • planning_context_urls: planning-only URLs.
    • simulation_stimulus_urls: respondent-visible URLs; these strongly suggest a Website test.
    • context_items: fully explicit mixed context when the client already has the structure.
    • upload_session_id and uploaded_assets_audience: whole-session attach for one upload session.
    • n_per_group: requested respondents per population; the backend can cap this by subscription tier.

    Keep planning context separate from respondent-visible stimulus. For example, a strategy memo may belong in planning_context_items, while an ad image should be attached as simulation_stimulus_items.

    For local files, call uploadStimulus before requestPlan. Do not pass base64, data: URLs, or raw file bytes through tool arguments.

    Slot manifest

    requestPlan returns slots with shape:

    {slot_id, kind, summary, required, default, bound_to?, read_only?}

    Slot kinds:

    • population: bindable when the user explicitly wants to reuse a saved population. Single-population plans use pop; multi-population plans use pop_0, pop_1, and so on.
    • experiment: read-only build-fresh slot. The experiment is generated from the plan; reuse is not supported in the current workflow.
    • stimulus: pre-bound at requestPlan time when using stimulus_ids; read-only after planning.
    • arm_stimulus: read-only planner-assigned stimulus for intervention arms.

    Treat read_only as authoritative. bindAsset rejects read-only slots, stimulus slots, and arm-stimulus slots.

    bindAsset

    Use bindAsset only when the user explicitly asks to reuse an existing saved population.

    Inputs:

    • plan_token: from requestPlan.
    • slot_id: the slot to override, such as pop or pop_0.
    • asset_id: a real population_key from listPopulations.

    Rules:

    • Do not fabricate ids.
    • Do not pre-list assets unless the user references reuse.
    • Do not bind stimulus. Stimulus must be supplied to requestPlan.
    • Do not bind read-only slots.
    • If the plan token has expired, call requestPlan again.

    For population reuse, call listPopulations, choose the intended population_key, then bind the relevant population slot.

    Do not use bindAsset for saved experiment reuse. The current workflow guide marks experiments as build-fresh plan outputs, and bindAsset rejects read-only slots.

    runSimulation

    Executes the plan identified by plan_token.

    runSimulation:

    • Creates fresh populations for unbound population slots.
    • Uses bound population keys as-is.
    • Creates the experiment from the plan.
    • Uses stimulus and arm assignments supplied at requestPlan time.
    • Starts the simulation.
    • Returns sim_key, population key data, experiment_key, bindings_applied, results_url, and sometimes sample_limit_summary.

    Call runSimulation only after the plan status is ready.

    Do not pass overrides to runSimulation; it only accepts plan_token.

    Assets and stimuli

    uploadStimulus

    Creates a one-time upload page where the user can drop image or document files.

    Use it when:

    • The user has local images, ads, screenshots, mockups, PDFs, documents, or other files.
    • You generated a file in chat and it needs to become simulation stimulus.
    • A chat client cannot send file bytes through MCP tool arguments.

    It returns:

    • stimulus_id: the upload session id.
    • upload_url: the page to share with the user.

    After the user uploads files, call listStimuli(stimulus_id) to confirm the assets. Then call requestPlan with either stimulus_ids=[stimulus_id] or explicit planning_context_items and simulation_stimulus_items.

    Do not use bindAsset to attach uploaded stimulus after planning. If an older tool hint suggests binding stimulus, ignore that hint; bindAsset rejects stimulus slots post-plan.

    listStimuli

    Lists the confirmed assets in an upload session.

    Use it when:

    • The user has finished uploading files.
    • You need to verify asset_count > 0 before planning.
    • You need durable file references to split uploaded files into planning context vs respondent-visible stimulus.

    It returns scrubbed asset records. Use stimulus_asset_ref, asset_id, or gcs_path when passing uploaded files back into requestPlan.

    Do not treat file preview URLs as website stimulus. Use simulation_stimulus_urls only when the user truly wants respondents to browse or evaluate a website.

    Private websites

    listWebsiteConnections

    Lists saved website connections for the authenticated user. Use it when:

    • The user asks whether a saved connection exists.
    • The user wants to reuse an authenticated website session.
    • You need to filter saved connections by target_url.

    Do not call it speculatively for public website tests.

    startWebsiteLiveSignIn

    Starts the live sign-in flow for a private or logged-in website test.

    Inputs include:

    • target_url: required private or logged-in page respondents should access.
    • login_url: optional sign-in page; defaults to target_url.
    • label: optional saved-connection label.
    • connection_id: optional existing connection to refresh.
    • auto_relogin: optional boolean for automatic re-login fallback.

    It returns an auth_session_id and a login_link. Show the login_link to the user and wait for them to finish signing in before planning.

    completeWebsiteLiveSignIn

    Completes and saves a pending sign-in session. Call it after the user confirms they signed in through the login_link.

    It takes auth_session_id and returns a website_connection_id. Pass that id inside the respondent-visible URL item sent to requestPlan.

    cancelWebsiteLiveSignIn

    Cancels a pending live sign-in flow and releases its temporary browser session. Use it when the user abandons or restarts the login flow.

    Read-only discovery

    listPopulations

    Lists the authenticated user's saved populations. Responses are keyed by population_key.

    Use it when:

    • The user explicitly asks which populations they have.
    • The user asks to reuse an existing population.
    • You need to identify the correct population key before bindAsset.

    Do not use it as a normal launch step. Fresh population creation is the default.

    listExperiments

    Lists the authenticated user's saved experiments. Responses are keyed by experiment_key.

    Use it when:

    • The user explicitly asks which experiments they have.
    • The user asks to reuse an existing experiment.
    • You need to identify the correct experiment key before bindAsset.

    Do not use it as a normal launch step. Fresh experiment creation is the default.

    listSimulations

    Lists the authenticated user's simulations with status and keys.

    Use it when:

    • The user asks what simulations exist.
    • You need to find a prior sim_key.
    • You are checking whether a run exists before inspecting results.

    The current MCP server does not expose a setup-clone tool. To branch a prior idea, use information from the prior run as context for a new requestPlan.

    Monitoring and results

    getSimulationStatus

    Gets the current status for a simulation by sim_key.

    Use it after runSimulation.

    Typical sequence:

    runSimulation
    getSimulationStatus
    getSimulationStatus
    getSimulationAnalysis
    getSimulationResults

    Wait for the simulation to complete before requesting results.

    getSimulationAnalysis

    Fetches the compact analysis payload for a completed simulation by sim_key.

    Use it when:

    • The simulation is complete.
    • The user wants the plain-English verdict, summary, and findings.
    • You need the fastest post-run answer before deciding whether to inspect full results.

    This tool takes only sim_key. It is the preferred first results call for normal user-facing answers.

    getSimulationResults

    Fetches results for a completed simulation by sim_key.

    The server checks the run status, chooses the appropriate results endpoint for survey vs website-style runs, and trims oversized fields for MCP response size. It preserves the analytical content an agent needs, including overview counts, findings, hypothesis validation, question-level breakdowns, respondent profile samples, and quote highlights when available.

    Use it when:

    • The simulation is complete.
    • The user asks what the simulation found.
    • You need result details for a report or downstream transformation.

    If the user needs the full untrimmed payload, use the web UI or the underlying API outside the MCP response-size constraints.

    getSimulationArtifactManifest

    Lists queryable artifacts for a completed simulation, including raw CSV artifacts and structured result tables.

    Use it when:

    • getSimulationAnalysis or getSimulationResults is not enough.
    • The run is large and you need table-level inspection.
    • You need an artifact_id before calling querySimulationArtifact.

    This tool takes only sim_key.

    querySimulationArtifact

    Queries one simulation artifact server-side. Use it for large runs instead of pulling the whole result payload through MCP.

    Inputs include:

    • sim_key: required simulation key.
    • artifact_id: required id from getSimulationArtifactManifest.
    • select: optional columns to return.
    • filters: optional row filters such as {column, op, value}. Supported operators include eq, in, contains, gt, gte, lt, and lte.
    • sort: optional sort specs such as {column, direction}.
    • limit: optional row cap; default is 50 and max is 200.
    • offset: optional row offset for pagination.

    getSimulationResultsCsvDownload

    Creates a short-lived direct download URL for the raw results CSV.

    Use it when:

    • The user asks for the raw data.
    • You need to export one population, arm, or stage slice.
    • You need columns, filters, or sorting that are easier to express as CSV export options than as a chat answer.

    Inputs include:

    • sim_key: required simulation key.
    • stage_idx: optional stage index for multi-stage runs. When omitted on a multi-stage run, the export combines stages and stamps stage metadata onto the rows.
    • select: optional list of CSV columns.
    • filters: optional row filters such as {column, op, value}. Supported operators include eq, in, contains, gt, gte, lt, and lte.
    • sort: optional sort specs such as {column, direction}.

    Common pitfalls

    Using old tool names

    The current server does not expose planSimulation, runFromBrief, getAssetUploadLink, listSessionAssets, uploadSimAssets, getSimulationSetup, getSimulationStimuli, getPopulationStats, or importSimulation.

    Use the current v2 tools listed above.

    Planning before upload

    If the user supplied local files/images for the simulation to show, call uploadStimulus and listStimuli before requestPlan. The planner needs stimulus up front to choose the right test type, mode, and arm mapping.

    Attaching stimulus through bindAsset

    bindAsset is not a stimulus attachment tool. Stimulus slots are pre-bound at plan time or assigned to arms by the planner. To change stimulus, call requestPlan again with corrected stimulus_ids, planning_context_items, or simulation_stimulus_items.

    Mixing planning context with respondent-visible stimulus

    Background research, notes, decks, and strategic context can help Populous design the simulation, but they are not always assets respondents should see.

    Use planning context for design inputs. Use simulation stimulus for material the synthetic audience should evaluate directly.

    Listing saved resources speculatively

    Do not call listPopulations or listExperiments unless the user explicitly asks to inspect or reuse saved resources. The default plan builds fresh resources.

    Fabricating or parsing keys

    Treat population_key, experiment_key, sim_key, plan_token, and stimulus_id as opaque strings. Do not parse or construct them.

    Passing inline file bytes

    Chat clients cannot send local file bytes through MCP tool arguments. Do not pass base64 fields or data: URLs into requestPlan. Use uploadStimulus, then listStimuli, and pass returned asset_id, gcs_path, or stimulus_id references.

    Expecting runtime overrides

    runSimulation accepts only plan_token. If the user changes the audience, task, uploaded files, arm assignment, or context after planning, call requestPlan again.

    Requesting results too early

    A simulation must complete before getSimulationResults can return useful output. Poll getSimulationStatus first.

    Skipping private-site sign-in

    For logged-in websites, do not send only the private URL to requestPlan. Start and complete the live sign-in flow first, then pass the returned website_connection_id with the respondent-visible URL.

    Missing the compact analysis step

    Use getSimulationAnalysis first for a normal answer. Use getSimulationResults for detailed structured payloads, getSimulationArtifactManifest and querySimulationArtifact for large queryable artifacts, and getSimulationResultsCsvDownload for raw CSV export links.

    Examples

    New exploratory simulation

    User request:

    Would mid-market HR leaders trust this onboarding automation product?

    Tool flow:

    getWorkflowGuide
    requestPlan(description="Would mid-market HR leaders trust this onboarding automation product?")
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)
    getSimulationResults(sim_key)

    Use this flow because the user starts from a question and audience that Populous should turn into a simulation plan.

    Add one ad image as respondent-visible stimulus

    Tool flow:

    getWorkflowGuide
    uploadStimulus(label="Q3 ad creative")
    User uploads the image through upload_url
    listStimuli(stimulus_id)
    requestPlan(description="Test ad recall with US shoppers", stimulus_ids=[stimulus_id])
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)
    getSimulationResults(sim_key)

    Use stimulus_ids because the whole upload session is respondent-visible stimulus.

    Split uploaded files into planning context and simulation stimulus

    User provides a strategy memo and two ad variants.

    Tool flow:

    getWorkflowGuide
    uploadStimulus(label="Memo and ad variants")
    User uploads all files through the same upload_url
    listStimuli(stimulus_id)
    requestPlan(
      description="Compare which ad variant is more credible to budget owners.",
      planning_context_items=[{asset_id: "<memo_asset_id>", audience: "planning"}],
      simulation_stimulus_items=[
        {asset_id: "<variant_a_asset_id>", audience: "simulation"},
        {asset_id: "<variant_b_asset_id>", audience: "simulation"}
      ]
    )
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)
    getSimulationResults(sim_key)

    Use structured context because not every uploaded file should be shown to respondents.

    Compare multiple audiences

    User request:

    Compare urgency for this product across SMB, mid-market, and enterprise buyers.

    Tool flow:

    getWorkflowGuide
    requestPlan(description="Compare urgency for this product across SMB, mid-market, and enterprise buyers.")
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)
    getSimulationResults(sim_key)

    The returned slots may include pop_0, pop_1, and pop_2. Do not manually create three separate runs unless the user asks for that.

    Reuse an existing population

    User request:

    Run this on my US millennials population.

    Tool flow:

    getWorkflowGuide
    listPopulations
    requestPlan(description="Test ad recall for the proposed campaign.")
    bindAsset(plan_token, slot_id="pop", asset_id="<population_key>")
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)
    getSimulationResults(sim_key)

    Use this flow because the user explicitly referenced a saved population.

    Private website test

    User request:

    Test whether trial users can find the billing export in our logged-in dashboard.

    Tool flow:

    getWorkflowGuide
    startWebsiteLiveSignIn(target_url="https://app.example.com/dashboard", login_url="https://app.example.com/login")
    User opens login_link and signs in
    completeWebsiteLiveSignIn(auth_session_id)
    requestPlan(
      description="Test whether trial users can find the billing export in our dashboard.",
      simulation_stimulus_urls=[{url: "https://app.example.com/dashboard", login_url: "https://app.example.com/login", website_connection_id: "<website_connection_id>"}]
    )
    runSimulation(plan_token)
    getSimulationStatus(sim_key)
    getSimulationAnalysis(sim_key)

    Use this flow when the site requires authentication. Do not plan the private website test until the saved website connection exists.

    Query a large results artifact

    User request:

    Show me enterprise-only rows with the strongest objections.

    Tool flow:

    getSimulationStatus(sim_key)
    getSimulationArtifactManifest(sim_key)
    querySimulationArtifact(
      sim_key,
      artifact_id="<artifact_id>",
      filters=[{column: "population_key", op: "eq", value: "pop_1"}],
      limit=100
    )

    Use this flow when the user wants a focused slice from a large completed run. Get a real artifact_id from the manifest and real filter values from prior metadata or result payloads.

    Export one results slice

    User request:

    Export the results for the enterprise audience.

    Tool flow:

    getSimulationStatus(sim_key)
    getSimulationResultsCsvDownload(sim_key, filters=[{column: "population_key", op: "eq", value: "pop_1"}])

    Use this flow when the user needs raw rows for a population, A/B arm, or stage. Use the result payload or prior run metadata to choose real filter values; do not invent keys.

    Operational notes

    • The MCP server implements Streamable HTTP directly at /mcp.
    • GET /mcp is an SSE keep-alive probe and can be used by clients before auth.
    • POST /mcp requires Authorization: Bearer <access_token>.
    • The server advertises OAuth metadata from the MCP host and proxies OAuth registration/token/authorization paths to the web app.
    • Keep tool calls scoped to the v2 workflow unless the server exposes a new tool in tools/list.
    • Treat getWorkflowGuide and the live tools/list response as the client-facing source of truth, with mcp/server.py as the implementation source of truth for this guide.