{"schema_version":"mcp-tools/v1","name":"touchstone","tools":[{"name":"order_test","description":"Order a human test of your app or site on Touchstone.\n\n    artifact_url: a public URL, or an artifact:// reference from upload_artifact.\n    artifact_type: web_url | apk_url | testflight.\n    niche: mobile_game | mobile_app | web_app | web_game | landing_page | ecommerce | other.\n    test_type: exploratory | scripted | ux_survey | gameplay.\n    budget_cents: per-tester payout in integer cents of your account currency\n    (no floats), charged per accepted tester up to max_testers. Capped at 5000\n    cents ($50) or 500000 kopecks (₽5 000) per tester; max_testers ≤ 5.\n    ends_at: ISO-8601 hard deadline for testing — required; testers see it and\n    unfinished assignments lapse at that moment. starts_at: optional ISO-8601;\n    defaults to the creation moment. credentials: optional login details for\n    the app under test, visible to testers.\n\n    Returns the created task JSON. Poll get_report(task_id) for the verdict.\n    ","inputSchema":{"properties":{"artifact_url":{"title":"Artifact Url","type":"string"},"artifact_type":{"title":"Artifact Type","type":"string"},"niche":{"title":"Niche","type":"string"},"test_type":{"title":"Test Type","type":"string"},"budget_cents":{"title":"Budget Cents","type":"integer"},"ends_at":{"title":"Ends At","type":"string"},"scenario_steps":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"default":null,"title":"Scenario Steps"},"survey_questions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"default":null,"title":"Survey Questions"},"focus_areas":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"default":null,"title":"Focus Areas"},"credentials":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Credentials"},"max_testers":{"default":1,"title":"Max Testers","type":"integer"},"starts_at":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Starts At"}},"required":["artifact_url","artifact_type","niche","test_type","budget_cents","ends_at"],"title":"order_testArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"order_testDictOutput","type":"object"}},{"name":"upload_artifact","description":"Upload a build (APK, web bundle) for use as order_test's artifact_url.\n\n    Over stdio the server shares your filesystem: it reads file_path, uploads\n    the bytes, and returns the artifact://<key> reference directly.\n\n    Over the remote HTTP endpoint the server cannot read your disk, so instead\n    it returns a presigned upload URL plus a ready-to-run curl command — run it\n    with your local shell tool, then pass the artifact:// reference to\n    order_test.\n    ","inputSchema":{"properties":{"file_path":{"title":"File Path","type":"string"}},"required":["file_path"],"title":"upload_artifactArguments","type":"object"},"outputSchema":{"properties":{"result":{"title":"Result","type":"string"}},"required":["result"],"title":"upload_artifactOutput","type":"object"}},{"name":"list_tasks","description":"List your test tasks, newest first, as a {tasks, count} envelope.\n\n    status: optional filter bucket — created | in_progress | done\n    (done = paid + rejected + done). Omit to list everything.\n\n    The result is a single JSON object: clients that read only the first\n    content item still see every task.\n    ","inputSchema":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Status"}},"title":"list_tasksArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"list_tasksDictOutput","type":"object"}},{"name":"get_report","description":"Fetch a task and its tester reports as a {task, reports} envelope.\n\n    Poll this after order_test. Each report carries bugs (severity, steps,\n    expected/actual), ux_findings, metrics, and a review status to act on with\n    approve_report / reject_report.\n    ","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"}},"required":["task_id"],"title":"get_reportArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_reportDictOutput","type":"object"}},{"name":"approve_report","description":"Approve a tester's report, releasing their payout.\n\n    note: optional feedback shown to the tester. Once every report on the task\n    is reviewed the task resolves to paid (≥1 approved) or rejected.\n    ","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"},"report_id":{"title":"Report Id","type":"string"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Note"}},"required":["task_id","report_id"],"title":"approve_reportArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"approve_reportDictOutput","type":"object"}},{"name":"reject_report","description":"Reject an inadequate report; the tester is not paid.\n\n    note is required — explain what is missing so the tester can improve.\n    ","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"},"report_id":{"title":"Report Id","type":"string"},"note":{"title":"Note","type":"string"}},"required":["task_id","report_id","note"],"title":"reject_reportArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"reject_reportDictOutput","type":"object"}},{"name":"mark_task_done","description":"Close a settled task (paid or rejected) after shipping the fixes.\n\n    Call this once you have applied the changes suggested by the approved\n    reports. fix_notes: what was improved — it becomes the task's audit trail\n    and is shown on the developer dashboard. The task must be paid or\n    rejected first; tasks still in testing return 409.\n    ","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"},"fix_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Fix Notes"}},"required":["task_id"],"title":"mark_task_doneArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"mark_task_doneDictOutput","type":"object"}},{"name":"get_balance","description":"Return your budget: balance_cents in your account currency (RUB for\n    Russian accounts, USD elsewhere), the currency, and recent top-ups.","inputSchema":{"properties":{},"title":"get_balanceArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_balanceDictOutput","type":"object"}},{"name":"topup_budget","description":"Top up the requester budget by amount_cents in your account currency.\n\n    The payment rail follows the account: Alfa Bank acquiring for RUB, Stripe\n    for USD. Until the corresponding credentials are configured on the server\n    the rail runs in stub mode and top-ups succeed instantly (form_url is\n    null — there is no checkout page to redirect to).\n    ","inputSchema":{"properties":{"amount_cents":{"title":"Amount Cents","type":"integer"}},"required":["amount_cents"],"title":"topup_budgetArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"topup_budgetDictOutput","type":"object"}},{"name":"quote_transfer","description":"Preview an own-wallet conversion between RUB and USD (integer cents).\n\n    Returns debit_cents, credit_cents, the CBR mid rate, and the platform\n    spread. Does not move money — call convert_balance to execute.","inputSchema":{"properties":{"from_currency":{"title":"From Currency","type":"string"},"to_currency":{"title":"To Currency","type":"string"},"amount_cents":{"title":"Amount Cents","type":"integer"}},"required":["from_currency","to_currency","amount_cents"],"title":"quote_transferArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"quote_transferDictOutput","type":"object"}},{"name":"convert_balance","description":"Convert amount_cents from one of your wallets to the other (RUB ↔ USD).\n\n    Quotes first, then executes at that credit so a mid-flight rate move\n    returns 409 rate_changed instead of filling at a worse price.","inputSchema":{"properties":{"from_currency":{"title":"From Currency","type":"string"},"to_currency":{"title":"To Currency","type":"string"},"amount_cents":{"title":"Amount Cents","type":"integer"}},"required":["from_currency","to_currency","amount_cents"],"title":"convert_balanceArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"convert_balanceDictOutput","type":"object"}},{"name":"cancel_task","description":"Cancel an open task (created or in_progress) and free its budget back\n    to your balance. Settled tasks (paid/rejected/done) return 409.","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"}},"required":["task_id"],"title":"cancel_taskArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"cancel_taskDictOutput","type":"object"}},{"name":"get_task","description":"Fetch one task's full detail: the task, its reports, and the tester\n    assignments (who accepted it).","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"}},"required":["task_id"],"title":"get_taskArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_taskDictOutput","type":"object"}},{"name":"get_artifact_url","description":"Return a short-lived download URL for the task's build artifact,\n    with the original filename and extension preserved.","inputSchema":{"properties":{"task_id":{"title":"Task Id","type":"string"}},"required":["task_id"],"title":"get_artifact_urlArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_artifact_urlDictOutput","type":"object"}},{"name":"get_profile","description":"Return your requester profile: name, email, and account currency.","inputSchema":{"properties":{},"title":"get_profileArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_profileDictOutput","type":"object"}},{"name":"switch_currency","description":"Switch the active account currency (RUB | USD).\n\n    Balances are separate per currency (like bank sub-accounts) — switching\n    never converts anything; it only changes which balance is active and\n    which rail top-ups use (Alfa for RUB, Stripe for USD).\n    ","inputSchema":{"properties":{"currency":{"title":"Currency","type":"string"}},"required":["currency"],"title":"switch_currencyArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"switch_currencyDictOutput","type":"object"}},{"name":"list_api_keys","description":"List your active (non-revoked) API keys as a {keys, count} envelope.\n    Raw keys are never returned — only ids, prefixes, labels, and dates.","inputSchema":{"properties":{},"title":"list_api_keysArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"list_api_keysDictOutput","type":"object"}},{"name":"create_api_key","description":"Issue a new API key (for another agent or CI job). The raw tst_… key\n    is returned ONCE — store it; the server keeps only its hash.","inputSchema":{"properties":{"label":{"title":"Label","type":"string"}},"required":["label"],"title":"create_api_keyArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"create_api_keyDictOutput","type":"object"}},{"name":"revoke_api_key","description":"Revoke an API key by id. The key stops working immediately.","inputSchema":{"properties":{"key_id":{"title":"Key Id","type":"string"}},"required":["key_id"],"title":"revoke_api_keyArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"revoke_api_keyDictOutput","type":"object"}},{"name":"list_notifications","description":"List your notifications (task status changes), newest first, as a\n    {notifications, count} envelope. At most 50 are returned.","inputSchema":{"properties":{},"title":"list_notificationsArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"list_notificationsDictOutput","type":"object"}},{"name":"get_unread_count","description":"Return how many unread notifications you have: {count}.","inputSchema":{"properties":{},"title":"get_unread_countArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_unread_countDictOutput","type":"object"}},{"name":"mark_all_notifications_read","description":"Mark every notification as read.","inputSchema":{"properties":{},"title":"mark_all_notifications_readArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"mark_all_notifications_readDictOutput","type":"object"}},{"name":"mark_notification_read","description":"Mark one notification as read by id.","inputSchema":{"properties":{"notification_id":{"title":"Notification Id","type":"string"}},"required":["notification_id"],"title":"mark_notification_readArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"mark_notification_readDictOutput","type":"object"}},{"name":"clear_notifications","description":"Delete ALL your notifications.","inputSchema":{"properties":{},"title":"clear_notificationsArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"clear_notificationsDictOutput","type":"object"}},{"name":"delete_notification","description":"Delete one notification by id.","inputSchema":{"properties":{"notification_id":{"title":"Notification Id","type":"string"}},"required":["notification_id"],"title":"delete_notificationArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"delete_notificationDictOutput","type":"object"}},{"name":"get_schema","description":"Fetch a versioned JSON Schema (name: task | report, version: v1) that\n    task instructions and report bodies are validated against.","inputSchema":{"properties":{"name":{"title":"Name","type":"string"},"version":{"title":"Version","type":"string"}},"required":["name","version"],"title":"get_schemaArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_schemaDictOutput","type":"object"}},{"name":"get_geo","description":"Return geo detection for the current request: country code and the\n    currency the platform would assign (RUB for Russia, USD elsewhere).","inputSchema":{"properties":{},"title":"get_geoArguments","type":"object"},"outputSchema":{"additionalProperties":true,"title":"get_geoDictOutput","type":"object"}}]}