Skip to main content
Glama
sunsiyuan

humansurvey-mcp

by sunsiyuan

HumanSurvey

Website: humansurvey.co · Docs: humansurvey.co/docs · FAQ: humansurvey.co/faq

human-survey MCP server

Attribution for the channels that have no referrer.

HumanSurvey asks one question — how did you hear about us — inside the host's own signup or payment flow, at a granularity that is actually actionable: the platform first, then which creator, podcast, event or store.

Agent configures a form   → platforms from the catalog, creators supplied by the caller
Host embeds /s/{id}       → in its signup flow, its payment flow, or both
Respondent answers        → picks a platform; that pick expands the follow-up in place
Host pushes conversions   → POST /api/attribution/events, keyed on its own user id
Agent reads back          → rollup, raw response stream, free text awaiting a mapping

What is this?

An API and MCP server for self-reported attribution. TikTok in-app, Instagram, podcasts, communities, word of mouth, AI assistants: the exposure happens where tracking cannot reach, and asking a human is the only always-on signal that survives every referrer leak.

Two placements answer different questions. In the payment flow, the respondent is already a paying customer, so the answer joins to revenue with no conversion ingest at all. In the signup flow, it is the only way to see the people a channel sends who never pay. Divide a channel's share of the paying population by its share of the signup population. Above 1 it converts better than your average, below 1 worse. Multiply that ratio by your overall signup-to-paid rate to get the channel's own rate.

It is designed for:

  • hosts embedding a form in their own onboarding or checkout

  • agents that keep the candidate list current and read the results back

It is not designed for:

  • general-purpose surveys — arbitrary question types, Markdown authoring and conditional logic were removed in the attribution pivot

  • a human-facing analytics dashboard: the aggregates are an API resource, and the agent is the dashboard

  • reaching your audience for you — HumanSurvey never contacts respondents; the transports it offers (the /s/{id} URL and the iframe embed) are ones you control

Related MCP server: veyra-forms

Features

  • Progressive disclosure, not pagination — POST the platform answer, PATCH the follow-up. The first answer is durable before the second is asked, and a respondent who abandons the follow-up is still real data.

  • Rotation by default — the orderable candidates are permuted per respondent, seeded by a client-minted render_id, so the raw share is unbiased by construction. fixed order exists for callers who want it and does not hide its bias.

  • Retroactive remapping — free text is stored verbatim and resolved against the remap table on every read, so one mapping fixes months of history with no backfill.

  • Immutable config snapshots — a response is joined to the version it was rendered against, so reconfiguring cannot rewrite what history says was shown.

  • One join key, both directionsexternal_id brings revenue in and carries per-user attribution back out to your own user table.

  • Cursor reads — a response becomes visible once it is complete, is emitted exactly once, and is final when emitted. Nothing downstream has to upsert.

Product Principles

  • AI-first I/O: agents configure the form and consume the results; humans are in the middle.

  • Everything is an API: creator functionality must be available over authenticated HTTP and MCP.

  • Narrow scope wins: one question, asked well. A feature that mainly serves a human survey operator probably does not belong here.

  • No confident percentages: every number ships beside the denominator it was computed over, and a number we cannot compute honestly is null rather than smoothed.

Quick Start

Get an API key

curl -X POST https://www.humansurvey.co/api/auth/code \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com" }'

curl -X POST https://www.humansurvey.co/api/auth/verify \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com", "code": "481920", "grant": "api_key" }'

Anonymous key creation is gone. Every key belongs to an account from birth, which is what gives a lost key a recovery path and makes rotation free.

Create a form, then configure it

curl -X POST https://www.humansurvey.co/api/attribution/forms \
  -H "Authorization: Bearer hs_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Checkout — how did you hear about us",
    "allowed_origins": ["https://app.example.com"]
  }'
{
  "id": "abc123efgh45",
  "form_url": "https://www.humansurvey.co/s/abc123efgh45",
  "warnings": ["this form has no config yet; PUT /api/attribution/forms/abc123efgh45 with {nodes} before embedding it"]
}

A form renders nothing until it has a config. PUT stores one as an immutable snapshot:

curl -X PUT https://www.humansurvey.co/api/attribution/forms/abc123efgh45 \
  -H "Authorization: Bearer hs_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "nodes": [
      {
        "id": "channel",
        "prompt": "Where did you first hear about us?",
        "candidates": [
          { "id": "tiktok", "catalog_slug": "tiktok", "expands": "creator" },
          { "id": "reddit", "catalog_slug": "reddit" },
          { "id": "friend", "label": "A friend or colleague" },
          { "id": "dunno", "label": "I don'\''t remember", "pinned": "end", "dont_remember": true }
        ]
      },
      {
        "id": "creator",
        "prompt": "Which account was it?",
        "candidates": [
          { "id": "oecuid_8812", "label": "Jade", "handle": "@jade.work0" }
        ]
      }
    ]
  }'

Platform labels, marks and aliases come from GET /api/attribution/catalog and are copied into the snapshot. Creator candidates are yours: the product renders a candidate set and returns the id that was chosen, and matching a vague description against a creator database is upstream work.

Read the results

curl "https://www.humansurvey.co/api/attribution/rollup?form_id=abc123efgh45&by=candidate&from=2026-07-01&to=2026-08-01" \
  -H "Authorization: Bearer hs_sk_..."

Also on the read side: GET /api/attribution/forms/{id}/responses (cursor stream, or one identity via ?external_id=), .../unresolved for free text awaiting a mapping, and POST .../remaps to resolve it retroactively. Full request and response shapes are in the OpenAPI document.

Use with Claude Code

{
  "mcpServers": {
    "survey": {
      "command": "npx",
      "args": ["-y", "humansurvey-mcp"],
      "env": {
        "HUMANSURVEY_API_KEY": "hs_sk_your_key_here"
      }
    }
  }
}

The server name stays survey and the package stays humansurvey-mcp — both sit inside every existing user's config. Its ten tools now speak the attribution API — see packages/mcp-server/README.md. npm publishes separately from this repo, so the version on npm can lag what is here.

Public Surface

  • Docs page: https://www.humansurvey.co/docs

  • OpenAPI: https://www.humansurvey.co/api/openapi.json

  • AI index: https://www.humansurvey.co/llms.txt

Tech Stack

Component

Technology

Framework

Next.js (App Router)

Database

Neon (serverless Postgres)

Frontend

React + Tailwind CSS

MCP Server

@modelcontextprotocol/sdk

Deployment

Vercel

Project Structure

├── apps/web/            # Next.js app (API + respondent page + site)
│   ├── lib/attribution/ # config, responses, reads, rollup, remap
│   └── supabase/migrations/  # applied through scripts/migrate.sh, with a ledger
├── packages/mcp-server/ # MCP server for Claude Code
└── docs/                # architecture, roadmap, design docs

Contributing

Read CONTRIBUTING.md before opening a PR. The most important rule is scope discipline: new UI variants, analytics dashboards, and human-operator features are usually out of scope.

Development

pnpm install
pnpm dev               # Start Next.js dev server
pnpm test              # node --test over apps/web/lib/**/*.test.ts
pnpm build             # Build all packages

License

MIT

Available Tools

5 tools
close_surveyClose SurveyA

Permanently close a survey so it no longer accepts new responses. Use this when you have enough responses or the data collection window has passed. Returns the final response count. Closing is irreversible via MCP — use PATCH /api/surveys/{id} to re-open.

ParametersJSON Schema
NameRequiredDescriptionDefault
survey_idYesThe survey ID to close

TDQS

A4.5/5.0
Behavior4/5

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

Discloses permanence ('Permanently close', 'irreversible via MCP') and return value ('Returns the final response count'). With no annotations, this covers key behavioral traits, though auth or side effects are not mentioned.

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

Conciseness5/5

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

Two concise sentences: first states purpose, second adds usage context and alternative. Front-loaded and no wasted words.

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?

For a simple tool with one param and no output schema, the description covers purpose, when to use, irreversibility, and return value fully.

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

Parameters3/5

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

Only one parameter survey_id, with 100% schema coverage. The description doesn't add extra meaning beyond the schema's 'The survey ID to close', but this is sufficient.

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 clearly states the verb 'close' and the resource 'survey' with the effect of no longer accepting new responses. This distinguishes it from siblings like create_survey, list_surveys, etc.

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?

Explicitly says 'Use this when you have enough responses or the data collection window has passed.' Also provides an alternative for re-opening via PATCH, guiding when not to use it irreversibly.

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

create_keyCreate API KeyA

Create a new HumanSurvey API key. Call this before any other tool if HUMANSURVEY_API_KEY is not set. Returns a key — store it as HUMANSURVEY_API_KEY in your MCP config. The key cannot be retrieved again after creation.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoA label for this key, e.g. the project or agent name.
emailNoContact email of the human owner. Used for billing and usage notifications in the future.
wallet_addressNoOptional wallet address in CAIP-10 format (e.g. "eip155:8453:0xabc..." for Base, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:ABC..." for Solana). Will be used for agent-native payments in the future.

TDQS

A4.2/5.0
Behavior4/5

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

Discloses that the key 'cannot be retrieved again after creation', a critical behavioral trait. No annotations exist, so the description carries the full burden; it is informative but could mention auth or error handling.

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

Conciseness5/5

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

Three concise sentences with no wasted words: first defines purpose, second gives usage context, third reveals a critical constraint. Front-loaded and efficient.

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

Completeness4/5

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

For a simple create-key tool with no output schema, the description adequately covers the action, prerequisite, and key irreversibility. Could mention return format or failure cases for full completeness.

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

Parameters3/5

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

Schema coverage is 100%, so the schema already documents all parameters. The description adds no parameter-level details beyond the schema, meeting the baseline.

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?

Clearly states 'Create a new HumanSurvey API key', a specific verb+resource. Sibling tools are about surveys, so this tool is distinct.

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 says 'Call this before any other tool if HUMANSURVEY_API_KEY is not set', giving clear when-to-use context. Does not list alternatives, but siblings are unrelated.

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

create_surveyCreate SurveyA

Use this when an agent task involves collecting structured feedback or data from a group of people. Common cases: post-event attendee feedback, product satisfaction after a launch, team health checks, customer ratings after support resolution. The schema parameter is fully typed — follow the field types rather than guessing. Returns a survey_url to share with respondents and a survey_id to pass to get_results later. The survey accepts responses immediately and stays open until you close it or it expires. Embedding: append "?embed=1" to the returned survey_url to render inside an on any host site (onboarding/lead-capture flows). The embedded form posts events to window.parent with source: "humansurvey" — type "loaded", "resize" (with height), and "submitted" (with responseId and answers). See https://www.humansurvey.co/llms.txt for the full embed contract.

ParametersJSON Schema
NameRequiredDescriptionDefault
schemaYesSurvey definition. Each question is a discriminated union keyed by type: single_choice, multi_choice, text, scale, or matrix. Use the typed fields below — do not send free-form JSON.
max_responsesNoOptional. Close the survey automatically after this many responses.
expires_atNoOptional. ISO 8601 datetime — close the survey automatically at this time (e.g. "2026-04-14T00:00:00Z").
webhook_urlNoOptional. URL to POST to once when the survey closes. Payload: { survey_id, status: "closed", closed_reason: "manual" | "max_responses", response_count, closed_at }. Fires when you call close_survey or when max_responses is reached. Does not fire when expires_at elapses.

TDQS

A4.4/5.0
Behavior5/5

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

No annotations provided, so description carries full burden. Discloses that surveys accept responses immediately, remain open until closed or expired, and explains embed behavior (?embed=1) with window.parent events. Also notes webhook limitations (does not fire on expiration). This goes beyond basic expectations for a creation tool.

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?

Well-structured with clear front-loading: 'Use this when...' followed by examples, then schema guidance, then return values, then embed details. Each sentence serves a purpose. Slightly lengthy but not redundant; could be tightened without losing value.

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 no output schema, the description fully explains return values (survey_url, survey_id) and how to use them. Covers lifecycle (immediate acceptance, expiration, closing), embed functionality, and webhook behavior. This provides a complete mental model for the agent to invoke the tool correctly.

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

Parameters3/5

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

Schema coverage is 100% with detailed descriptions on each field, including nested objects and conditional logic (showIf). The description adds minor value: advises to follow field types and mentions returns (survey_url, survey_id). But the schema already explains parameters thoroughly, so the description adds little beyond baseline.

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?

Clearly states the tool's purpose: creating surveys for collecting structured feedback from groups. Provides specific examples like post-event feedback, product satisfaction, team health checks. The verb 'create' and resource 'survey' are unambiguous, and the description distinguishes it from sibling tools (close_survey, etc.) through context.

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 says when to use: 'when an agent task involves collecting structured feedback or data from a group of people.' Lists common use cases. However, it doesn't explicitly mention when not to use this tool or name alternatives (like using get_results for retrieving responses). The guidance is strong but lacks exclusions.

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

get_resultsGet ResultsA

Retrieve aggregated results for a survey. Shows survey status (open/closed), total response count, and per-question results: choice tallies with percentages, scale mean/median/distribution, and recent text responses. If the survey is still open, call again later to check for new responses — the output will tell you. Use close_survey when you have enough responses.

ParametersJSON Schema
NameRequiredDescriptionDefault
survey_idYesThe survey ID from the create_survey output (last segment of the survey_url, e.g. "abc123efgh45")

TDQS

A4.5/5.0
Behavior4/5

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

Discloses that the output indicates if survey is open and suggests re-calling. Since no annotations exist, the description compensates well, though it could explicitly state the tool is read-only.

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

Conciseness5/5

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

The description is concise, well-structured, and front-loaded with the core purpose. Every sentence adds value without waste.

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?

Despite no output schema, the description thoroughly covers the return content (status, counts, per-question details) and provides context for re-calling. Completeness is high for the tool's complexity.

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

Parameters3/5

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

Schema coverage is 100% with an already detailed description of survey_id. The description adds no extra meaning beyond the schema, so baseline 3 is appropriate.

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 specifies the verb 'retrieve' and resource 'aggregated results for a survey', listing specific output details (status, counts, per-question results). It clearly differentiates from siblings like close_survey.

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?

Explicitly advises to call again if survey is open and recommends using close_survey when enough responses are collected, providing clear when-to-use and alternatives.

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

list_surveysList SurveysA

List all surveys created with the current API key, ordered newest first. Use this to find a survey_id you need for get_results or close_survey, or to check which surveys are still open.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

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

Discloses ordering and scope (surveys with current API key) but no annotations exist. For a simple read-only list, this is sufficient; no destructive actions are implied.

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

Conciseness5/5

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

Two sentences, front-loaded with action, no waste. Efficient and clear.

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?

For a zero-parameter, no-output-schema tool, description covers purpose, ordering, and use cases. Complexity is low, and description is complete.

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

Parameters4/5

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

No parameters, so baseline 4 applies. Description adds no parameter info as none exist.

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?

Description clearly states the tool lists all surveys created with the current API key, ordered newest first, and distinguishes it from sibling tools like get_results and close_survey.

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 says when to use: to find a survey_id for get_results or close_survey, or check open surveys. Does not specify when not to use, but context is clear.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 2 tool updatesv0.1.2
    • Addedcreate_key
    • Changedcreate_survey5 fields changed
      • removedInput schema / properties / schema / additionalProperties
        Removed value: -{}
      • changedInput schema / properties / schema / description
        Previous value: -"Survey as a JSON schema object: { title: string, sections: [{ questions: [{ type, label, ...}] }] }. Question types: single_choice (needs options), multi_choice (needs options), text, scale (needs min/max, range ≤ 11), matrix (needs rows + columns). Add showIf: { questionId, operator: \"eq\"|\"neq\"|\"contains\"|\"answered\", value } to any question for conditional logic."New value: +"Survey definition. Each question is a discriminated union keyed by type: single_choice, multi_choice, text, scale, or matrix. Use the typed fields below — do not send free-form JSON."
      • addedInput schema / properties / schema / properties
        Added value: +{
        +  "description": {
        +    "description": "Optional intro text shown on the welcome screen.",
        +    "type": "string"
        +  },
        +  "sections": {
        +    "description": "Survey sections, each with questions. Use a single section for simple surveys.",
        +    "items": {
        +      "properties": {
        +        "description": {
        +          "description": "Optional section description.",
        +          "type": "string"
        +        },
        +        "questions": {
        +          "description": "Questions in this section.",
        +          "items": {
        +            "oneOf": [
        +              {
        +                "properties": {
        +                  "description": {
        +                    "description": "Optional helper text shown under the question label.",
        +                    "type": "string"
        +                  },
        +                  "label": {
        +                    "description": "Question text shown to the respondent.",
        +                    "type": "string"
        +                  },
        +                  "options": {
        +                    "description": "Options the respondent chooses exactly one of.",
        +                    "items": {
        +                      "properties": {
        +                        "hasTextInput": {
        +                          "description": "Set true for an \"Other: ___\" option that lets the respondent type a free-text value.",
        +                          "type": "boolean"
        +                        },
        +                        "label": {
        +                          "description": "Option text shown to the respondent.",
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "label"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "minItems": 1,
        +                    "type": "array"
        +                  },
        +                  "required": {
        +                    "description": "Whether an answer is required. Defaults to false.",
        +                    "type": "boolean"
        +                  },
        +                  "showIf": {
        +                    "description": "Only show this question if the condition on an earlier question is met.",
        +                    "properties": {
        +                      "operator": {
        +                        "description": "eq = referenced answer equals value; neq = not equal; contains = multi_choice selection includes value; answered = respondent gave any answer.",
        +                        "enum": [
        +                          "eq",
        +                          "neq",
        +                          "contains",
        +                          "answered"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "questionId": {
        +                        "description": "ID of the earlier question to check. IDs are assigned in order of appearance as q_0, q_1, q_2, ... across all sections. Must reference a question before the one where showIf is set.",
        +                        "type": "string"
        +                      },
        +                      "value": {
        +                        "description": "Option ID (opt_0, opt_1, ...) for eq/neq/contains — numbered per-question in option order. Omit for the answered operator.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "questionId",
        +                      "operator"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": {
        +                    "const": "single_choice",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "type",
        +                  "label",
        +                  "options"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "properties": {
        +                  "description": {
        +                    "description": "Optional helper text shown under the question label.",
        +                    "type": "string"
        +                  },
        +                  "label": {
        +                    "description": "Question text shown to the respondent.",
        +                    "type": "string"
        +                  },
        +                  "options": {
        +                    "description": "Options the respondent can pick one or more of.",
        +                    "items": {
        +                      "properties": {
        +                        "hasTextInput": {
        +                          "description": "Set true for an \"Other: ___\" option that lets the respondent type a free-text value.",
        +                          "type": "boolean"
        +                        },
        +                        "label": {
        +                          "description": "Option text shown to the respondent.",
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "label"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "minItems": 1,
        +                    "type": "array"
        +                  },
        +                  "required": {
        +                    "description": "Whether an answer is required. Defaults to false.",
        +                    "type": "boolean"
        +                  },
        +                  "showIf": {
        +                    "description": "Only show this question if the condition on an earlier question is met.",
        +                    "properties": {
        +                      "operator": {
        +                        "description": "eq = referenced answer equals value; neq = not equal; contains = multi_choice selection includes value; answered = respondent gave any answer.",
        +                        "enum": [
        +                          "eq",
        +                          "neq",
        +                          "contains",
        +                          "answered"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "questionId": {
        +                        "description": "ID of the earlier question to check. IDs are assigned in order of appearance as q_0, q_1, q_2, ... across all sections. Must reference a question before the one where showIf is set.",
        +                        "type": "string"
        +                      },
        +                      "value": {
        +                        "description": "Option ID (opt_0, opt_1, ...) for eq/neq/contains — numbered per-question in option order. Omit for the answered operator.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "questionId",
        +                      "operator"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": {
        +                    "const": "multi_choice",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "type",
        +                  "label",
        +                  "options"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "properties": {
        +                  "description": {
        +                    "description": "Optional helper text shown under the question label.",
        +                    "type": "string"
        +                  },
        +                  "label": {
        +                    "description": "Question text shown to the respondent.",
        +                    "type": "string"
        +                  },
        +                  "required": {
        +                    "description": "Whether an answer is required. Defaults to false.",
        +                    "type": "boolean"
        +                  },
        +                  "showIf": {
        +                    "description": "Only show this question if the condition on an earlier question is met.",
        +                    "properties": {
        +                      "operator": {
        +                        "description": "eq = referenced answer equals value; neq = not equal; contains = multi_choice selection includes value; answered = respondent gave any answer.",
        +                        "enum": [
        +                          "eq",
        +                          "neq",
        +                          "contains",
        +                          "answered"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "questionId": {
        +                        "description": "ID of the earlier question to check. IDs are assigned in order of appearance as q_0, q_1, q_2, ... across all sections. Must reference a question before the one where showIf is set.",
        +                        "type": "string"
        +                      },
        +                      "value": {
        +                        "description": "Option ID (opt_0, opt_1, ...) for eq/neq/contains — numbered per-question in option order. Omit for the answered operator.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "questionId",
        +                      "operator"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": {
        +                    "const": "text",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "type",
        +                  "label"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "properties": {
        +                  "description": {
        +                    "description": "Optional helper text shown under the question label.",
        +                    "type": "string"
        +                  },
        +                  "label": {
        +                    "description": "Question text shown to the respondent.",
        +                    "type": "string"
        +                  },
        +                  "max": {
        +                    "description": "Highest scale value. The range (max - min + 1) must be ≤ 11.",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "maxLabel": {
        +                    "description": "Label shown at the max end, e.g. \"Very likely\".",
        +                    "type": "string"
        +                  },
        +                  "min": {
        +                    "description": "Lowest scale value (usually 0 or 1).",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "minLabel": {
        +                    "description": "Label shown at the min end, e.g. \"Not likely\".",
        +                    "type": "string"
        +                  },
        +                  "required": {
        +                    "description": "Whether an answer is required. Defaults to false.",
        +                    "type": "boolean"
        +                  },
        +                  "showIf": {
        +                    "description": "Only show this question if the condition on an earlier question is met.",
        +                    "properties": {
        +                      "operator": {
        +                        "description": "eq = referenced answer equals value; neq = not equal; contains = multi_choice selection includes value; answered = respondent gave any answer.",
        +                        "enum": [
        +                          "eq",
        +                          "neq",
        +                          "contains",
        +                          "answered"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "questionId": {
        +                        "description": "ID of the earlier question to check. IDs are assigned in order of appearance as q_0, q_1, q_2, ... across all sections. Must reference a question before the one where showIf is set.",
        +                        "type": "string"
        +                      },
        +                      "value": {
        +                        "description": "Option ID (opt_0, opt_1, ...) for eq/neq/contains — numbered per-question in option order. Omit for the answered operator.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "questionId",
        +                      "operator"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": {
        +                    "const": "scale",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "type",
        +                  "label",
        +                  "min",
        +                  "max"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "properties": {
        +                  "columns": {
        +                    "description": "Columns of the matrix — each column defines the options used for every row.",
        +                    "items": {
        +                      "properties": {
        +                        "label": {
        +                          "description": "Column label.",
        +                          "type": "string"
        +                        },
        +                        "options": {
        +                          "description": "Options shown in each cell of this column. Every row uses the same column options.",
        +                          "items": {
        +                            "properties": {
        +                              "hasTextInput": {
        +                                "description": "Set true for an \"Other: ___\" option that lets the respondent type a free-text value.",
        +                                "type": "boolean"
        +                              },
        +                              "label": {
        +                                "description": "Option text shown to the respondent.",
        +                                "type": "string"
        +                              }
        +                            },
        +                            "required": [
        +                              "label"
        +                            ],
        +                            "type": "object"
        +                          },
        +                          "minItems": 1,
        +                          "type": "array"
        +                        }
        +                      },
        +                      "required": [
        +                        "label",
        +                        "options"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "minItems": 1,
        +                    "type": "array"
        +                  },
        +                  "description": {
        +                    "description": "Optional helper text shown under the question label.",
        +                    "type": "string"
        +                  },
        +                  "label": {
        +                    "description": "Question text shown to the respondent.",
        +                    "type": "string"
        +                  },
        +                  "required": {
        +                    "description": "Whether an answer is required. Defaults to false.",
        +                    "type": "boolean"
        +                  },
        +                  "rows": {
        +                    "description": "Rows of the matrix — usually items or criteria being evaluated.",
        +                    "items": {
        +                      "properties": {
        +                        "label": {
        +                          "description": "Row label — usually an item or criterion being evaluated.",
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "label"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "minItems": 1,
        +                    "type": "array"
        +                  },
        +                  "showIf": {
        +                    "description": "Only show this question if the condition on an earlier question is met.",
        +                    "properties": {
        +                      "operator": {
        +                        "description": "eq = referenced answer equals value; neq = not equal; contains = multi_choice selection includes value; answered = respondent gave any answer.",
        +                        "enum": [
        +                          "eq",
        +                          "neq",
        +                          "contains",
        +                          "answered"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "questionId": {
        +                        "description": "ID of the earlier question to check. IDs are assigned in order of appearance as q_0, q_1, q_2, ... across all sections. Must reference a question before the one where showIf is set.",
        +                        "type": "string"
        +                      },
        +                      "value": {
        +                        "description": "Option ID (opt_0, opt_1, ...) for eq/neq/contains — numbered per-question in option order. Omit for the answered operator.",
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "questionId",
        +                      "operator"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": {
        +                    "const": "matrix",
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "type",
        +                  "label",
        +                  "rows",
        +                  "columns"
        +                ],
        +                "type": "object"
        +              }
        +            ]
        +          },
        +          "minItems": 1,
        +          "type": "array"
        +        },
        +        "title": {
        +          "description": "Optional section heading.",
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "questions"
        +      ],
        +      "type": "object"
        +    },
        +    "minItems": 1,
        +    "type": "array"
        +  },
        +  "title": {
        +    "description": "Survey title shown to respondents on the welcome screen.",
        +    "type": "string"
        +  }
        +}
      • removedInput schema / properties / schema / propertyNames
        Removed value: -{
        -  "type": "string"
        -}
      • addedInput schema / properties / schema / required
        Added value: +[
        +  "title",
        +  "sections"
        +]
  2. 4 tool updatesv0.1.0
    • First observedclose_survey
    • First observedcreate_survey
    • First observedget_results
    • First observedlist_surveys

TDQS

A4.4/5.0
Disambiguation5/5

Each tool has a distinct, non-overlapping purpose: creating API keys, creating surveys, listing surveys, retrieving results, and closing surveys. No ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (create_key, create_survey, list_surveys, get_results, close_survey), making them predictable and easy to distinguish.

Tool Count5/5

With 5 tools, the server is well-scoped for managing surveys. Each tool serves a necessary function without unnecessary bloat, fitting within the ideal range of 3-15 tools.

Completeness3/5

Covers core survey lifecycle (create, list, results, close) but lacks update and delete operations. While re-opening is possible via API, it's not exposed as a tool, creating a notable gap.

Maintenance

ActivitySlowing
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Collects user feedback with text and image support through an Electron app, allowing AI tools to gather and process user input with customizable prompts and multiple response options.
    1
    9
    2
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to recruit real humans for evaluation tasks like surveys, A/B tests, and ratings on text, images, audio, and video, returning aggregated results directly into the conversation.
    13
    7
    MIT
  • F
    license
    A
    quality
    B
    maintenance
    Interactive feedback server for AI-assisted development with Web UI and desktop app support, enabling user feedback collection after AI tasks.
    2
    -

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sunsiyuan/human-survey'

If you have feedback or need assistance with the MCP directory API, please join our Discord server