@clien-ai/mcp
v0.2.1
Published
Clien.ai MCP server — deep product research from Claude Code.
Maintainers
Readme
@clien-ai/mcp
Run a full Clien.ai product-research pass from Claude Code. One tool —
clien_research — that takes an idea, runs a 15-25 minute deep research pass
on our sandbox, and hands you back a markdown report plus structured
report_data (hypotheses, competitors, key findings) with a typed
trust layer — per-claim GROUNDED/SPECULATION/NO_RECEIPT
classifications, source receipts, and robustness survival counts.
Quick start
npx @clien-ai/mcp installRestart Claude Code, then ask:
run a deep research pass on my product idea
The first call opens your browser for a one-time OAuth login. The refresh token is stored in your OS keyring (or an encrypted file if the keyring is unavailable). Subsequent calls reuse it silently.
Manual install
If you prefer to edit Claude Code's config yourself, add this to
~/.claude.json:
{
"mcpServers": {
"clien": {
"command": "npx",
"args": ["-y", "@clien-ai/mcp"]
}
}
}Restart Claude Code. First call triggers OAuth.
What the tool returns
{
"content": [{ "type": "text", "text": "<full markdown report>" }],
"_meta": {
"job_id": "...",
"status": "complete",
"report_data": {
"hypotheses": [...],
"competitors": [...],
"key_findings": [...],
// Trust layer (typed):
"claims": [
{ "id": "CLM-p0-pp0", "personaId": "persona-0", "text": "...", "state": "GROUNDED", "sourceId": "RCP-p0-s0", "quoteSpan": "..." }
],
"personas": [
{ "name": "...", "sources": [{ "url": "...", "platform": "Hacker News", "quote": "...", "retrievedAt": "..." }] }
],
"hypothesisResults": [
{ "hypothesisId": "h1", "status": "validated", "confidence": 0.82, "robustness": { "survived": 3, "total": 3, "flipped": false } }
],
"sycophancySignals": { "lowDiscriminationCount": 0, "totalRejections": 2, "personaSignals": [...], "disagreements": [...] }
// ...the full structured report
}
}
}The markdown is what a human reads. The structured report_data is what you
pass back to Claude Code when you want it to reason about the research
further — "find the strongest competitor", "draft a positioning doc against
the top 3 threats", etc.
Trust signals
report_data carries a typed trust layer so you can judge how well-evidenced
a finding is, rather than taking the prose at face value:
| Field | What it tells you |
|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| claims[] | Every persona/interview claim with a state: GROUNDED (span-verified against a cached source quote), SPECULATION, or NO_RECEIPT (evidence-shaped but unsourced). A GROUNDED claim carries a sourceId receipt and the quoteSpan that grounds it. |
| personas[].sources[] | The cached forum posts (url, platform, quote, retrievedAt) a claim's sourceId (RCP-p{i}-s{j}) points at — the receipts. |
| personas[].qaFlagged / insufficientEvidence / sourcesFound | Per-persona quality flags: qaFlagged means the persona failed a QA check; insufficientEvidence / sourcesFound tell you whether a NO_RECEIPT reflects a weak claim or just a thin evidence base. |
| hypothesisResults[].robustness | How many reworded re-asks a verdict survived (survived/total); when flipped is true, downgradedStatus is the verdict to trust, not the top-level status. |
| sycophancySignals | Anti-sycophancy readout: broken-persona flags (lowDiscrimination), per-hypothesis disagreement splits, and explicit totalRejections. |
These fields are all optional — a legacy report or a run that skipped a section
simply omits them. The full Zod schema lives in
src/types/report.ts.
Recipes: composing beyond the hero
clien_research is the hero — the recommended default for validating an idea
end to end. Alongside it, the server exposes granular primitives (create_persona,
generate_persona, enrich_persona, interview_persona, scan_competitors, search_forums,
list_projects / create_project, list_reports / get_report,
clien_research_status) you can sequence for targeted, cheaper checks.
See docs/recipes/ for the supported compositions:
- Competitor spot-check — read
competitors[]from a report instead of commissioning a new study - Pivot viability — research a pivot and compare it against the original
- New-market persona validation —
create_persona→interview_persona, no credits, no full run
Rule of thumb: for a full validation, call the hero; reach for a primitive composition only for a narrow, cheaper probe.
Inputs
| Field | Type | Required | Default | Notes |
|----------------|--------------------------|----------|---------|--------------------------------------------------------------------------------------------------|
| idea | string (1-10,000 chars) | yes | | The idea, hypothesis, or question |
| depth | "quick" | "deep" | no | deep | quick caps cost; deep is the full 15-25 min pass |
| project_id | UUID | no | | Existing Clien.ai project to attach the run to (returned in _meta.project_id from prior runs) |
| project_name | string (1-100 chars) | no | | Name for a new project. Supply when project_id is not set so the report is discoverable in the web UI. Ignored when project_id is also provided. |
Outputs
The tool returns markdown content plus _meta:
| _meta field | Type | Notes |
|--------------------|-----------------|-------------------------------------------------------------------------------------|
| job_id | UUID | The validation job's ID |
| status | string | Terminal status: complete, failed, or cancelled |
| project_id | UUID | null | The project this run is attached to. Pass back as project_id on follow-up runs. |
| report_data | object | null| Structured report (hypotheses, competitors, key findings) plus the typed trust layer — claims[], personas[].sources[], hypothesisResults[].robustness, sycophancySignals (see Trust signals) |
| total_cost_cents | number | Optional. Total cost of the run, in cents. |
Progress
The MCP emits notifications/progress events every ~5 seconds during the
run. Claude Code keeps the tool call alive as long as progress flows
(verified in our Unit 0 spike with a 25-minute run).
Troubleshooting
| Symptom | Likely cause | Fix |
|------------------------------------------------------------|----------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| "Session expired during research" | Access + refresh both expired | Run clien_research again — triggers re-consent in browser |
| "Insufficient credits ..." | Credit balance at 0 | Buy a pack at https://clien.ai/app/billing |
| "All OAuth redirect ports [7873, 7874, 7875] are in use" | Another app is on all three loopback ports | Free one port and retry |
| "keytar not available" note in logs | libsecret missing (WSL, headless Linux) | Falls back to AES-256-GCM encrypted file at ~/.clien-ai/tokens.json.enc — OK but weaker than the OS keyring |
| Browser never opens | Headless environment / container | See the Devcontainer / remote SSH section below |
| tokens.json.enc corrupt after a copy to a different host | Machine-id changed; encrypted file can't decrypt | Run clien_research — triggers new OAuth, overwrites the file |
Reset authentication
# Drops the stored refresh token. Next tool call opens OAuth again.
npx @clien-ai/mcp logout
# --json for agent-pipeable output
npx @clien-ai/mcp logout --json
# {"ok":true,"hadTokenIn":"file"}Check current state
# Snapshot of credentials state without triggering OAuth.
npx @clien-ai/mcp status
# @clien-ai/mcp v0.1.0
#
# Backend: file
# Has token: yes
# Last refreshed: 2026-04-27T14:32:18.421Z (3h ago)
# --json for agents
npx @clien-ai/mcp status --jsonHeadless / CI authentication
For non-interactive environments (devcontainers, CI runners, remote SSH), the loopback OAuth flow can't open a browser. Two ways to authenticate without a TTY:
# 1) Pre-seed via env var (skips OAuth entirely on first call):
export CLIEN_MCP_REFRESH_TOKEN=<refresh_token_from_a_prior_browser_run>
npx @clien-ai/mcp
# 2) Or persist the seed once with the authorize subcommand:
npx @clien-ai/mcp authorize --token <refresh_token>If neither is set in a non-TTY context (CI / devcontainer / SSH session
without a browser), the OAuth flow opens a loopback server and waits up to
5 minutes for the callback. After that timeout it surfaces oauth_timeout
with the authorize URL — re-run after seeding the env var or the
authorize subcommand. (The MCP intentionally does NOT short-circuit on
non-TTY because Claude Code launches the server over stdio, which is also
non-TTY but is the primary production path.)
Devcontainer / remote SSH / Docker
Run the MCP on your local machine, not inside a container or a remote
shell. The OAuth handshake opens a browser on http://localhost:787x/callback,
which won't reach a containerized or remote process. Claude Code already
runs locally; the MCP subprocess it spawns runs locally too by default.
If you develop inside a devcontainer and want to use Clien.ai, install and configure the MCP in your host's Claude Code, not the one inside the container.
Env overrides (for development)
| Variable | Purpose |
|-----------------------------|----------------------------------------------------|
| CLIEN_MCP_ENV=test | Use the test Supabase project + test client id |
| CLIEN_MCP_SERVER_URL | Override the Clien.ai HTTP base URL |
| CLIEN_MCP_SUPABASE_URL | Override the Supabase auth base URL |
| CLIEN_MCP_CLIENT_ID | Override the OAuth client id |
| CLIEN_MCP_POLL_INTERVAL_MS| Change events poll cadence (default 5000 ms) |
Privacy
Credentials never leave your machine. The refresh token is stored either in your OS keyring (macOS Keychain, Windows Credential Manager, Linux libsecret) or in an AES-256-GCM encrypted file keyed to your host. Clien.ai sees only the bearer token on each API call — the same token your browser would send from the web app.
CLI exit codes
The CLI uses stable, documented exit codes so scripts and agents can branch on failure class without parsing message strings.
| Code | Meaning |
|------|---------|
| 0 | success |
| 1 | generic / uncategorized error |
| 2 | authentication failed (OAuthError, refresh-token revoked, no-TTY without env seed) |
| 3 | filesystem operation failed (EACCES, ENOENT, ENOTDIR, ENOSPC, EROFS, ...) |
| 4 | network operation failed (AbortError, TimeoutError, fetch failed) |
| 5 | invalid arguments / unknown flag |
Pass --debug to any command to surface stack traces alongside the
human-readable error message.
License
UNLICENSED — do not redistribute. Contact Clien.ai for commercial licensing.
