Sign In

@getabrain/mcp-server

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@getabrain/mcp-server - npm Package Compare versions

Comparing version
0.1.5
to
0.2.0
+48
-25
dist/index.js

@@ -59,21 +59,42 @@ #!/usr/bin/env node

name: "get_balance",
description: "Get the prepaid balance (in cents) available to fund GetABrain queries.",
description: 'Check the prepaid balance (in cents) available to fund submit_query calls, plus account mode. Call before submit_query if unsure funds suffice, or whenever a query fails/stalls for balance reasons. Read-only, no side effects, free in test and live mode. Response includes mode ("test" = sandbox key, free simulated responses; "live" = real key, real spend), and when relevant whether auto_reload is on, plus an auto_reload_setup_url + hint to enable it so a live account does not stall at zero balance. Disambiguation: reports funds available to spend; does not list queries (list_queries) or responses (get_responses/wait_for_responses).',
inputShape: {},
run: async (_args, client) => {
const b = await client.account.balance();
return ok({ balance_cents: b.balance_cents, company_name: b.company_name });
return ok({
balance_cents: b.balance_cents,
company_name: b.company_name,
...b.mode !== void 0 ? { mode: b.mode } : {},
...b.auto_reload_enabled !== void 0 ? { auto_reload_enabled: b.auto_reload_enabled } : {},
...b.auto_reload_setup_url !== void 0 ? { auto_reload_setup_url: b.auto_reload_setup_url } : {},
...b.hint !== void 0 ? { hint: b.hint } : {}
});
}
},
{
name: "create_topup_link",
description: "Generate a one-time Stripe Checkout URL for adding funds to the prepaid balance. Use when get_balance shows insufficient funds for an upcoming submit_query, or a human asks to add money. Side effect: creates a pending Stripe session (no charge yet); the returned checkout_url must be OPENED IN A BROWSER BY A HUMAN to enter payment details and complete the charge -- the agent cannot complete payment itself; this is an out-of-band, human-in-the-loop step. Works with a test-mode or live-mode key (funding a test-mode account is how you move a sandbox integration to real spending power). Balance updates only after checkout completes; poll get_balance to confirm. Disambiguation: only mints a payment link -- never moves money or blocks waiting for payment itself.",
inputShape: {
amount_cents: z.number().int().min(500).max(1e7).describe(
"Amount to add to the prepaid balance, in whole cents (min 500 = $5.00, max 10000000 = $100,000.00). E.g. 5000 = $50.00."
)
},
run: async (args, client) => ok(await client.account.createTopupLink(args.amount_cents))
},
{
name: "submit_query",
description: `Ask a human / add a human in the loop: submit a human-judgment query to real human workers and get its id back. Use this for any human-in-the-loop (HITL) step, human approval, or when your model needs a real human opinion. "type" is one of: ${QUERY_TYPES.join(", ")}. "content_data" is the type-specific payload (e.g. ab_test: {question, variant_a:{description}, variant_b:{description}}; yes_no: {question}; rating_scale: {question, scale_type, scale_min, scale_max}). Cost = (bid_amount_cents + bonus_amount_cents) * required_responses, deducted from your balance.`,
description: `Submit a structured question to real human workers, returning a query_id -- the entry point for any human-in-the-loop (HITL) step: judgment calls, subjective evaluation, approval/review, or "ask a real person" tasks a model should not answer itself. "type" selects the question format (one of: ${QUERY_TYPES.join(", ")}); "content_data" is the matching type-specific payload (e.g. ab_test: {question, variant_a:{description}, variant_b:{description}}; yes_no: {question}; rating_scale: {question, scale_type, scale_min, scale_max}). Cost/side effects: with a LIVE key this deducts (bid_amount_cents + bonus_amount_cents) * required_responses from balance immediately and dispatches to paid workers (fails if balance too low -- check get_balance or use create_topup_link). With a TEST key, no balance is touched and responses are synthetic, marked simulated: true, so you can build/test a full pipeline for free before going live. Returns immediately, does not wait -- use get_responses (one-shot) or wait_for_responses (bounded polling) to retrieve answers.`,
inputShape: {
type: z.enum(QUERY_TYPES),
title: z.string().min(5).max(255),
content_data: z.record(z.any()),
required_responses: z.number().int().min(1).max(1e3),
bid_amount_cents: z.number().int().min(5).max(1e7),
description: z.string().optional(),
bonus_amount_cents: z.number().int().min(0).optional(),
min_worker_quality: z.number().min(0).max(5).optional()
type: z.enum(QUERY_TYPES).describe(`Question format/template. One of: ${QUERY_TYPES.join(", ")}. Determines the required shape of content_data.`),
title: z.string().min(5).max(255).describe("Short human-readable title for the query, shown to workers as the task headline (5-255 characters)."),
content_data: z.record(z.any()).describe(
'Type-specific payload whose required fields depend on "type" (e.g. {question, variant_a, variant_b} for ab_test; {question} for yes_no; {question, scale_type, scale_min, scale_max} for rating_scale). See the API docs for the full schema per type.'
),
required_responses: z.number().int().min(1).max(1e3).describe("Number of distinct human worker responses to collect before the query is considered complete (1-1000)."),
bid_amount_cents: z.number().int().min(5).max(1e7).describe(
"Cents paid to EACH worker per accepted response (min 5 = $0.05, max 10000000 = $100,000.00). Total cost = (bid_amount_cents + bonus_amount_cents) * required_responses, deducted from balance in live mode. No charge occurs in test mode."
),
description: z.string().optional().describe("Optional longer explanation/context shown to workers alongside the title, for extra instructions or background."),
bonus_amount_cents: z.number().int().min(0).optional().describe("Optional extra cents paid to EACH worker on top of bid_amount_cents per accepted response (default 0). Included in the total cost calculation."),
min_worker_quality: z.number().min(0).max(5).optional().describe("Optional minimum worker quality score (0-5) required to accept this query; higher restricts to more experienced/reliable workers.")
},

@@ -84,4 +105,6 @@ run: async (args, client) => ok(await client.queries.create(args))

name: "get_responses",
description: "Get a query and the human responses submitted so far.",
inputShape: { query_id: z.string() },
description: `One-shot read: fetch a query's current status and whatever human responses have been submitted so far, without waiting. Use this to check progress on demand, or after wait_for_responses reports "pending" if you want an immediate snapshot instead of polling again. Read-only, no cost, returns instantly (does not block or retry). Disambiguation: unlike wait_for_responses, this never delays or blocks waiting for more answers to arrive -- it just reports what exists right now, which may be fewer than required_responses.`,
inputShape: {
query_id: z.string().describe("The id returned by submit_query, identifying which query to read.")
},
run: async (args, client) => {

@@ -99,7 +122,7 @@ const q = await client.queries.get(args.query_id);

name: "wait_for_responses",
description: 'Poll for up to max_wait_seconds (default 50) for human responses to a query. Returns status "ready" with the responses if enough arrived, otherwise status "pending" \u2014 call again to keep waiting.',
description: 'Poll for human responses to a query, blocking for up to max_wait_seconds (default 50, max 50) before returning. Use right after submit_query to wait for real answers in one call instead of manually re-checking with get_responses. DOES NOT GUARANTEE COMPLETION -- if min_responses have not arrived within the time budget it returns status "pending" (with a hint to call again) rather than erroring; call again to keep waiting. Returns status "ready" with the responses array once enough have arrived (or the query otherwise completed). Read-only / free -- cost was already charged by submit_query. Disambiguation: unlike get_responses (instant, one-shot, may return 0 responses), this actively waits, trading time for a higher chance of a complete result.',
inputShape: {
query_id: z.string(),
min_responses: z.number().int().min(1).optional(),
max_wait_seconds: z.number().int().min(1).max(50).optional()
query_id: z.string().describe("The id returned by submit_query, identifying which query to wait on."),
min_responses: z.number().int().min(1).optional().describe(`How many responses must arrive before returning status "ready" (default: the query's required_responses).`),
max_wait_seconds: z.number().int().min(1).max(50).optional().describe('Maximum seconds to poll before giving up and returning status "pending" if not enough responses arrived yet (default 50, max 50).')
},

@@ -133,6 +156,6 @@ run: async (args, client) => {

name: "list_queries",
description: "List your recent GetABrain queries (most recent first).",
description: 'List your recent GetABrain queries, most recent first. Use this to get an overview of past/active queries, recover a query_id you lost track of, or filter by status (e.g. find everything still "active" or "pending"). Read-only, no cost. Disambiguation: this lists MANY queries at a summary level; it does not return the individual worker responses for any one query -- use get_responses or wait_for_responses with a specific query_id for that.',
inputShape: {
status: z.string().optional(),
limit: z.number().int().min(1).max(100).optional()
status: z.string().optional().describe('Optional filter to only return queries in this status (e.g. "active", "pending", "completed", "cancelled", "failed", "expired"). Omit to return all statuses.'),
limit: z.number().int().min(1).max(100).optional().describe("Maximum number of queries to return, most recent first (1-100, default server-side).")
},

@@ -143,8 +166,8 @@ run: async (args, client) => ok(await client.queries.list(args))

name: "rate_response",
description: "Rate a worker's response 1-5 (feeds the quality system). Optionally include feedback_text.",
description: "Rate a single worker's response 1-5 to feed the worker quality/reputation system, optionally with free-text feedback. Use after reviewing a response from get_responses/wait_for_responses, to reward good answers and flag poor ones -- this affects the worker's quality score and future eligibility (e.g. queries with min_worker_quality set) and can trigger rewards/suspension server-side. Side effect: writes a rating record and returns the updated worker quality score; does not resubmit or modify the original response. Disambiguation: rates a response you already have -- does not fetch new responses (use get_responses/wait_for_responses first).",
inputShape: {
query_id: z.string(),
response_id: z.string(),
score: z.number().int().min(1).max(5),
feedback_text: z.string().optional()
query_id: z.string().describe("The id of the query the response belongs to (from submit_query)."),
response_id: z.string().describe("The id of the specific response to rate (from get_responses/wait_for_responses output)."),
score: z.number().int().min(1).max(5).describe("Quality rating for the response, 1 (worst) to 5 (best). Feeds the worker's ongoing quality score."),
feedback_text: z.string().optional().describe("Optional free-text comment explaining the rating, visible to the worker.")
},

@@ -151,0 +174,0 @@ run: async (args, client) => ok(await client.responses.rate(args.query_id, args.response_id, { score: args.score, feedback_text: args.feedback_text }))

{
"name": "@getabrain/mcp-server",
"version": "0.1.5",
"version": "0.2.0",
"description": "MCP server for GetABrain.ai \u2014 real human judgment as agent tools",

@@ -22,3 +22,3 @@ "type": "module",

"dependencies": {
"@getabrain/sdk": "^0.1.1",
"@getabrain/sdk": "^0.2.0",
"@modelcontextprotocol/sdk": "^1.18.0",

@@ -34,4 +34,5 @@ "zod": "^3.25.0"

"type": "git",
"url": "https://github.com/Guitarmaniac24/Getabrain.ai"
}
"url": "https://github.com/Guitarmaniac24/getabrain-mcp-server"
},
"homepage": "https://getabrain.ai"
}

@@ -26,17 +26,47 @@ # @getabrain/mcp-server

## Test mode
Test mode is a flag on the key, not a different key format. When you mint an API key — via
`POST /api/v1/requestor/keys` with `{"mode":"test"}`, or by choosing "test" in the dashboard — you get
back a completely normal `gab_k_…` / `gab_s_…` key pair. There's no `_test_` in the string; the
test-ness lives in the database as an `is_test` flag on that key. No funding or card required.
Point `GETABRAIN_API_KEY` / `GETABRAIN_API_SECRET` at a test-mode key and the server behaves identically, except:
- `submit_query` never touches your balance — no charge, no `insufficient_balance` errors.
- Responses come back synthetic and are always marked **`simulated: true`**, so your pipeline (submit →
wait/poll → rate) can be built and exercised end-to-end before any real human worker or real money is
involved.
- `get_balance` reports `mode: "test"` so the agent/human can tell at a glance which environment it's in.
When you're ready to go live: mint a **live-mode key** (same call, `{"mode":"live"}` or the dashboard
default), fund the account with `create_topup_link` (works with either key type — a test-mode agent can
generate the link, a human completes checkout to add real funds), and swap the env vars. `get_balance`
then reports `mode: "live"`, and `submit_query` starts spending real balance and dispatching to real paid
workers.
## Tools
- `get_balance` — check your prepaid balance.
- `submit_query` — ask real humans a question (16 query types: A/B test, rating, ranking, sentiment, yes/no, image/video/audio review, voice/video/photo capture, …). Returns a `query_id`.
- `get_responses` — fetch the human answers for a query.
- `wait_for_responses` — poll (bounded) until enough humans answer; call again while it returns `pending`.
- `list_queries` — your recent queries.
- `rate_response` — rate a worker's answer 1–5.
- `get_balance` — read-only: prepaid balance (cents), `mode` (`"test"`/`"live"`), and `auto_reload_enabled`
(with a setup link + hint when it's off and would otherwise stall a live account at zero balance).
- `create_topup_link` — mints a Stripe Checkout URL to add funds (min $5); a human opens it in a browser to
pay — the agent cannot complete payment itself.
- `submit_query` — ask real humans a question (16 query types: A/B test, rating, ranking, sentiment, yes/no,
image/video/audio review, voice/video/photo capture, …). Returns a `query_id`. Spends balance on a live
key; free and `simulated: true` on a test key.
- `get_responses` — one-shot, read-only: current status + whatever responses exist right now, no waiting.
- `wait_for_responses` — bounded polling (up to `max_wait_seconds`, default/max 50s); returns `ready` with
responses once enough arrive, or `pending` — call again to keep waiting. Use this instead of `get_responses`
when you want the tool call itself to wait.
- `list_queries` — read-only: your recent queries, optionally filtered by `status`.
- `rate_response` — rate a worker's answer 1–5 (optional `feedback_text`); feeds the worker quality system.
## Example agent flow
1. `get_balance` → ensure funds.
2. `submit_query` → get `query_id`.
3. `wait_for_responses` (repeat while `pending`) → read the human answers.
1. `get_balance` → confirm funds (or `mode: "test"` for a free sandbox run).
2. If funds are short on a live key: `create_topup_link` → human completes checkout → `get_balance` again.
3. `submit_query` → get `query_id`.
4. `wait_for_responses` (repeat while `pending`) → read the human (or simulated, in test mode) answers.
5. `rate_response` → optionally rate each response to improve future worker matching.
Full API docs: https://getabrain.ai/docs/api