# SynthPanel

> Run synthetic focus groups and user research panels using AI personas. CLI tool, Python library, any LLM.

- **Type:** MCP server
- **Install:** `agentstack add mcp-dataviking-tech-synthpanel`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [DataViking-Tech](https://agentstack.voostack.com/s/dataviking-tech)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [DataViking-Tech](https://github.com/DataViking-Tech)
- **Source:** https://github.com/DataViking-Tech/SynthPanel
- **Website:** https://dataviking-tech.github.io/synthbench/

## Install

```sh
agentstack add mcp-dataviking-tech-synthpanel
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# synthpanel

[](https://pypi.org/project/synthpanel/)
[](https://github.com/DataViking-Tech/SynthPanel/actions/workflows/ci.yml)
[](LICENSE)
[](https://pypi.org/project/synthpanel/)
[](https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/mcp.md)
[](https://github.com/DataViking-Tech/SynthPanel/pkgs/container/synthpanel)
[](https://ko-fi.com/dataviking)

Site:  · Benchmark: 

**SynthPanel is the synthetic-population MCP server for AI agents.**

When your agent needs to know what a representative slice of humans would say
about a decision — pricing, naming, friction points, copy — it makes one tool
call:

```jsonc
// MCP tool call
{
  "tool": "run_panel",
  "arguments": {
    "pack_id": "general-consumer",
    "questions": [{ "text": "Would you pay $49 or $79 for this launch tier?" }],
    "decision_being_informed": "choosing launch tier price"
  }
}

// Response (same envelope from both `run_panel` and `panel run --output-format json`)
{
  "result_id": "result-20260510-abc123",
  "model": "claude-haiku-4-5",
  "synthesis": {
    "summary": "Cohort splits on $79; price is the dominant objection.",
    "themes": [...],
    "agreements": [...],
    "disagreements": [...],
    "surprises": [...],
    "recommendation": "..."
  },
  "rounds": [{ "name": "default", "results": [...], "synthesis": null }],
  "path": [],
  "warnings": [],
  "total_cost": "$0.0142",
  "total_usage": { "input_tokens": 4231, "output_tokens": 1102, ... },
  ...
}
```

You get a structured `synthesis` block — themes, agreements, disagreements,
surprises, and a single recommendation line your agent can act on — plus the
full per-panelist transcript under `rounds[].results[]` and per-turn cost
telemetry. **Bring your own LLM key — Claude, OpenAI, Gemini, or local.**
Drops into Claude Code, Cursor, Windsurf, LangChain, CrewAI, OpenAI Agents
SDK.

> **Note (v1.0.6):** the v1.0.0 `panel_verdict` artifact (`headline`,
> `convergence`, `dissent_count`, `flags[]`, `schema_version`) defined in
> [`schemas/v1.0.0.json`](src/synth_panel/schemas/v1.0.0.json) is now **emitted
> on the success path** of the MCP panel tools (`run_panel`, `run_quick_poll`,
> `extend_panel` in BYOK mode): it rides under the envelope's `panel_verdict`
> key alongside the `synthesis` block above, and the response gate validates it
> on egress. Sampling-mode and ensemble runs don't persist a transcript and
> carry no verdict; the CLI `panel run` envelope is unchanged — see
> [docs/response-contract.md](docs/response-contract.md). Error responses use
> the typed envelope (`error_code`, `schema_version`, `retry_safe`).

```bash
pip install synthpanel
```

**Frozen contract:** the v1.0.0 schema lives in the package at
[`synthpanel/schemas/v1.0.0.json`](src/synth_panel/schemas/v1.0.0.json) and is
echoed on every persisted-panel success envelope and every typed error
(`schema_version: "1.0.0"`). Field-by-field reference:
[docs/response-contract.md](docs/response-contract.md). Migrating from v0.12?
[docs/migration-v1.md](docs/migration-v1.md). Methodology and inspectability:
[docs/methodology.md](docs/methodology.md).

**Zero-config inside any MCP host that speaks sampling** (Claude Desktop,
Claude Code, Cursor, Windsurf) — drop the config in and run a panel with **no
API key set**. The host runs the model on your behalf, using its own
subscription. Bring your own provider key when you want reproducibility,
ensembles, or larger panels. Personas and instruments are plain YAML; every
response is schema-validated with per-turn cost telemetry.

## Why

Traditional focus groups cost $5,000-$15,000 and take weeks. Synthetic panels cost pennies and take seconds. They don't replace real user research, but they're excellent for:

- **Pre-screening** survey instruments before spending budget on real participants
- **Rapid iteration** on product names, copy, and positioning
- **Hypothesis generation** across demographic segments
- **Concept testing** at the speed of thought

## Agent Quick Start

> **New here?** [**docs/agent-quickstart.md**](docs/agent-quickstart.md) is the
> full end-to-end walkthrough — install → verify → dry-run → run → 30–40 persona
> poll → save → emit JSON, on both the CLI and MCP surfaces, with a
> structured-output example. The snippets below are the short version.

Wire the MCP server into your editor (see [Use with Claude Code / Cursor /
Windsurf / Zed](#use-with-claude-code--cursor--windsurf--zed) below) and call
the four research tools from agent code. Every panel-running call requires a
`decision_being_informed` field (12–280 chars, single line) — the panel won't
run without one.

```jsonc
// run_panel — full synthetic focus group
{
  "tool": "run_panel",
  "arguments": {
    "pack_id": "general-consumer",
    "instrument_pack": "pricing-discovery",
    "decision_being_informed": "choosing launch tier price"
  }
}

// run_quick_poll — one question across personas
{
  "tool": "run_quick_poll",
  "arguments": {
    "question": "Which name feels most premium: Core, Plus, or Pro?",
    "pack_id": "general-consumer",
    "decision_being_informed": "naming the paid tier"
  }
}

// extend_panel — append an ad-hoc follow-up round
{
  "tool": "extend_panel",
  "arguments": {
    "result_id": "result-20260503-abc123",
    "questions": ["What would you pay for this if it shipped tomorrow?"],
    "decision_being_informed": "validating the indie pricing ceiling"
  }
}
```

Read `synthesis.recommendation` for the headline call, `synthesis.disagreements`
for dissent, and `rounds[].results[]` for the per-panelist transcript. See
[docs/response-contract.md](docs/response-contract.md) for the full v1.0.0
envelope (note: `panel_verdict` fields like `convergence` and `flags[]` are
defined but not yet emitted on the success path — see the note in the lede).

**Structured polling is the agent default.** For pick-one, Likert,
confidence, and tagged-themes questions, pass a bounded
`response_schema` so panelists return parsed JSON, not prose. No regex,
no post-hoc parsing. See [docs/structured-polling.md](docs/structured-polling.md)
for the full pattern catalogue and a runnable 35-persona prioritization
example.

## Human Operator Quick Start

Prefer a terminal? Same engine, CLI surface. Pick the install path that
matches how you use Python tools:

| Path | When | Command |
|------|------|---------|
| **pip** (in your project venv) | You're integrating SynthPanel as a library | `pip install synthpanel` |
| **pip + MCP** (in your project venv) | You also want the MCP server for agent integration | `pip install 'synthpanel[mcp]'` |
| **pipx** (global, isolated) | You want `synthpanel` on your PATH without polluting any project | `pipx install synthpanel` |
| **uvx** (zero-install) | You just want to run it once — no install at all | `uvx --from synthpanel synthpanel --help` |
| **source** (latest unreleased) | You want main-branch fixes ahead of the next PyPI cut | `pip install git+https://github.com/DataViking-Tech/SynthPanel.git@main` |

After installing, verify the CLI is on your PATH and the runtime is sane
*before* configuring providers:

```bash
synthpanel --version              # smoke: package metadata + entry point dispatch
synthpanel doctor --install-only  # install health only — no credentials needed
synthpanel doctor                 # full preflight (install + credentials)
synthpanel whoami                 # which providers (if any) have credentials
```

### Package vs. module name

The PyPI distribution and CLI entry point are spelled **`synthpanel`** (one
word). The importable Python module — the historical PEP 8 spelling — is
**`synth_panel`** (two words, snake_case):

```python
import synth_panel                       # canonical
from synth_panel import run_panel, sdk   # library use
```

```bash
synthpanel --version          # CLI
python -m synth_panel --version  # canonical module form
python -m synthpanel --version   # one-word alias also works (sy-het)
```

Both spellings resolve to the same code. The one-word `synthpanel` module
is a thin shim (`__path__` redirect + ``__main__.py``) shipped so agents
that guess `python -m ` don't hit a wall. New code should still
prefer `import synth_panel` — it's what `__all__`, the docs, and the
schemas refer to.

`doctor` exits non-zero with actionable guidance when something's
missing (no provider configured, wrong Python, MCP extra absent, etc.) —
it's the canonical "did the install land cleanly?" check, and
`clean-install-smoke` in CI runs the same sequence against the built
wheel on every push, so all three commands are part of the supported
contract.

Use `synthpanel doctor --install-only` immediately after `pip install
synthpanel` to validate the package, dependencies, and bundled packs
without provisioning a provider key — exit 0 in that mode means the
install is healthy, even when credentials are not yet configured. The
JSON output (`--output-format json doctor --install-only`) separates
`install_ok`, `credential_configured`, and `checks_ok` so agents and CI
can branch on each surface independently.

Then provide an API key (Claude, OpenAI, Gemini, xAI, or any
OpenAI-compatible provider) — either export it in your shell or persist
it once via `synthpanel login`:

```bash
export ANTHROPIC_API_KEY="sk-..."
# or
synthpanel login --provider anthropic --api-key sk-...    # stored at
# ~/.config/synthpanel/credentials.json, mode 0600
synthpanel whoami

# Run a single prompt
synthpanel prompt "What do you think of the name Traitprint for a career app?"

# Run a full panel
synthpanel panel run \
  --personas examples/personas.yaml \
  --instrument examples/survey.yaml
```

## Works with

SynthPanel is **MCP-native** — it ships an MCP server, and every major
agent framework now supports MCP as a first-class tool source. That
means SynthPanel works out of the box with any framework that speaks
MCP, with zero framework-specific wrapper packages to install. Runnable
examples for each framework live in
[`examples/integrations/`](examples/integrations/README.md).

| Framework | Example | Bridge | One-line install |
|-----------|---------|--------|------------------|
| [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/mcp/) | [openai_agents.py](examples/integrations/openai_agents.py) | Built-in `MCPServerStdio` | `pip install openai-agents synthpanel[mcp]` |
| [LlamaIndex](https://docs.llamaindex.ai/) | [llamaindex_tool.py](examples/integrations/llamaindex_tool.py) | `llama-index-tools-mcp` | `pip install llama-index-tools-mcp llama-index-llms-anthropic synthpanel[mcp]` |
| [CrewAI](https://docs.crewai.com/) | [crewai_tool.py](examples/integrations/crewai_tool.py) | `crewai-tools[mcp]` | `pip install "crewai-tools[mcp]" crewai synthpanel[mcp]` |
| [LangChain](https://python.langchain.com/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langchain-anthropic synthpanel[mcp]` |
| [LangGraph](https://langchain-ai.github.io/langgraph/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langgraph langchain-anthropic synthpanel[mcp]` |
| [Microsoft Agent Framework 1.0](https://learn.microsoft.com/en-us/agent-framework/) | [microsoft_agent.py](examples/integrations/microsoft_agent.py) | Built-in `MCPStdioTool` | `pip install agent-framework synthpanel[mcp]` |
| [n8n](https://n8n.io/) | [n8n_workflow.json](examples/integrations/n8n_workflow.json) | Built-in MCP Client tool | `pip install synthpanel[mcp]` on the n8n runner |
| [LangChain via Composio](https://composio.dev/) | [composio_langchain.py](examples/integrations/composio_langchain.py) | `synth_panel.integrations.composio` (in-process, non-MCP) | `pip install composio composio_langchain langchain langchain-anthropic synthpanel` |
| [CrewAI via Composio](https://composio.dev/) | [composio_crewai.py](examples/integrations/composio_crewai.py) | `synth_panel.integrations.composio` (in-process, non-MCP) | `pip install composio composio_crewai crewai synthpanel` |

Also reaches [Zapier MCP](https://zapier.com/mcp) (30K+ actions), the
[VS Code AI Toolkit](https://code.visualstudio.com/api/extension-guides/ai/mcp),
Windsurf, Cursor, Zed, Claude Code, and Claude Desktop via the same MCP
server — all clients in that list install SynthPanel with
`pip install synthpanel[mcp]` and a one-line MCP config entry (see
[Use with Claude Code / Cursor / Windsurf / Zed](#use-with-claude-code--cursor--windsurf--zed)).

> **Don't see your framework?** MCP bridges are available for nearly
> every major agent framework. Start from
> [`examples/integrations/README.md`](examples/integrations/README.md)
> — the pattern is identical in each case (point the client at
> `synthpanel mcp-serve` over stdio) — or
> [file an issue](https://github.com/DataViking-Tech/SynthPanel/issues)
> so we can add a sibling example.

## Run via Docker

A pre-built image is published to both
[GitHub Container Registry](https://github.com/DataViking-Tech/SynthPanel/pkgs/container/synthpanel)
and Docker Hub on every tagged release. Use it for ephemeral or serverless
invocation (Lambda, Cloud Run, GitHub Actions, n8n) where you'd rather
spin up a container than pip-install.

```bash
# Pull (either registry works — same image, multi-arch: amd64 + arm64)
docker pull ghcr.io/dataviking-tech/synthpanel:latest
docker pull synthpanel/synthpanel:latest

# One-off prompt
docker run --rm \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  synthpanel/synthpanel \
  prompt "What makes a name feel trustworthy?"

# MCP server on stdio (default CMD — wire this into an agent's MCP config)
docker run --rm -i \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  synthpanel/synthpanel

# Panel run with a mounted instrument file
docker run --rm \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  -v "$PWD":/work -w /work \
  synthpanel/synthpanel \
  panel run --personas personas.yaml --instrument survey.yaml
```

The image's default `CMD` is `mcp-serve`, so omitting the command starts
the MCP stdio server. Any `synthpanel` subcommand can be passed as
arguments to override. Provider keys are read from environment variables
(`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`/`GEMINI_API_KEY`,
`XAI_API_KEY`) — pass whichever your model requires.

Pin to a specific version (`:0.11.0`) in production rather than `:latest`.

## Use as a Python Library

Everything the CLI and MCP server can do is also callable from Python.
No subprocess, no extra install — just import and go.

```python
from synth_panel import quick_poll, run_panel, run_prompt

# One-shot LLM call
reply = run_prompt("What makes a name feel trustworthy?")
print(reply.response, reply.cost)

# Ask a bundled persona pack a single question
poll = quick_poll(
    "Which pricing tier name feels most premium: Core, Plus, or Pro?",
    pack_id="general-consumer",
)
print(poll.synthesis["recommendation"])

# Run a full branching instrument against a bundled pack
panel = run_panel(
    pack_id="general-consumer",
    instrument_pack="pricing-discovery",
)
print(panel.path)         # e.g. ["discovery", "probe_pricing", "validation"]
print(panel.total_cost)
```

The package root exposes eight functions plus three typed return
dataclasses — `PromptResult`, `PollResult`, `PanelResult`. Every
result is dict-compatible (`result["model"]`) so code that used to
consume the MCP JSON payload works unchanged.

| Function | What it does |
|----------|--------------|
| `run_prompt(prompt, *, model=...)` | Single LLM call — no personas |
| `quick_poll(question, pack_id=...)` | One question across a panel + synthesis |
| `run_panel(pack_id=..., instrument_pack=...)` | Full branching panel run |
| `extend_panel(result_id, questions)` | Append an ad-hoc follow-up round |
| `list_personas()` / `list_instruments()` | Discover installed packs |
| `list_panel_results()` / `get_panel_result(id)` | Reload saved results |

Use this path when subp

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [DataViking-Tech](https://github.com/DataViking-Tech)
- **Source:** [DataViking-Tech/SynthPanel](https://github.com/DataViking-Tech/SynthPanel)
- **License:** MIT
- **Homepage:** https://dataviking-tech.github.io/synthbench/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-dataviking-tech-synthpanel
- Seller: https://agentstack.voostack.com/s/dataviking-tech
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
