Skip to main content
Glama

horizOn MCP Server

npm version npm downloads License: MIT

MCP server for horizOn Backend-as-a-Service

Gives AI coding assistants documentation, live API tools, and workflow prompts for game and app development.


Quick Install

Add to your MCP client configuration (Claude Desktop, Cursor, etc.):

{
  "mcpServers": {
    "horizOn": {
      "command": "npx",
      "args": ["-y", "horizon-mcp"],
      "env": {
        "HORIZON_API_KEY": "your-api-key-here"
      }
    }
  }
}

Related MCP server: Godot MCP

Features

Resources (18 docs)

Documentation resources are served directly from the MCP server. No API key required.

URI

Description

horizon://overview

What is horizOn, core concepts (Account vs User), features, tier system, API structure, and SDKs

horizon://docs/auth

Authentication methods (Anonymous, Email, Google), endpoints, SDK code examples, and common errors

horizon://docs/leaderboard

Leaderboard score submission, top entries, user rank, entries around user, player profile per entry, validated only boards, with SDK examples

horizon://docs/cloud-save

Cloud save/load for JSON and binary data, tier size limits, SDK examples

horizon://docs/remote-config

Server-side key-value configuration: feature flags, game balance, A/B testing. SDK examples

horizon://docs/localization

Server-side localized strings across 15 languages: per-key translations, single/all fetch, available languages. SDK examples

horizon://docs/news

In-game news and announcements with language filtering. SDK examples

horizon://docs/gift-codes

Gift code validation and redemption for promotional rewards, including cosmetic unlocks via grants. SDK examples

horizon://docs/player-profile

Player avatar, frame and badges from a per-project cosmetics catalog, unlocks via gift code grants, profile in leaderboard entries. SDK examples

horizon://docs/validated-actions

Server-checked runs: single-use run tickets with a server seed, SHA-256 input log hash, server-only rules, validated only leaderboards, server-owned player state, start context, evidence upload, admin evidence review with sus packages and package export, rejection codes. SDK examples

horizon://docs/feedback

Bug reports, feature requests, and general feedback submission. SDK examples

horizon://docs/user-logs

Server-side event and error tracking. Requires BASIC tier or higher. SDK examples

horizon://docs/crash-reporting

Crash report submission, session tracking, fingerprinting, breadcrumbs, and auto-regression detection. SDK examples

horizon://docs/email-sending

Transactional and event-based email delivery to registered users. Templates, scheduling, status tracking, and SMTP integration. SDK examples

horizon://api/reference

Complete API reference for all horizOn App API endpoints with request/response schemas

horizon://quickstart/godot

Step-by-step guide to integrate horizOn in Godot with GDScript examples

horizon://quickstart/unity

Step-by-step guide to integrate horizOn in Unity with C# examples

horizon://quickstart/unreal

Step-by-step guide to integrate horizOn in Unreal Engine 5.5+ with the official horizOn SDK plugin. C++ and Blueprint examples

Tools (34 tools)

Live API tools that call the horizOn backend. Requires a valid API key.

horizon_submit_score, horizon_save_cloud_data, horizon_load_cloud_data, horizon_redeem_gift_code, horizon_get_profile, horizon_set_profile, horizon_start_run, horizon_submit_validated, horizon_get_state and horizon_upload_evidence also need the player's session: sign in first and pass the returned accessToken as sessionToken.

Every tool declares MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so clients can tell reads from writes. Destructive tools are horizon_save_cloud_data (replaces the save), horizon_set_profile (replaces the whole profile), horizon_submit_validated (consumes the ticket, can spend balances) and horizon_cancel_email. The read tools that return an object also declare an outputSchema and return structuredContent next to the JSON text. Each description names when to use the tool, which sibling to use instead, what it returns and how to recover from its errors.

Tool

Description

horizon_test_connection

Test connection to the horizOn API (health check)

horizon_signup_anonymous

Create a new anonymous user account

horizon_signup_email

Create a new user account with email and password

horizon_signin_email

Sign in with email and password

horizon_signin_anonymous

Sign in with an anonymous token

horizon_check_auth

Check whether a user session is still valid

horizon_list_leaderboards

List available leaderboard boards for multi-board calls

horizon_submit_score

Submit a score to the leaderboard (403 VALIDATED_SUBMIT_REQUIRED on validated only boards)

horizon_get_leaderboard_top

Get the top leaderboard entries with each player's profile, optionally by board key

horizon_get_user_rank

Get a user's leaderboard rank, optionally by board key

horizon_get_leaderboard_around

Get leaderboard entries around a user's position, optionally by board key

horizon_save_cloud_data

Save cloud data for a user, optionally only at an expectedRevision (409 on conflict)

horizon_load_cloud_data

Load cloud save data for a user, with its revision

horizon_get_remote_config

Get a single remote config value by key

horizon_get_all_remote_configs

Get all remote config values

horizon_get_localization

Get a single localized string by key, optionally for a specific language

horizon_get_all_localizations

Get all localized strings, optionally for a specific language

horizon_get_localization_languages

List the languages that have localizations for the app

horizon_get_news

Get news articles with optional language filtering

horizon_validate_gift_code

Validate a gift code without redeeming it

horizon_redeem_gift_code

Redeem a gift code for a user (returns grantedUnlocks for codes with cosmetic grants)

horizon_get_profile

Get a player's profile (avatar, frame, badges), unlocks and the cosmetics catalog

horizon_set_profile

Replace a player's whole profile (avatar, frame, up to 3 badges)

horizon_start_run

Start a server-checked run: single-use ticket with a server seed, optionally bound to a board and with a start context (game, content, simulation and replay format versions, content digest, initial state as base64)

horizon_submit_validated

Submit a run result with the ticket and the SHA-256 input log hash (given, or computed locally from base64 bytes or text), optionally with earned server-owned values; returns sus (accepted but over a soft threshold); rejections name their code

horizon_get_state

Read the player's server-owned values (balance, earned today, daily cap per value key); read only

horizon_upload_evidence

Upload the input log (text or base64, encoded locally) of a run whose submit result asked for evidence; rejections name their code

horizon_submit_feedback

Submit user feedback (bug reports, feature requests)

horizon_create_log

Create a server-side log entry (INFO, WARN, ERROR)

horizon_create_crash_report

Submit a crash report (grouped by fingerprint, with regression detection)

horizon_create_crash_session

Register a game session for the crash-free rate

horizon_send_email

Send a transactional email to a registered user from a template

horizon_cancel_email

Cancel a pending or scheduled email

horizon_get_email_status

Get the status of a sent or scheduled email

Prompts (4 prompts)

Workflow prompts that guide AI assistants through common horizOn tasks.

Prompt

Description

integrate-feature

Generate integration code for a specific horizOn feature in your game engine

setup-auth

Step-by-step guide to set up horizOn authentication in your project

debug-connection

Diagnose and fix horizOn connection issues

explain-feature

Get a detailed explanation of any horizOn feature

Configuration

Variable

Required

Description

HORIZON_API_KEY

Yes (for tools)

Your horizOn API key. Get one at horizon.pm

HORIZON_BASE_URL

No

API base URL. Defaults to https://horizon.pm

Resources (documentation) work without an API key. Only the live API tools require authentication.

Admin Tools (v1.2+)

With an Account Key (creatable in your horizOn Dashboard -> API Keys -> Create -> Account Key), the MCP server exposes additional tools that let Claude manage your dashboard -- projects, remote config, news, email templates, gift codes, users, leaderboards, cloud-save data, crash reports, feedback, user logs, SMTP, and Validated Actions (rules, runs, player values and the evidence review).

How to get your Account Key

  1. Log in to your horizOn Dashboard

  2. Navigate to API Keys in the sidebar

  3. Click Create API Key

  4. Select Account Key as the key type

  5. Choose whether the key can access the entire account, a single Project API Key, or selected feature groups

  6. Click Create -- your key will be shown once. Copy it immediately.

  7. Add the key to your MCP configuration (see Setup below)

Setup

Add both keys to your MCP client configuration:

{
  "mcpServers": {
    "horizOn": {
      "command": "npx",
      "args": ["-y", "horizon-mcp"],
      "env": {
        "HORIZON_API_KEY": "your-project-key (for player-facing tools)",
        "HORIZON_ACCOUNT_API_KEY": "your-account-key (for dashboard tools)"
      }
    }
  }
}

Both can be set together or individually. Admin tools only register when the account key is set -- otherwise the server exposes only the original player-facing tools.

Scope

Account Keys inherit your account's tier (FREE/BASIC/PRO/ENTERPRISE) -- they grant no extra privileges. A key can be full-account, limited to a single Project API Key, limited to selected feature groups, or both. Platform-admin-only endpoints (Blog, Banner, System-Config) are automatically unreachable. A handful of ultra-sensitive endpoints (account deletion, credentials change, key management itself, subscription cancel) require a dashboard session and cannot be called via an Account Key.

When a key is project-scoped, the backend enforces that scope on direct HTTP calls too. Account-wide endpoints or ID-only endpoints that cannot prove project context are rejected for project-scoped keys.

Tool Groups

Admin tools carry the same annotations as the player tools: list, get and statistics tools are read only, update and delete tools are marked destructive.

Prefix

Description

horizon_admin_projects_*

Project API key management (create/update/regenerate/revoke/delete)

horizon_admin_remoteconfig_*

Remote config CRUD

horizon_admin_news_*

Multilingual news (titles/messages as {lang: content})

horizon_admin_emailtemplates_*

Multilingual email templates with variables

horizon_admin_giftcodes_*

Gift code CRUD + revoke

horizon_admin_users_*

User management + statistics (no full-list needed)

horizon_admin_leaderboard_*

Leaderboard entries + statistics

horizon_admin_cloudsave_*

Cloud save data + statistics

horizon_admin_crashes_*

Crash groups, reports, statistics

horizon_admin_feedback_*

Read user feedback

horizon_admin_userlogs_*

Read user logs

horizon_admin_smtp_*

Account SMTP configuration (password always returned masked)

horizon_admin_validated_evidence_*

Validated Actions evidence review: list (top N records or, with sus: true, sus packages), quota, metadata (with susPackage), log download (base64 or hashes only), package export (ZIP written to a local file, with the integrity headers), delete

horizon_admin_validated_rules_*, _usage_get, _runs_list, _state_*

Validated Actions configuration: rule set per Project API key (get, replace, delete), run capacity of the hour, recent runs with rejection codes (filter sus), server-owned player values (read, support correction)

What is horizOn?

horizOn is a multi-tenant Backend-as-a-Service platform built for game and app developers. It provides a managed backend so developers can focus on building their game or app instead of server infrastructure.

Core features:

  • Authentication (Anonymous, Email, Google, Apple)

  • Leaderboards

  • Cloud Save

  • Remote Config

  • Localization

  • News and Announcements

  • Gift Codes

  • Player Profile (avatar, frame, badges)

  • Validated Actions (server-checked runs, validated only leaderboards, server-owned currency)

  • User Feedback

  • User Logs

  • Crash Reporting

  • Email Sending

Learn more at horizon.pm. Install this MCP server via npm.

Supported Engines

  • Godot 4.5+ -- GDScript SDK

  • Unity 6 -- C# SDK

  • Unreal Engine 5.5+ -- C++ and Blueprint SDK

Development

# Clone the repository
git clone https://github.com/ProjectMakersDE/horizOn-mcp.git
cd horizOn-mcp

# Install dependencies
npm install

# Start the server (development mode)
npm run dev

# Build for production
npm run build

# Run tests
npm test

License

MIT

Available Tools

34 tools
horizon_cancel_emailCancel EmailA
DestructiveIdempotent

Cancels a queued email that is still pending (sent now or scheduled) so it is never delivered. Use when: a scheduled email is no longer wanted, for example the player already came back. Not for: emails that are already processing or sent (they cannot be recalled); check with horizon_get_email_status first when unsure. Requires: the emailId from horizon_send_email, sent with the same API key. Side effects: the email is never sent and cannot be restored; to send it later, call horizon_send_email again. Returns: {message: 'Email cancelled'}. Errors: An email that is not pending (already processing, sent, failed or cancelled) or belongs to another API key is rejected: read its state with horizon_get_email_status. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
emailIdYesEmail ID (UUID) returned by horizon_send_email

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds substantial value beyond them: irreversibility ('cannot be restored'), the same-API-key constraint, required HORIZON_API_KEY, error semantics (isError with HTTP status/body), and specific 401/429 meanings including rate limiting. This is rich behavioral context layered on top of the structured hints.

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 front-loaded with a labeled Use when / Not for / Requires / Side effects / Returns / Errors structure that scans cleanly. Slightly verbose: horizon_get_email_status and HORIZON_API_KEY are each referenced twice, and the error paragraph is dense, costing some tightness.

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?

With no output schema, the description supplies the return value ({message: 'Email cancelled'}), error behavior, prerequisites, and side effects. An agent has everything needed to call it correctly and interpret results.

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?

Schema coverage is 100% and documents emailId, so the baseline is 3. The description adds useful provenance — the emailId comes from horizon_send_email and must be sent with the same API key — which meaningfully constrains correct invocation beyond the schema text.

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?

States a precise verb and resource ('cancels a queued email') plus the crucial scope qualifier ('still pending... so it is never delivered'). This clearly distinguishes it from horizon_send_email and horizon_get_email_status among the large sibling set.

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?

Explicit 'Use when' (scheduled email no longer wanted), 'Not for' (already processing/sent, cannot be recalled), and a named alternative ('check with horizon_get_email_status first when unsure'). The when/when-not routing is fully spelled out.

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

horizon_check_authCheck AuthenticationA
Idempotent

Checks whether a player's session token (accessToken) is still valid for the given user. Use when: before a session tool when the token may have expired, or when a game resumes, to decide whether the player must sign in again. Not for: testing the API key or base URL (use horizon_test_connection) or getting a new token (use horizon_signin_email or horizon_signin_anonymous). Requires: userId and the accessToken from horizon_signin_email or horizon_signin_anonymous. Side effects: a valid check refreshes the session's one hour idle timeout; nothing else changes. Returns: {userId, isAuthenticated, authStatus, message}. An invalid or expired token is not an HTTP error: isAuthenticated is false, so sign in again with horizon_signin_*. Errors: 400 for a malformed userId or token: pass the values from the sign-in result. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from the result of horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous (max 256 characters)

Output Schema

ParametersJSON Schema
NameRequiredDescription
userIdNo
messageNo
authStatusNo
isAuthenticatedNo

TDQS

A4.8/5.0
Behavior5/5

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

Annotations declare readOnlyHint=false and idempotentHint=true; the description supplies the reason — a valid check refreshes the one-hour idle timeout and nothing else changes — which is exactly the non-obvious behavior the hint implies. It further discloses that an invalid token is NOT an HTTP error (isAuthenticated=false), the API-key requirement, the 429 rate-limit meaning, and the isError contract on failures.

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?

Dense but well-labeled (Use when / Not for / Requires / Side effects / Returns / Errors) with the core purpose front-loaded. Slightly over-long: the recover-by-signing-in guidance appears twice (under Returns and implicitly under Not for), and the Returns detail overlaps the output schema.

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 two-parameter authenticated check, the description covers trigger, alternatives, prerequisites, side effects, success shape, and the full error taxonomy — more than enough even though an output schema already exists. Nothing an agent needs to call it correctly is missing.

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?

Schema coverage is 100%, so the schema already documents both parameters, but the description adds real meaning by naming the origin of each value (userId from signup/signin, token from horizon_signin_*) and explaining that a 400 means malformed input. Minor friction: the prose calls the token 'accessToken' while the schema property is 'sessionToken', resolving the synonym is left to the schema's own description.

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?

States a specific verb (checks) and resource (a player's session token validity for a userId) up front, and explicitly differentiates itself from siblings like horizon_test_connection and horizon_signin_*. An agent can identify the tool's role without opening the schema.

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?

Provides an explicit 'Use when' trigger (before session tools when a token may have expired, or on game resume) and an explicit 'Not for' with named alternatives for both excluded cases. Nothing about tool selection is left to inference.

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

horizon_create_crash_reportCreate Crash ReportA

Submits one crash (CRASH), caught exception (NON_FATAL) or freeze (ANR) with device data to horizOn Crash Reporting, grouped by fingerprint. Use when: the game crashed (send on next start) or caught an exception worth tracking. Not for: technical events without a crash (use horizon_create_log) and messages written by players (use horizon_submit_feedback). Requires: a sessionId registered with horizon_create_crash_session for this app run; userId is optional. Side effects: adds one report per call (a repeat adds a duplicate) and marks the session as crashed. Reports with the same fingerprint form one group; a group marked resolved becomes REGRESSED when a newer app version crashes again. Returns: {id, groupId, createdAt}; groupId identifies the crash group in the dashboard. Errors: 400 when a required field is missing or too long: fix it and resend. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
osYesOS details (e.g. 'Android 14', 'iOS 17.2')
typeYesCrash type: CRASH (fatal), NON_FATAL (exception), or ANR (Application Not Responding)
userIdNoPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in
messageYesError or exception message (1 to 5000 characters)
platformYesPlatform (e.g. 'Android', 'iOS', 'Windows')
sessionIdYesThe sessionId registered with horizon_create_crash_session for this app run (1 to 100 characters)
appVersionYesApp version (e.g. '1.2.3')
customKeysNoString key to string value metadata such as level or build flavor (max 10 entries)
sdkVersionYeshorizOn SDK version, for example '1.8.2' (1 to 50 characters)
stackTraceNoFull stack trace (max 20000 characters)
breadcrumbsNoRecent events before the crash, oldest first (max 50)
deviceModelYesDevice model (e.g. 'Pixel 8', 'iPhone 15')
fingerprintYesGrouping key: reports with the same fingerprint form one crash group, for example a hash of exception type and top stack frame (1 to 128 characters)
deviceMemoryMbNoDevice RAM in MB, for example 8192

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the annotations (readOnlyHint=false, openWorldHint=true, idempotentHint=false): it discloses that each call adds a report and repeats create duplicates, that the session is marked crashed, that same-fingerprint reports form a group, and that resolved groups become REGRESSED on a newer version. It also documents auth (HORIZON_API_KEY), error behavior (400/401/429) and the isError contract.

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?

Front-loaded with the core action, then cleanly segmented into Use when / Not for / Requires / Side effects / Returns / Errors. Despite its length, every section carries distinct information, so nothing is wasted.

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 14-parameter, 9-required mutation with a nested breadcrumbs array and no output schema, the description supplies return shape ({id, groupId, createdAt}), grouping semantics, auth requirements, and error handling. An agent has everything needed to invoke it 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 description coverage is 100%, so the schema already documents all 14 parameters including fingerprint grouping and sessionId provenance. The description adds only marginal meaning (userId optional, sessionId must come from horizon_create_crash_session), so the baseline 3 applies.

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?

States a specific verb (Submits) and resource (a CRASH/NON_FATAL/ANR report with device data) plus the grouping model by fingerprint. It explicitly distinguishes itself from horizon_create_log and horizon_submit_feedback, so an agent can route correctly without opening schemas.

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?

Provides explicit 'Use when', 'Not for', and 'Requires' sections. It names the two alternatives (horizon_create_log, horizon_submit_feedback) with the conditions that select them, and specifies the sessionId prerequisite from horizon_create_crash_session.

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

horizon_create_crash_sessionCreate Crash SessionA

Registers one app run (session) so horizOn can calculate the crash-free session rate. Use when: once at every app start, with a new unique sessionId; keep that ID for horizon_create_crash_report. Not for: reporting the crash itself (use horizon_create_crash_report) or player sign-in sessions (those come from horizon_signin_*). Side effects: records one session per call; a later crash report with the same sessionId marks it as crashed. Returns: {status: 'ok'}. Errors: 400 when a field is missing or too long: fix it and resend. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdNoPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in
platformYesPlatform (e.g. 'Android', 'iOS', 'Windows')
sessionIdYesNew unique ID for this app run, for example a UUID generated at start (1 to 100 characters)
appVersionYesApp version (e.g. '1.2.3')

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the annotations, it discloses the side effect (one session recorded per call; a later crash report with the same sessionId marks it crashed), the return value, and a full error taxonomy: 400 validation, HORIZON_API_KEY requirement, 401 vs horizon_test_connection, and 429 per-minute rate limiting with retry guidance.

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?

Labeled sections (Use when / Not for / Side effects / Returns / Errors) make it skimmable, and the core purpose leads. Every sentence carries operational information; nothing is padding.

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?

With no output schema, the description supplies the return shape, the safety-relevant side effect, cross-tool ID reuse, and the error contract, which is more than enough for a 4-parameter ingest call.

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?

Schema description coverage is 100%, so the baseline is 3, but the description adds lifecycle meaning the schema lacks: sessionId must be new and unique per run and must be kept for horizon_create_crash_report. It does not add much about userId, platform, or appVersion beyond the schema.

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?

States a specific verb and resource ('Registers one app run (session)') plus the downstream purpose ('so horizOn can calculate the crash-free session rate'). It distinguishes itself from horizon_create_crash_report and the horizon_signin_* family without the reader needing to open a schema.

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?

Explicit 'Use when' (once at every app start, with a new unique sessionId) and 'Not for' clauses that name the correct alternatives (horizon_create_crash_report for the crash itself, horizon_signin_* for player sessions). It even states the caller must retain the sessionId for the later report call.

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

horizon_create_logCreate LogA

Writes one server-side log entry (INFO, WARN or ERROR) for a player, visible in the horizOn dashboard's user logs. Use when: the game records a technical event or a handled error for later debugging, for example a failed purchase or a slow load. Not for: crashes and exceptions with a stack trace (use horizon_create_crash_report) or messages written by players (use horizon_submit_feedback). Requires: a userId from horizon_signup_* or horizon_signin_* and the BASIC tier or higher; no session token. Side effects: creates one log entry per call; a repeat creates a duplicate. Returns: {id, createdAt} of the new entry. Errors: 403 on the FREE tier: logs need BASIC or higher, so upgrade or skip logging. 400 for an invalid userId: pass the ID from the sign-in result. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
typeYesLog level: INFO, WARN or ERROR
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
messageYesLog message (max 1000 characters)
errorCodeNoOptional code to group entries in the dashboard, useful with ERROR, for example 'IAP_TIMEOUT' (max 50 characters)

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare this as a non-idempotent, non-destructive write, and the description adds substantial context beyond that: one entry created per call with duplicates on repeat, the exact return shape ({id, createdAt}), tier-gated 403 behavior, 400 for bad userId, 401 API-key mismatch, and 429 per-minute rate limiting with a retry recommendation. It is fully consistent with the annotations.

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?

Front-loads the core action and uses clear labeled sections (Use when, Not for, Requires, Side effects, Returns, Errors) that make scanning easy. Some content is redundant, such as restating the BASIC-tier requirement in the 403 error note, which slightly dilutes an otherwise tight structure.

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 four-parameter write tool with no output schema, the description covers purpose, routing to siblings, auth requirements, side effects, return shape, and the expected error modes. An agent has everything needed to invoke it correctly and interpret failures without opening other resources.

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 description coverage is 100%, so all four parameters already have in-schema documentation (type enum, userId UUID source, message max length, errorCode grouping). The description restates the userId source and INFO/WARN/ERROR levels but adds no syntax or format detail beyond the schema, so the baseline of 3 applies.

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?

States a specific verb and resource ('Writes one server-side log entry ... for a player') and pins the scope to the horizOn dashboard. It explicitly distinguishes itself from the two nearest siblings by naming horizon_create_crash_report and horizon_submit_feedback as different use cases.

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?

Has explicit 'Use when' and 'Not for' clauses, and the exclusion names the correct alternative tool for each case (crash report with stack trace, player-written feedback). Prerequisites (userId source, BASIC tier, no session token) are also stated, leaving nothing to inference.

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

horizon_get_all_localizationsGet All LocalizationsA
Read-onlyIdempotent

Reads all translated strings of one language as a key to text map (default: the app's default language). Use when: at game start or on a language switch, to load every UI text at once. Not for: a single key (use horizon_get_localization). Side effects: None (read only). Returns: {translations, language, total}; translations is empty (total 0) when the language has no strings. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
langNoISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language.

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
languageNo
translationsNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description adds genuinely new behavioral context: the required HORIZON_API_KEY, the isError/HTTP-status error contract, a 401 meaning a bad key, and a 429 per-minute rate limit with retry guidance. This is exactly the auth-needs and rate-limit disclosure that goes beyond structured annotations.

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?

Front-loads the purpose, then uses labeled sections (Use when / Not for / Side effects / Returns / Errors) that map to the questions an agent asks before calling. Every sentence carries information; the only mild redundancy is the read-only side-effect line, which is negligible.

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 an output schema exists, return-shape explanation is optional, but the description goes further by covering auth, empty-result behavior (total 0), and error/rate-limit semantics. Nothing an agent needs to invoke this read tool correctly is missing.

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 description coverage is 100%; the lang parameter is fully documented in the schema (ISO 639-1, 2 lowercase letters, enumerated values, omit for default). The description restates 'one language' and the default-language fallback but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

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?

States a specific verb and resource ('Reads all translated strings of one language as a key to text map') and immediately scopes it with the default-language behavior. It explicitly distinguishes itself from the single-key sibling horizon_get_localization, so an agent can select between them without opening either schema.

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?

Provides an explicit 'Use when' (game start or language switch, load all UI text at once) and an explicit 'Not for' that names the alternative (horizon_get_localization) for single keys. Both the positive trigger and the exclusion are stated, leaving nothing to inference.

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

horizon_get_all_remote_configsGet All Remote ConfigsA
Read-onlyIdempotent

Reads every remote config value of the app in one call as a key to string map. Use when: at game start, to cache all flags and balance values at once. Not for: a single value (use horizon_get_remote_config) or checking the API key only (use horizon_test_connection). Side effects: None (read only). Returns: {configs, total}, where configs maps each key to its string value; an app without configs returns an empty map and total 0. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
configsNo

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/destructive/openWorld, but the description goes well beyond them by disclosing auth requirements (HORIZON_API_KEY), the error contract (isError with HTTP status/body), and behavioral specifics for 401 (key wrong) and 429 (per-minute rate limit; wait and retry). This is rich operational context the annotations cannot provide.

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?

Front-loaded with the operation, then cleanly labeled sections (Use when, Not for, Side effects, Returns, Errors). Every sentence adds distinct value; nothing is padding.

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?

An output schema exists, yet the description still orients the agent on the {configs, total} shape and the empty-map/zero-total edge case, plus the full error taxonomy. For a read-only config fetch, an agent has everything needed to call and interpret it.

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?

The tool takes zero parameters, so there is no parameter semantics to document; the description's 'key to string map' phrasing correctly conveys the shape of what is read. Baseline 4 applies for a parameterless tool.

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?

States a specific verb (reads) and resource (every remote config value of the app) with clear scope (all, in one call, as a key-to-string map). It distinguishes itself from siblings by naming horizon_get_remote_config for single values, so an agent can route correctly without opening schemas.

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?

Explicit 'Use when' (game start, to cache all flags at once) and 'Not for' clauses that route to two named alternatives: horizon_get_remote_config for a single value and horizon_test_connection for API-key checks. Nothing is left to inference.

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

horizon_get_email_statusGet Email StatusA
Read-onlyIdempotent

Returns the delivery status (pending, processing, sent or failed) and details of one email queued with horizon_send_email. Use when: checking whether a sent or scheduled email was delivered, or why it failed. Not for: sending again (use horizon_send_email only for a new email) or stopping delivery (use horizon_cancel_email). Requires: the emailId from horizon_send_email. Side effects: None (read only). Returns: {id, status, templateSlug, userId, language, scheduledAt, processedAt, errorReason, createdAt}; errorReason explains a failed email (for example SMTP rejected it). Errors: An unknown emailId or one of another API key is rejected: pass the id returned by horizon_send_email. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
emailIdYesEmail ID (UUID) returned by horizon_send_email

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
statusNo
userIdNo
languageNo
createdAtNo
errorReasonNo
processedAtNo
scheduledAtNo
templateSlugNo

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already cover readOnly/idempotent/destructive, but the description adds substantial context beyond them: auth requirement (HORIZON_API_KEY), rate-limit behavior (429 per-minute, wait and retry), 401 meaning, and cross-API-key id rejection. These are genuine behavioral disclosures the annotations do not provide.

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?

Uses labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) with the purpose front-loaded, so scanning is fast. It is somewhat verbose, and restating the return fields is arguably redundant given an output schema exists, but no sentence is wasted.

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 single-parameter read tool this covers everything an agent needs: selection criteria, prerequisites, side-effect profile, error taxonomy with remediation, and return shape. Output schema exists, yet the description's return summary is a harmless supplement rather than a gap.

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?

Schema coverage is 100% and the schema already documents emailId as the UUID returned by horizon_send_email, so the baseline is 3. The description adds that an unknown id or one belonging to another API key is rejected, which is a real invocation constraint beyond the schema text.

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?

States a specific verb and resource ('Returns the delivery status... of one email queued with horizon_send_email') and enumerates the possible status values. It explicitly distinguishes itself from the siblings horizon_send_email and horizon_cancel_email, so an agent can select it without ambiguity.

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?

Provides explicit when-to-use ('checking whether a sent or scheduled email was delivered, or why it failed') and when-not-to-use with named alternatives ('Not for: sending again... or stopping delivery...'). This is the full when/when-not/alternative triple.

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

horizon_get_leaderboard_aroundGet Leaderboard Around UserA
Read-onlyIdempotent

Returns the leaderboard entries directly above and below a player's own position, including the player, each with profile. Use when: a game shows 'you and your rivals' instead of the global top. Not for: the global top list (use horizon_get_leaderboard_top) or the position alone (use horizon_get_user_rank). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only). Returns: {entries: [{position, username, score, profile}]} in board order. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
rangeNoHow many entries around the player to return, 1 to 50 (default 10)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
leaderboardKeyNoBoard key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board.

Output Schema

ParametersJSON Schema
NameRequiredDescription
entriesNo

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=true, so safety is covered structurally. The description adds useful non-annotation context: no session token required, the userId provenance, error semantics (404/401/429 with the 429 rate-limit wait-and-retry instruction), and the isError behavior. That said, much of the return-shape detail is redundant with the existing output schema, so it does not reach the top of the range.

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?

Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and front-load the scope before the alternative routing. It is slightly long, and the Returns block partially duplicates the output schema, but no sentence is wasted.

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 a read-only tool with a full schema and an output schema, the definition still covers prerequisites (userId, no session token), auth (HORIZON_API_KEY), error handling and rate-limit recovery, and the sibling routing needed to call it correctly. Nothing an agent needs is missing.

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 description coverage is 100%, so all three parameters (range, userId, leaderboardKey) are already documented, including UUID format and the leaderboardKey pattern/default. The description echoes the userId source and leaderboardKey default rather than adding new semantics beyond the schema, so the baseline 3 applies.

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?

States a specific verb and resource ('returns the leaderboard entries directly above and below a player's own position') and immediately distinguishes itself from horizon_get_leaderboard_top and horizon_get_user_rank. An agent can identify the exact scope without opening the schema.

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?

Explicit 'Use when' gives the triggering scenario ('you and your rivals' UI) and 'Not for' names both alternative siblings with the condition that selects each. Nothing is left to inference.

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

horizon_get_leaderboard_topGet Leaderboard TopA
Read-onlyIdempotent

Returns the top entries of a leaderboard from position 1, each with the player's profile, plus the requesting player's own entry when they are outside the list. Use when: a game shows a global top list (top 10, top 100). Not for: one player's position alone (use horizon_get_user_rank) or the players around them (use horizon_get_leaderboard_around). Requires: a userId from horizon_signup_* or horizon_signin_* (used to append the player's own entry); no session token. Side effects: None (read only). Returns: {entries: [{position, username, score, profile}]} in board order. When the userId is not among them, the player's own entry with the real position is added at the end. An empty board returns an empty list. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of top entries to return, 1 to 100 (default 10)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
leaderboardKeyNoBoard key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board.

Output Schema

ParametersJSON Schema
NameRequiredDescription
entriesNo

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond annotations: discloses the self-entry append behavior when the userId is outside the list, empty-board behavior, 404/401/429 error semantics with remediation, the HORIZON_API_KEY requirement, and 'no session token'. The read-only claim aligns with readOnlyHint.

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?

Front-loaded with a labeled structure (Use when / Not for / Requires / Side effects / Returns / Errors) that makes scanning trivial. Every sentence carries operational value with no filler.

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?

Covers return shape, edge cases (empty board, self-entry), auth prerequisites, and error taxonomy including cross-tool 401 comparison. Despite an output schema existing, the extra edge-case detail is warranted and complete for correct invocation.

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% and both userId and leaderboardKey carry full descriptions including UUID format, defaults, and the 'omit to use the API key's default board' fallback. The description largely defers to the schema, which is the right call here, so baseline 3 applies.

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?

States a specific verb+resource ('Returns the top entries of a leaderboard from position 1') and explicitly distinguishes from siblings horizon_get_user_rank and horizon_get_leaderboard_around. An agent can pick the right tool without opening any schema.

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?

Explicit 'Use when' (global top list, top 10/top 100) and 'Not for' clauses naming the two alternative tools and their selecting conditions. Nothing is left to inference.

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

horizon_get_localizationGet LocalizationA
Read-onlyIdempotent

Reads one translated string by key in one language (default: the app's default language). Use when: the game needs a single text, for example a dynamic message. Not for: loading the UI texts at start (use horizon_get_all_localizations) or finding out which languages exist (use horizon_get_localization_languages). Side effects: None (read only). Returns: {localizationKey, value, language, found}. A missing key or translation is not an error: found is false and value null, so show a fallback text. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesLocalization key exactly as defined in the dashboard, for example 'ui.play_button' (max 100 characters)
langNoISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language.

Output Schema

ParametersJSON Schema
NameRequiredDescription
foundNo
valueNo
languageNo
localizationKeyNo

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the annotations (which only cover readOnly/idempotent/destructive/openWorld) by disclosing the return shape, that a missing key is NOT an error (found=false, value=null), the HORIZON_API_KEY requirement, and the 401/429 failure semantics including rate-limit retry guidance.

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?

Front-loaded with the core action, then clearly labelled Use when / Not for / Side effects / Returns / Errors sections. Dense but every sentence carries actionable information.

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 the output schema existing, the description completes the picture by covering the auth prerequisite, non-error missing-key case, and error taxonomy, which the schema and annotations do not convey.

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 description coverage is 100%, so both parameters are already documented in the schema. The description only restates the default-language behavior for 'lang', adding no syntax beyond the structured fields; baseline 3 applies.

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?

States a specific verb and resource ('Reads one translated string by key in one language') plus the default behavior, which an agent can distinguish immediately from horizon_get_all_localizations and horizon_get_localization_languages.

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?

Explicit 'Use when' with a concrete example (dynamic message) and an explicit 'Not for' clause naming both alternative tools and the conditions that select them.

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

horizon_get_localization_languagesGet Localization LanguagesA
Read-onlyIdempotent

Lists the languages that have at least one translation for the app. Use when: before horizon_get_localization or horizon_get_all_localizations, to pick a valid lang or build a language menu. Not for: the texts themselves (use horizon_get_all_localizations). Side effects: None (read only). Returns: {languages, total}, where languages holds ISO 639-1 codes such as 'en' or 'de'; empty when the app has no translations. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
languagesNo

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the readOnly/idempotent/non-destructive annotations, the description adds auth requirements (HORIZON_API_KEY), the exact return shape ({languages, total} with ISO 639-1 codes, empty when no translations), and concrete failure semantics including distinguishing 401 from horizon_test_connection and the 429 per-minute rate limit with a retry hint.

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?

Organized as labeled, front-loaded sections (Use when / Not for / Side effects / Returns / Errors) with no filler. The only mild overlap is the Returns section against the existing output schema, but it is brief and non-redundant in substance.

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 read tool, the definition covers routing, semantics, side effects, return structure and error behavior, so an agent can select and invoke it without further exploration. Nothing needed is missing given the annotations and output schema already present.

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?

The tool takes zero parameters, so the schema baseline applies (baseline 4). There is nothing for the description to clarify about inputs, and it correctly adds no invented parameter detail.

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?

States a specific verb+resource ('Lists the languages that have at least one translation for the app') and immediately bounds the scope to translated languages only. It is clearly distinguishable from horizon_get_localization and horizon_get_all_localizations, which return texts rather than the language list.

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 when to use ('before horizon_get_localization or horizon_get_all_localizations, to pick a valid lang or build a language menu') and when not ('the texts themselves - use horizon_get_all_localizations'). Alternatives are named with the condition that selects them.

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

horizon_get_newsGet NewsA
Read-onlyIdempotent

Lists the published in-game news of the app (announcements, patch notes) created in the horizOn dashboard, newest first. Use when: a game shows a news feed or a message of the day, optionally filtered to the player's language. Not for: configuration values (use horizon_get_remote_config) or UI translations (use horizon_get_localization). Side effects: None (read only). Returns: an array of {id, title, message, releaseDate, languageCode} with only published entries whose release date has passed; an empty array means there is no news. Without languageCode, entries of all languages are returned. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of entries to return, 0 to 100 (default 20)
languageCodeNoISO 639-1 code (2 lowercase letters, for example 'en' or 'de') to return only entries in that language. Omit for all languages

TDQS

A4.9/5.0
Behavior5/5

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

Goes well beyond the annotations by disclosing auth requirements (HORIZON_API_KEY), filtering behavior (only published entries past release date), empty-array semantics, and detailed error semantics: 401 means a bad key (cross-referenced to horizon_test_connection) and 429 means a per-minute rate limit with a retry instruction. This is exactly the extra context annotations don't carry.

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?

Front-loaded with purpose, then cleanly labeled sections (Use when / Not for / Side effects / Returns / Errors). The length is justified because each section carries decision-relevant information for an agent with no output schema to fall back on.

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?

With no output schema, the description compensates by specifying the return shape ({id, title, message, releaseDate, languageCode}), field semantics, and empty-result meaning. Auth, side effects, and error handling are all covered, so an agent has everything needed to invoke and interpret the call.

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?

Schema coverage is 100%, so the baseline is 3. The description reinforces the languageCode filtering meaning ('optionally filtered to the player's language', all languages when omitted), which adds contextual clarity, though it adds no syntax detail for limit beyond what the schema already documents.

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?

States a specific verb and resource ('Lists the published in-game news... announcements, patch notes'), adds ordering ('newest first'), and explicitly distinguishes itself from siblings horizon_get_remote_config and horizon_get_localization. An agent can identify the tool's scope without opening the schema.

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?

Provides an explicit 'Use when' condition (a game shows a news feed or message of the day, optionally language-filtered) and an explicit 'Not for' with the correct alternative named for each exclusion. Nothing is left to inference.

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

horizon_get_profileGet Player ProfileA
Read-onlyIdempotent

Returns a player's profile (avatar, frame, badges), the player's unlocks and the cosmetics catalog of the API key with an available flag per entry. Use when: before horizon_set_profile, to show the selection screen and learn which IDs the player may pick. Not for: changing the profile (use horizon_set_profile) or showing other players' profiles (leaderboard entries already carry them). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId, profile: {avatarId, frameId, badges}, unlocks, cosmetics: [{id, type, locked, available}], limits: {maxBadges, maxUnlocks}}. available true means this player may select the entry. Errors: 401 SESSION_REQUIRED for a missing or expired session: sign in again. 403 SESSION_FORBIDDEN for a session of another user: pass the userId that signed in. 404 PLAYER_NOT_FOUND for an unknown userId. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

Output Schema

ParametersJSON Schema
NameRequiredDescription
limitsNo
userIdNo
profileNo
unlocksNo
cosmeticsNo

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, yet the description goes further: it names the required session flow (signin tools producing accessToken), the no-side-effects guarantee, the HORIZON_API_KEY dependency, per-minute 429 rate limits, and specific error semantics (401/403/404) with remediation. This is materially richer than the annotations.

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?

Front-loaded with labeled sections (Use when/Not for/Requires/Side effects/Returns/Errors) that make it highly scannable. The Errors paragraph is verbose with some redundancy, but nearly every sentence carries actionable information.

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?

Though an output schema exists, the description still enumerates the return shape and the meaning of the 'available' flag, covers auth prerequisites, side-effect profile, and the full error/rate-limit surface. Nothing an agent needs to invoke it correctly is missing.

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 description coverage is 100%, so both parameters (userId UUID, sessionToken) are already documented in the schema. The description restates their provenance (userId from signup/signin, sessionToken as Bearer) but adds little beyond the schema, so the baseline 3 applies.

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?

States a specific verb+resource ('Returns a player's profile ... unlocks and the cosmetics catalog') and explicitly distinguishes itself from horizon_set_profile and from leaderboard-embedded profiles. An agent can identify this tool's scope without reading any other tool.

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?

Provides explicit 'Use when' (before horizon_set_profile, to show the selection screen), 'Not for' (changing the profile, showing others' profiles), and names the correct alternatives for each excluded case. Nothing is left to inference.

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

horizon_get_remote_configGet Remote ConfigA
Read-onlyIdempotent

Reads one remote config value by key (a feature flag or balance value set in the horizOn dashboard) as a string. Use when: the game needs a single value, for example to check one feature flag. Not for: loading many values at start (use horizon_get_all_remote_configs, one request instead of many). Side effects: None (read only). Returns: {configKey, configValue, found}. Values are always strings: parse numbers and booleans yourself. An unknown key is not an error: found is false and configValue null, so fall back to a default. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesConfig key exactly as defined in the dashboard, case-sensitive, for example 'max_lives' (max 256 characters)

Output Schema

ParametersJSON Schema
NameRequiredDescription
foundNo
configKeyNo
configValueNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description goes well beyond them: unknown keys are not errors (found=false, configValue=null, fall back to a default), all values are strings requiring manual parsing, and error semantics include HORIZON_API_KEY requirement, 401 diagnosis via horizon_test_connection, and 429 per-minute rate limit with a wait-and-retry instruction.

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?

Dense but organized under labeled sections (Use when / Not for / Side effects / Returns / Errors), with the core purpose front-loaded in the opening sentence. Every line carries actionable information; none is filler.

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 one-parameter read with an output schema, the description supplies everything an agent needs: auth requirement, verbatim error taxonomy, string-typed return caveat, and default-fallback behavior on missing keys. Nothing material is omitted.

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% and the single 'key' parameter is fully documented in the schema (case-sensitivity, 256 char max, example). The description adds only 'by key', contributing nothing beyond the structured field, so the baseline 3 applies.

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?

Specific verb+resource ('Reads one remote config value by key') with scope stated as a single value, and it explicitly contrasts with the sibling horizon_get_all_remote_configs. An agent can distinguish these two tools without opening either schema.

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?

Explicit 'Use when' (single value / check one feature flag) and 'Not for' (loading many values at start → use horizon_get_all_remote_configs, one request instead of many), naming the exact alternative and the condition that selects it.

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

horizon_get_stateGet Player StateA
Read-onlyIdempotent

Returns the player's server-owned values (Validated Actions): balance, today's earnings and daily cap per value key, such as currency or loot counters. Use when: the game shows the wallet or checks whether a spend is possible before starting a run. Not for: changing balances: nothing writes a balance directly, only accepted runs through horizon_submit_validated with earned. Also not for the save game (use horizon_load_cloud_data). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {userId, day, values: [{key, balance, earnedToday, dailyCap}]}: every value key defined in the API key's rules, sorted by key (balance 0 when never earned); values is empty when the rules define no values. day is the current UTC day, earnedToday the positive credit on that day (0 after midnight UTC), dailyCap null without a daily cap; the other value rules stay hidden. Games may mirror the values into cloud save for offline display but must never send them back. Errors: The error result names the stable code: 401 SESSION_REQUIRED (sign in again), 403 SESSION_FORBIDDEN (pass the userId that signed in), 404 PLAYER_NOT_FOUND, 429 without code (account request limit, wait). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

Output Schema

ParametersJSON Schema
NameRequiredDescription
dayNo
userIdNo
valuesNo

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial context beyond them: required session token sourcing, the UTC-day reset semantics of earnedToday, the 0-when-never-earned default, the empty-values case, and a full error taxonomy (401/403/404/429) with remediation. This is far richer than the annotation baseline.

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?

Front-loaded with the core purpose and organized under clear labels (Use when / Not for / Requires / Side effects / Returns / Errors), which aids scanning. It is on the long side and the Returns section overlaps the output schema, but for a tool with this many auth and error paths the length is largely earned.

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 the complexity of session-authenticated reads with specific error codes, the description covers prerequisites, side-effect profile, return shape semantics, and failure handling. Even though an output schema exists, the added day/dailyCap/sorting semantics make it complete for correct invocation.

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 description coverage is 100%, so userId and sessionToken are already documented in the schema; the description's 'Requires: userId and the player's session' largely restates that. It adds only the constraint that the session must come from a matching sign-in, which is marginal value over the schema.

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?

Opens with a specific verb+resource ('Returns the player's server-owned values (Validated Actions)') and enumerates the concrete payload (balance, today's earnings, daily cap). It explicitly names siblings it is not (horizon_submit_validated, horizon_load_cloud_data), so an agent can separate it from the many horizon_* tools.

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?

Provides an explicit 'Use when' trigger (wallet display, pre-spend check), an explicit 'Not for' exclusion with the correct alternative named for each case (horizon_submit_validated for writes, horizon_load_cloud_data for saves). Nothing about selection is left to inference.

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

horizon_get_user_rankGet User RankA
Read-onlyIdempotent

Returns one player's own position, score and profile on a leaderboard. Use when: after horizon_submit_score, or to show 'your rank' in the game. Not for: a list of entries (use horizon_get_leaderboard_top or horizon_get_leaderboard_around). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only). Returns: {position, username, score, profile}. profile is {avatarId, frameId, badges} (IDs from the cosmetics catalog; null or [] when not set, set with horizon_set_profile). Errors: 404 when the player has no score on this board yet (submit one first) or the leaderboardKey is unknown (check horizon_list_leaderboards). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
leaderboardKeyNoBoard key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board.

Output Schema

ParametersJSON Schema
NameRequiredDescription
scoreNo
profileNo
positionNo
usernameNo

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the description goes beyond them by disclosing required auth (HORIZON_API_KEY), the 404 semantics (no score yet / unknown board) with remedies, and 401/429 failure handling including rate-limit advice. This is substantial behavioral context an agent cannot get from the annotations.

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?

Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it scannable and front-loaded with the core purpose first. The Errors sentence is dense and long, but each clause is actionable rather than filler.

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?

Although an output schema exists, the description still summarizes the return shape and profile sub-fields, and it covers auth, error taxonomy, and rate limits. Nothing an agent needs to select or invoke this tool correctly is missing.

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 description coverage is 100%, so both userId and leaderboardKey are fully documented in the schema (origin, format, default-board behavior). The description largely restates those origins rather than adding new syntax or value constraints, so the baseline 3 is correct.

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?

States a specific verb+resource ('Returns one player's own position, score and profile on a leaderboard') and immediately distinguishes itself from the sibling list tools by scope (single player's own rank vs. a list of entries). An agent can differentiate it from horizon_get_leaderboard_top/around without opening any schema.

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?

Gives explicit 'Use when' triggers (after horizon_submit_score, to show 'your rank') and an explicit 'Not for' with named alternatives (horizon_get_leaderboard_top, horizon_get_leaderboard_around). Preconditions are also spelled out (needs a userId, no session token).

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

horizon_list_leaderboardsList Leaderboard BoardsA
Read-onlyIdempotent

Lists the leaderboard boards of this API key with their keys, sort order and whether they accept only validated runs. Use when: first, when a game has several boards (weekly, per level) or before submitting, to learn the leaderboardKey values and whether a board is validatedOnly. Not for: reading entries (use horizon_get_leaderboard_top, horizon_get_user_rank or horizon_get_leaderboard_around). Side effects: None (read only). Returns: {boards: [{key, name, sortOrder, isActive, scoreCount, validatedOnly}], totalElements}. Pass a key as leaderboardKey to the submit, top, rank and around tools; without it they use the default board. validatedOnly true means scores are accepted only through horizon_start_run plus horizon_submit_validated. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
boardsNo
totalElementsNo

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, so the description's 'Side effects: None (read only)' is redundant. It earns credit for the downstream-key contract ('pass a key as leaderboardKey... without it they use the default board') and the validatedOnly semantics, but the errors section partially overlaps with the output schema and general MCP error patterns.

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?

Front-loaded with purpose, then Use/Not-for/Side effects/Returns/Errors sections. Dense but well-organized. The errors paragraph names a specific 401/429 interplay with horizon_test_connection that is useful, though slightly verbose.

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?

Given an output schema exists, the return values needn't be restated, yet the description does so anyway (helpful for agents that don't parse schemas). The auth/error contract (HORIZON_API_KEY, 401/429 semantics, test_connection cross-reference) fills a real gap for a zero-param read tool.

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?

Zero parameters, so baseline is 4. The description adds value by explaining how returned keys are consumed by other tools, which is param-adjacent semantics not present in the (empty) schema.

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?

Specific verb+resource ('Lists the leaderboard boards of this API key') with the returned fields enumerated, and sibling tools for reading entries are named as out-of-scope. An agent can distinguish this discovery/listing tool from horizon_get_leaderboard_top without opening either schema.

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?

Explicit 'Use when' clauses (multiple boards, before submitting to learn leaderboardKey/validatedOnly) plus an explicit 'Not for' clause naming the three alternative tools for reading entries. This is the strongest form of routing guidance.

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

horizon_load_cloud_dataLoad Cloud DataA
Read-onlyIdempotent

Reads a player's save game that was stored with horizon_save_cloud_data. Use when: the game starts or the player switches devices and needs the saved progress. Not for: writing (use horizon_save_cloud_data) or balances of server-owned values (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: None (read only). Returns: {found, saveData}. found false with saveData null means the player never saved: this is normal on first start, so initialize default data. Errors: 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

Output Schema

ParametersJSON Schema
NameRequiredDescription
foundNo
saveDataNo

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description adds layers beyond them: the auth prerequisite (sign in via horizon_signin_email/anonymous, pass accessToken as sessionToken), HORIZON_API_KEY requirement, the normal-case 'found:false/saveData:null' semantics, and error decoding (401 expired session, 403 token-user mismatch, 429 rate limit). This is unusually rich behavioral disclosure that directly shapes correct invocation and retry logic.

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?

Front-loaded purpose followed by labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors). It is dense, but every sentence carries actionable detail — auth, edge cases, error triage — with no filler.

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 the tool is a read with an output schema, the description needn't explain return shape, yet it still documents the found/saveData contract and first-run initialization. Combined with auth, side-effect, and error coverage, nothing an agent needs to call it correctly is missing.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds practical meaning: where userId and sessionToken come from, the sign-in flow that produces the token, and the 403 rule that the userId must match the signed-in user. That goes beyond the schema text, though it doesn't fully specify field formats.

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?

Opens with a specific verb+resource: 'Reads a player's save game that was stored with horizon_save_cloud_data.' It ties the resource to the exact sibling that produces it, and the paired 'Not for' clause names the write counterpart, so an agent can distinguish it without opening any schema.

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?

Explicit triggering conditions ('when the game starts or the player switches devices') and explicit exclusions routing to alternatives ('use horizon_save_cloud_data' for writing, 'horizon_get_state' for server-owned balances). Covers both when-to-use and when-not-to-use.

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

horizon_redeem_gift_codeRedeem Gift CodeA

Redeems a gift code for a player: uses up one redemption and returns the reward data and any cosmetic unlocks. Use when: the player confirms a code in the game. Check it first with horizon_validate_gift_code when unsure. Not for: only checking a code (use horizon_validate_gift_code, which uses nothing up). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: each successful call uses up one redemption and cannot be undone; cosmetic grants are added to the player's unlocks. A repeat redeems again or fails when the per-player limit is reached. Returns: {success, message, giftData, grantedUnlocks}. giftData is a JSON string with the reward set in the dashboard, which the game must parse and apply. grantedUnlocks lists the cosmetic IDs from giftData.grants the player owns after this redemption ([] without grants); show them with horizon_get_profile. Errors: 404 for an unknown code. 400 for an expired or revoked code or a reached limit: tell the player the code does not work. 409 UNLOCK_LIMIT_REACHED when the player would own more than 25 unlocks; the code is not used up. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesGift code as the player typed it (max 50 characters)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

TDQS

A4.6/5.0
Behavior5/5

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

Annotations (readOnlyHint=false, idempotentHint=false, openWorldHint=true, destructiveHint=false) only sketch the safety profile; the description adds far more: one redemption is consumed per success, the action cannot be undone, repeat calls redeem again or fail at the per-player limit, unlock grants mutate the player's unlocks, HORIZON_API_KEY is required, and per-minute rate limits apply. It also spells out the full error taxonomy (404, 400 expired/revoked/limit, 409 UNLOCK_LIMIT_REACHED with the code not consumed, 401 vs 403 semantics) and the isError result contract.

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?

Densely labeled with 'Use when', 'Not for', 'Requires', 'Side effects', 'Returns', 'Errors', and front-loads the core action and its cost before the detail. Every section carries actionable content, though the error enumeration is long enough that an agent must read past several lines to reach the auth/rate-limit notes.

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?

No output schema exists, yet the description fully specifies the return shape ({success, message, giftData, grantedUnlocks}), explains that giftData is a JSON string the game must parse and apply, and clarifies that grantedUnlocks lists post-redemption cosmetic IDs. Combined with auth prerequisites, side effects, and error handling, an agent has everything needed to invoke and interpret this call.

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 description coverage is 100%, so code, userId, and sessionToken are already documented at the field level, including that the token is sent as a Bearer session. The description restates the acquisition path ('sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken') but adds no format, constraint, or edge-case detail beyond the schema. Baseline 3 is appropriate when the schema does the heavy lifting.

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?

Starts with a specific verb+resource ('Redeems a gift code for a player') and immediately scopes what the call does: consumes a redemption and returns reward data plus cosmetic unlocks. It explicitly names the sibling it is not (horizon_validate_gift_code), so an agent can distinguish redeem from validate without opening either schema.

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?

Provides explicit when ('the player confirms a code in the game'), when-not ('only checking a code'), and the alternative (horizon_validate_gift_code, noted as using nothing up). The routing decision between redeem and validate is fully specified with the cost trade-off that motivates it.

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

horizon_save_cloud_dataSave Cloud DataA
DestructiveIdempotent

Stores a player's save game as one string (usually JSON) on the server, replacing the player's previous save. Use when: the game saves progress so it survives reinstalls and can be loaded on another device. Not for: reading the save (use horizon_load_cloud_data) or server-owned currency that players must not edit (use Validated Actions: horizon_submit_validated and horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: overwrites the player's single save slot; the old save is gone. Saving the same data again changes nothing. Returns: {success: true, dataSizeBytes}. Errors: 403 when the data exceeds the tier limit (defaults FREE 1 KB, BASIC 5 KB, PRO 20 KB, ENTERPRISE 250 KB): shrink the save or upgrade. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
dataYesThe complete save as a string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes well beyond them: it explains what gets destroyed (the single save slot, old save gone), that re-saving is a no-op, the auth prerequisites (userId + sessionToken from sign-in), and enumerated error meanings (403 tier limit, 401 expired session, 429 rate limit, wrong API key).

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?

Front-loads the core action in the first sentence, then labels blocks (Use when / Not for / Requires / Side effects / Returns / Errors). Despite its length, every section carries actionable information an agent needs, with no filler.

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?

No output schema exists, and the description compensates fully by documenting the return shape ({success, dataSizeBytes}) and the full failure surface with status codes and remediation. Auth, side effects, and limits are all covered, leaving no material gap for a mutation tool.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: data is usually serialized JSON subject to a lower tier limit than the schema maxLength, and sessionToken is the accessToken from a specific sign-in tool that must belong to the passed userId. This relationships-and-provenance detail is not in the schema.

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?

States a specific verb (Stores) and resource (a player's save game as one string) with scope: it replaces the previous save. Explicitly distinguishes itself from horizon_load_cloud_data and the Validated Actions siblings, so an agent can select it without opening any schema.

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?

Uses explicit 'Use when' and 'Not for' framing, names the alternative read tool (horizon_load_cloud_data) and the server-owned-currency alternative (horizon_submit_validated/horizon_get_state). The condition that selects each sibling is spelled out.

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

horizon_send_emailSend EmailA

Queues a transactional email from a dashboard template to one registered player, sent now or at a scheduled time through the developer's own SMTP server. Use when: the game triggers a message to a player, such as a welcome mail or a reminder. Not for: checking delivery (use horizon_get_email_status) or stopping a queued email (use horizon_cancel_email). Requires: an SMTP configuration and the template in the horizOn dashboard, and a recipient with a verified email address. Side effects: queues one new email per call; repeating the call sends the email again, so never repeat it to retry a status check. Returns: {id, status: 'pending', scheduledAt}; pass id to horizon_get_email_status to follow delivery or to horizon_cancel_email to stop it. Errors: 400 for an unknown templateSlug or a recipient without a verified email address: check the slug in the dashboard or pick another user. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) of the recipient; the player needs a verified email address
languageYesISO 639-1 code (2 lowercase letters) of the template translation to render, for example 'en' or 'de'
variablesYesValues for the template's variables as a string map, for example {"username": "John"}; pass {} when the template has none
scheduledAtNoISO 8601 timestamp for delayed delivery, at most 30 days ahead, for example 2026-10-01T09:00:00Z. Omit to send immediately
templateSlugYesSlug of an email template defined in the dashboard, for example 'welcome' or 'reminder'

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover the safety profile (readOnlyHint=false, idempotentHint=false, openWorldHint=true), and the description adds substantial context beyond them: it queues one email per call, repeating sends again (so never retry a status check), requires an SMTP config + dashboard template + verified recipient, and documents the return shape and the 400/401/429 error semantics including rate limiting.

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?

Purpose is front-loaded, followed by labeled Use when / Not for / Requires / Side effects / Returns / Errors blocks, so an agent can scan to the relevant section. It is long, but the length is justified by the non-idempotent send and multiple error modes; little of it is filler.

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?

No output schema exists, and the description compensates fully by describing the return object ({id, status, scheduledAt}), how to use the id downstream, the required credentials (HORIZON_API_KEY), and the error envelope behavior. Everything needed to call the tool correctly and interpret failures is present.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds failure semantics tied to specific parameters: a 400 for an unknown templateSlug or a recipient without a verified email address, plus the instruction to check the slug in the dashboard or pick another user. That is genuine meaning beyond the schema field docs, though most syntax still lives in the schema.

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?

States a specific verb+resource+scope: 'Queues a transactional email from a dashboard template to one registered player, sent now or at a scheduled time through the developer's own SMTP server.' It also distinguishes itself from siblings by name (horizon_get_email_status, horizon_cancel_email), so an agent can route correctly without opening any schema.

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?

Explicit 'Use when' (game triggers a message to a player) and 'Not for' clauses that name the two alternative tools for delivery checking and cancellation. When-to-use, when-not-to-use, and alternatives are all stated rather than inferred.

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

horizon_set_profileSet Player ProfileA
DestructiveIdempotent

Sets a player's avatar, frame and displayed badges. This REPLACES THE WHOLE PROFILE: an omitted, null or empty slot is cleared. Use when: the player confirms a new look. Pass the current values from horizon_get_profile for the slots that should stay. Not for: reading the profile or the catalog (use horizon_get_profile). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Every ID must be in the API key's catalog, have the type of its slot and be free or unlocked for the player; at most 3 distinct badges. Side effects: overwrites all three slots; the same call again changes nothing more. The profile shows up in leaderboard entries. Returns: the same body as horizon_get_profile after the change. Errors: The error result names the stable code. 400 INVALID_BADGES, INVALID_COSMETIC_ID, COSMETIC_NOT_FOUND or COSMETIC_TYPE_MISMATCH: pick IDs of the right type from horizon_get_profile. 403 COSMETIC_LOCKED: the cosmetic is locked and the player has not unlocked it (unlocks come from gift code grants). 401 SESSION_REQUIRED for a missing or expired session: sign in again. 403 SESSION_FORBIDDEN for a session of another user: pass the userId that signed in. 404 PLAYER_NOT_FOUND for an unknown userId. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
badgesNoBadge cosmetic IDs of type badge to display (0 to 3, distinct, order kept, each 1 to 32 characters: a-z, 0-9, ., _ and -). Omit or [] clears all badges.
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
frameIdNoCosmetic ID of type frame from the catalog (for example "frame.gold"). Omit, null or "" clears the frame slot.
avatarIdNoCosmetic ID of type avatar from the catalog (for example "avatar.gold"). Omit, null or "" clears the avatar slot.
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session

TDQS

A4.8/5.0
Behavior5/5

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

Although annotations already declare destructive=true and idempotent=true, the description goes well beyond them: it explains that omitted/null/empty clears slots, that the call replaces all three slots at once, the catalog/type/unlock constraints, the 3-badge cap, the leaderboard visibility, and a full error taxonomy (400 INVALID_BADGES, 403 COSMETIC_LOCKED, 401/403 SESSION_*, 404, 429 rate limit with retry advice). This is unusually rich disclosure and does not contradict the annotations.

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?

Long but dense and well-sectioned into Use when / Not for / Requires / Side effects / Returns / Errors, with the destructive replace-all semantics front-loaded. Every sentence carries actionable content, though the error-code enumeration makes it heavier than strictly necessary.

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?

A mutation tool with no output schema needs to explain side effects, auth, and failure modes; it does all three, including what is returned (the get_profile body) and the isError contract. Nothing an agent needs to call this correctly is missing.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: pass current values from horizon_get_profile for slots that should stay, every ID must belong to the API key's catalog with the type of its slot and be free or unlocked, and at most 3 distinct badges. These constraints are semantic rules not expressible in the JSON schema.

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?

Opens with a specific verb and resource ("Sets a player's avatar, frame and displayed badges") and immediately names the sibling it is not (horizon_get_profile for reading). An agent can distinguish it from the ~30 siblings without opening the schema.

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?

Explicit "Use when: the player confirms a new look" plus a concrete instruction to seed unchanged slots from horizon_get_profile, and a "Not for:" clause naming the alternative. Both the when and the when-not are stated.

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

horizon_signin_anonymousSign In AnonymouslyA

Signs in an anonymous (guest) account with its stored anonymousToken and starts a player session (accessToken). Use when: a returning guest opens the game, or right after horizon_signup_anonymous, before any tool that needs sessionToken. Not for: email accounts (use horizon_signin_email) or creating a guest (use horizon_signup_anonymous). Requires: the anonymousToken returned by horizon_signup_anonymous for this account. Side effects: creates a new session on every call; older sessions stay valid. Returns: {userId, username, accessToken, authStatus, message}. Pass userId and accessToken (as sessionToken) to the session tools; the token stays valid for one hour after its last use. Errors: 404 for an unknown anonymousToken: the account is lost, create a new one with horizon_signup_anonymous. 429 also comes from the per-token limit (5 attempts per minute) and the per-IP limit (30 per minute): wait a minute. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
anonymousTokenYesanonymousToken returned by horizon_signup_anonymous (exactly 32 characters: letters, digits, _ and -)

TDQS

A4.6/5.0
Behavior5/5

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

The annotations already mark this as a non-read-only, non-idempotent, non-destructive, open-world operation. The description goes well beyond them by disclosing session side effects, token lifetime, rate limits, required API key, and error semantics, all consistent with the annotations.

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?

The description is well structured with front-loaded sections for use, exclusions, requirements, side effects, returns, and errors. It is somewhat verbose, however, and the 429 explanation is repeated in the final sentence, slightly diluting conciseness.

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 one-parameter authentication tool with no output schema, the description covers prerequisites, returns, session lifetime, side effects, and common failure modes. An agent has enough information to invoke it correctly and handle expected errors.

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 description coverage is 100%, so the input schema already fully documents anonymousToken, including its exact format and origin. The description adds only a light reminder that the token comes from horizon_signup_anonymous for this account, without extra syntax or usage detail beyond the schema.

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 states a specific verb and resource: signs in an anonymous guest account and starts a player session. It distinguishes itself from siblings by naming horizon_signin_email and horizon_signup_anonymous as adjacent but different operations.

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?

It explicitly says when to use it ('returning guest opens the game', 'right after horizon_signup_anonymous') and when not to use it, naming both alternative tools. The routing guidance is complete enough that an agent can choose correctly without opening other schemas.

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

horizon_signin_emailSign In with EmailA

Signs in an existing email account with email and password and starts a player session (accessToken). Use when: a registered, verified player logs in, before any tool that needs sessionToken (submit score, cloud save, gift code redeem, profile, validated runs). Not for: guest accounts (use horizon_signin_anonymous), new players (use horizon_signup_email) or checking an existing token (use horizon_check_auth). Side effects: creates a new session on every call; older sessions stay valid. Returns: {userId, username, email, accessToken, authStatus, message}. Pass userId and accessToken (as sessionToken) to the session tools; the token stays valid for one hour after its last use. Errors: 401 for a wrong password or unknown email: ask the player to check the credentials. 403 (NOT_VERIFIED) for an unverified email: the player must confirm the verification email first. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
emailYesEmail address the account was registered with (max 40 characters)
passwordYesAccount password (max 128 characters); sent to the API only, never returned

TDQS

A4.6/5.0
Behavior5/5

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

Discloses behavior far beyond the annotations: a new session is created on every call while older sessions stay valid, token lifetime of one hour after last use, HORIZON_API_KEY requirement, 401/403 discrimination, isError semantics on every failure, and the 429 per-minute rate limit. This is a model example of documenting side effects and auth needs.

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?

Front-loaded with the core action, then organized into labeled Use when/Not for/Side effects/Returns/Errors blocks. It is long but dense and well-structured; a few clauses (e.g. the dual-401 explanation) could be tightened, keeping it just short of perfect.

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 non-idempotent, open-world auth tool with no output schema, the description covers purpose, gating, side effects, returned fields, token lifecycle, error codes, and rate limiting. An agent has everything needed to call it and handle outcomes.

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 email and password constraints are already fully documented in the schema. The description only restates that email and password are used and adds post-call guidance (pass userId/accessToken as sessionToken), which is about return usage rather than parameter meaning. Baseline 3 applies.

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?

States a specific verb+resource ('Signs in an existing email account with email and password and starts a player session'), and goes further by naming the return token. It clearly delineates itself from the signup/anonymous/check siblings.

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?

Explicit 'Use when' clause (registered, verified player logs in before any sessionToken-dependent tool) plus a 'Not for' clause that names the exact alternative for each rejected case (horizon_signin_anonymous, horizon_signup_email, horizon_check_auth). Nothing is left to inference.

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

horizon_signup_anonymousSign Up AnonymouslyA

Creates a new anonymous (guest) player account that needs only a display name and returns its anonymousToken. Use when: a player starts without email, for example on first launch of a game with guest play. Not for: players who sign up with email and password (use horizon_signup_email) or returning guests (use horizon_signin_anonymous with the stored anonymousToken). Side effects: creates one new player account per call; calling it again creates another account, it never finds an existing one. Sign-up starts no session. Returns: {userId, username, isAnonymous: true, anonymousToken, createdAt}. Store anonymousToken on the device: it is the only way back into this account. Then call horizon_signin_anonymous to get the accessToken that session tools need. Errors: 400 for an invalid displayName: fix the name and retry. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
displayNameYesDisplay name shown on leaderboards (max 30 characters)

TDQS

A4.7/5.0
Behavior5/5

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

Adds substantial context beyond the annotations: one account created per call with no lookup semantics, no session started, the anonymousToken being the only way back in, the need for HORIZON_API_KEY, and per-status error handling (400/401/429). The annotations already cover non-idempotence and open-world behavior, and the description reinforces and extends that with the retry and storage guidance.

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?

Dense but well partitioned into Use when / Not for / Side effects / Returns / Errors, with the core purpose front-loaded. Every labeled sentence carries unique operational value (idempotence caveat, token storage, error triage) rather than repeating structured fields.

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?

Even without an output schema, the description enumerates the return object fields and the follow-up call (horizon_signin_anonymous) needed for a session. For a low-complexity, 1-param signup tool this leaves no meaningful gap.

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 single displayName parameter (with its 30-char limit) is fully documented by the schema. The description reinforces that only a display name is needed and adds the 400-invalid-name failure mode, but adds no syntax beyond the schema.

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?

States a specific verb and resource ('Creates a new anonymous (guest) player account') plus the exact return artifact ('returns its anonymousToken'). It explicitly distinguishes itself from the email-signup and returning-guest siblings, so an agent can route correctly without opening any schema.

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?

Explicit 'Use when' and 'Not for' clauses name the alternatives (horizon_signup_email, horizon_signin_anonymous with stored token) and the selecting condition (no email / first guest launch). Nothing is left to inference.

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

horizon_signup_emailSign Up with EmailA

Creates a new player account with email, password and display name; the account starts unverified and without a session. Use when: a new player registers with email so the account can be recovered on other devices. Not for: existing accounts (use horizon_signin_email) and guest play without email (use horizon_signup_anonymous). Side effects: creates one player account and sends the verification email. It does not sign in. Returns: the new user with userId and isVerified: false. After the player verified the email address, call horizon_signin_email to get the accessToken. Errors: 409 when the email already belongs to an account: sign in with horizon_signin_email instead. 400 for an invalid email, a password outside 8 to 128 characters or a common password, or a bad name: fix the value and retry. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
emailYesPlayer email address (valid format, max 40 characters); must not be registered yet
passwordYesPassword, 8 to 128 characters; common passwords such as "password1" are rejected. Sent to the API only, never returned
displayNameYesDisplay name shown on leaderboards (max 30 characters)

TDQS

A4.6/5.0
Behavior5/5

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

Adds rich context beyond annotations: account starts unverified/no session, sends a verification email, does not sign in, and it documents error semantics (409, 400, 401, 429) plus required HORIZON_API_KEY. This is far beyond the minimal readOnly/destructive/idempotent hints.

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?

Front-loaded purpose, then structured 'Use when/Not for/Side effects/Returns/Errors' blocks. Well organized, though the error block is dense and could be trimmed slightly.

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 and a mutation tool, the description fully covers return value (userId, isVerified:false), side effects, follow-up workflow, and error handling. Nothing an agent needs to invoke correctly is missing.

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 description coverage is 100%, so the schema already documents email/password/displayName constraints. The description restates some password length limits but adds little new semantic detail beyond the schema's 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?

Specific verb+resource ('Creates a new player account') with scope details ('starts unverified and without a session'). Explicitly distinguishes from siblings horizon_signin_email and horizon_signup_anonymous.

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?

Explicit 'Use when' for new email registrations and 'Not for' naming the two alternatives (signin, anonymous signup). Also gives a follow-up flow when email is already taken.

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

horizon_start_runStart Validated RunA

Starts a server-checked run (Validated Actions): issues a single-use ticket with a server seed and starts the server's run timer. Use when: before a round whose score or earned currency must be checked by the server, and always for boards marked validatedOnly in horizon_list_leaderboards. Not for: normal boards where the client may write its own score (use horizon_submit_score) and reading balances (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Pass leaderboardKey to bind the ticket to a board (it must exist; 'default' is created on first use). Optionally declare the start context (gameVersion, contentVersion, simulationVersion, replayFormatVersion, contentDigest, initialStateBase64); the server binds it with its own start values (rule version, cloud save, balances, seed) into the run, and a sus run keeps it in its review package. Side effects: issues a new ticket per call and counts against the run limits per player and per account; unused tickets simply expire. Returns: {runId, ticket, seed, leaderboardKey, issuedAt, expiresAt, expiresInSeconds}. Seed the game's deterministic randomness with seed, record the input log, then send the result with horizon_submit_validated and the unchanged ticket before expiresAt. Errors: Errors carry a stable code in the body and the error result names it: 400 for a bad context field, 400 INITIAL_STATE_INVALID_ENCODING (initialState not standard base64), 413 INITIAL_STATE_TOO_LARGE (decoded initialState above the plan's evidenceMaxBytes), 401 SESSION_REQUIRED, 403 SESSION_FORBIDDEN, 404 PLAYER_NOT_FOUND or LEADERBOARD_NOT_FOUND, 429 RUN_RATE_LIMITED (per player and hour) or RUN_CAPACITY_REACHED (account per UTC hour; do not retry automatically, the wait can be an hour), 503 VALIDATED_ACTIONS_UNAVAILABLE (server has no ticket key). After 401 sign in again; after 403 SESSION_FORBIDDEN pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
gameVersionNoGame build version, for example "1.4.2" (1 to 64 printable ASCII characters), stored in the run's start context. Optional
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session
contentDigestNoSHA-256 of the game content the run uses, 64 hex characters (sent in lower case). Optional
contentVersionNoVersion of the game content (levels, balancing data) the run uses (1 to 64 printable ASCII characters), stored in the run's start context. Optional
leaderboardKeyNoBoard key to bind the ticket to, from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit for an unbound ticket (currency only runs, or choose the board at submit).
simulationVersionNoVersion of the deterministic simulation that replays the input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional
initialStateBase64NoBytes the simulation starts from as standard base64 (sent as context.initialState); decoded at most the plan's evidenceMaxBytes (32,768 bytes by default). Optional
replayFormatVersionNoFormat version of the recorded input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional

TDQS

A4.8/5.0
Behavior5/5

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

Annotations (non-read-only, non-idempotent, open-world) cover only the safety profile; the description adds the real behavior: a new single-use ticket per call, run limits per player and per account, ticket expiry, server-owned start values bound into the run, and a full error taxonomy with stable codes and remediation for each (401/403/404/429/503). This is well beyond what the annotations provide.

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?

Roughly 350 words, but front-loaded with the core action and then segmented into Use when / Not for / Requires / Side effects / Returns / Errors labels, which makes it scannable. It loses a point for mild redundancy, e.g. 429 handling appearing both in the Errors list and again in the closing rate-limit note.

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?

No output schema exists, yet the return object is enumerated and the follow-through workflow is spelled out (seed deterministic randomness with seed, record the input log, submit with horizon_submit_validated using the unchanged ticket before expiresAt). Nothing needed to call this correctly is missing.

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?

Schema coverage is 100%, so the baseline is 3 and the schema already documents all nine parameters. The description nonetheless adds semantics not in the schema, notably that leaderboardKey binds the ticket to a board that must already exist and that 'default' is created on first use, plus how the optional context fields are consumed server-side.

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?

Opens with a specific verb+resource and mechanism: 'Starts a server-checked run (Validated Actions): issues a single-use ticket with a server seed and starts the server's run timer.' It distinguishes itself from siblings by explicitly naming horizon_submit_score and horizon_get_state as the wrong tools for adjacent needs.

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?

Explicit 'Use when' (before a round whose score or currency must be server-checked; always for boards marked validatedOnly in horizon_list_leaderboards) and explicit 'Not for' with the correct alternatives named. Prerequisites and auth chain are stated, leaving nothing to inference.

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

horizon_submit_feedbackSubmit FeedbackA

Sends a message written by a player (bug report, feature request or comment) to the developer's feedback inbox in the horizOn dashboard. Use when: the player fills in a feedback or bug report form in the game. Not for: crashes and caught exceptions (use horizon_create_crash_report) or technical events the game logs by itself (use horizon_create_log). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: creates one feedback entry per call; a repeat creates a duplicate. Returns: the text "ok" when the entry was stored. Errors: An unknown userId, or one of another API key, is rejected: pass the ID from the sign-in result. 403 when the account's feedback limit is reached: delete old feedback in the dashboard. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
emailNoContact email address for a reply, if the player wants one
titleYesShort summary shown in the dashboard list (1 to 100 characters)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
messageYesFull feedback text (1 to 2048 characters)
categoryNoFree text category (max 50 characters); the horizOn SDKs use BUG, FEATURE and GENERAL. Omit for none
deviceInfoNoDevice and OS details for bug reports, for example 'Pixel 8, Android 14' (max 500 characters)

TDQS

A4.7/5.0
Behavior5/5

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

Although annotations already cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), the description adds substantial context beyond them: one entry per call with duplicates on repeat, the literal 'ok' return, required HORIZON_API_KEY, 403 feedback-limit behavior, and a full error taxonomy including 401 vs 429 diagnosis. This is rich, actionable behavioral disclosure consistent with the annotations.

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?

Labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) make it highly scannable, and the core purpose is front-loaded. Despite its length, each block carries distinct operational information an agent needs.

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 non-idempotent mutation tool with no output schema, the description covers auth requirements, side effects, the return value, and the full failure surface including status-code interpretation. Nothing an agent needs to call it correctly is missing.

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 description coverage is 100%, so the schema already documents all six parameters with formats and length limits. The description reinforces userId provenance (from horizon_signup_*/horizon_signin_*) and the session-token-free requirement, but adds little semantic detail the schema lacks. 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?

States a specific verb and resource ('Sends a message written by a player ... to the developer's feedback inbox') and enumerates the content types (bug report, feature request, comment). It explicitly names the siblings it is not, so an agent can distinguish it from horizon_create_crash_report and horizon_create_log without opening any schema.

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?

Provides an explicit 'Use when' (player fills in a feedback/bug report form) and an explicit 'Not for' with the two alternative tools named for each excluded case. The condition selecting each sibling is spelled out, leaving nothing to inference.

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

horizon_submit_scoreSubmit ScoreA
Idempotent

Submits a player's score to a leaderboard; the board keeps only each player's best score (higher on DESC boards, lower on ASC boards). Use when: a round ends on a normal board. Then call horizon_get_user_rank to show the new position. Not for: boards marked validatedOnly in horizon_list_leaderboards (use horizon_start_run and horizon_submit_validated) and reading scores (use horizon_get_leaderboard_top). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. Side effects: replaces the player's entry only when the new score beats it; a worse or equal score, or the same call again, changes nothing. Returns: {success: true} (also when the score did not beat the best one). Errors: 403 VALIDATED_SUBMIT_REQUIRED on a validatedOnly board, nothing written: switch to horizon_start_run and horizon_submit_validated, do not retry. 403 PLAYER_BANNED when a moderator banned the player from the board: final, do not retry. 404 for an unknown leaderboardKey: list valid keys with horizon_list_leaderboards. 401 means the session is missing or expired: sign in again and retry with the new accessToken. 403 for a session means the token belongs to another user: pass the userId that signed in. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
scoreYesScore to submit, a non-negative integer
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session
leaderboardKeyNoBoard key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board.

TDQS

A4.8/5.0
Behavior5/5

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

Goes well beyond the annotations by disclosing the replace-only-if-better semantics, the auth/session flow, the return value, and a full error taxonomy (403 VALIDATED_SUBMIT_REQUIRED, 403 PLAYER_BANNED, 404, 401, 429) with retry guidance. This is exactly the extra context annotations (idempotentHint=true) cannot convey.

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?

Front-loaded with purpose and organized under labeled clauses (Use when / Not for / Requires / Side effects / Returns / Errors), so it scans well. It is on the long side, but nearly every clause carries actionable content rather than filler.

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?

No output schema exists, yet the description supplies the return shape and the full error/retry matrix, plus the session prerequisite. An agent has everything needed to invoke correctly and handle failures without consulting anything else.

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?

Schema coverage is 100%, so the baseline is 3; the description adds meaning by explaining how sessionToken is obtained (horizon_signin_email/anonymous) and that leaderboardKey can be omitted to use the API key's default board. It doesn't add format detail beyond the schema, but the auth-flow framing is genuinely useful.

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?

States a specific verb+resource ('Submits a player's score to a leaderboard') and immediately disambiguates by board type ('higher on DESC boards, lower on ASC boards'). It clearly distinguishes itself from horizon_submit_validated and the read-oriented siblings.

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?

Provides explicit 'Use when', 'Not for', and 'Requires' sections, naming the alternative tools (horizon_start_run + horizon_submit_validated for validated boards, horizon_get_leaderboard_top for reads). The trigger condition (round ends on a normal board) is unambiguous.

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

horizon_submit_validatedSubmit Validated RunA
Destructive

Submits the result of a run started with horizon_start_run; the server checks ticket and server-only rules before it writes the score and earned values. Use when: a validated run ends: send the ticket, the claimed score (and stage) and the SHA-256 commitment of the input log. Not for: runs without a ticket (use horizon_submit_score on normal boards) and reading balances (use horizon_get_state). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. The ticket from horizon_start_run and exactly one of inputLogHash (a ready SHA-256), inputLogBase64 (raw log bytes, hashed locally) or inputLog (UTF-8 text, hashed locally); the log itself is never sent. score is required when a board is targeted (the ticket's board, or leaderboardKey) and ignored otherwise. Send earned ({key, amount}[]) only when the API key's rules define values: positive amounts earn, negative amounts spend. Side effects: consumes the ticket (single use, also when rejected); an accepted run writes the score (best score kept) and changes the balances of earned values. The same ticket cannot be submitted twice. Returns: {accepted, runId, leaderboardKey, score, bestScore, isNewHighScore, rank, durationSeconds, state, evidence, sus} plus inputLogHash (the hash that was sent). sus is true when the run was accepted but crossed a soft threshold of the rules (the flag names stay on the server); the run counts normally and the server keeps a review package. Rejected runs are never sus; an older server without the field reads as false. state is the player's server-owned values after the run: {day, values: [{key, balance, earnedToday, dailyCap, requested, credited}]}, every value key of the rules sorted by key; requested (amount sent) and credited (amount applied) appear only for the keys in earned. credited < requested on a positive amount means dailyCap or maxBalance clamped it (not an error). For a spend, credited is either requested or 0 (a concurrent run of the same player used the balance first): grant a purchase only when credited == requested. state is null when the rules define no values or the state write failed. evidence is null, or {required: true, runId, uploadBefore, maxBytes} when the server asks for the input log (the run became the player's row and is flagged or lands in the board's evidence top N, or the run is sus): upload exactly the logged bytes with horizon_upload_evidence before uploadBefore (24 hours); a log that was only hashed via inputLogHash must be kept by the caller. Errors: Rejections carry a stable code (never the rule values) and the error result names it: 400 SCORE_REQUIRED (board targeted without score) or PLAYER_NAME_REQUIRED; 401 SESSION_REQUIRED; 403 SESSION_FORBIDDEN, PLAYER_BANNED (banned from the board by a moderator, final; the ticket is not used) or SCORE_LIMIT_REACHED (ticket used up); 404 PLAYER_NOT_FOUND or LEADERBOARD_NOT_FOUND; 422 TICKET_INVALID, TICKET_EXPIRED, TICKET_FOREIGN, TICKET_CONSUMED, LEADERBOARD_MISMATCH; 422 rule codes STAGE_REQUIRED, STAGE_UNKNOWN, SCORE_ABOVE_MAX, SCORE_BELOW_MIN, STAGE_SCORE_ABOVE_MAX, STAGE_SCORE_BELOW_MIN, DURATION_TOO_SHORT, SCORE_RATE_TOO_HIGH and value codes UNKNOWN_VALUE_KEY (key not defined in the rules' values, also when the rules define none), DUPLICATE_VALUE_KEY, EARNED_ABOVE_MAX (above maxPerRun), EARNED_BELOW_MIN (below minPerRun), INSUFFICIENT_BALANCE (spend larger than the balance) (the ticket is consumed, start a new run); 503 VALIDATED_ACTIONS_UNAVAILABLE. After a 422 rule or value code or SCORE_LIMIT_REACHED the ticket is spent; after 401, 404, 429 or 503 the same ticket may be sent again. Local errors (no request sent, ticket kept): INVALID_INPUT_LOG_HASH when the hash input was missing, doubled or malformed, DUPLICATE_VALUE_KEY when earned lists a key twice. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
scoreNoClaimed score (0 to 9007199254740991). Required when a board is targeted, ignored for a run without board.
stageNoStage key for stage rules (for example "level-3")
earnedNoEarned or spent server-owned values ({key, amount}, at most 64, each key once). Every key must be defined in the values of the API key's rules (else UNKNOWN_VALUE_KEY). Omit when the game uses no server-owned values.
ticketYesticket from horizon_start_run, sent unchanged (opaque, about 190 characters, max 512)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
inputLogNoInput log as UTF-8 text; the tool hashes its UTF-8 bytes locally. Use this or inputLogHash or inputLogBase64.
inputLogHashNoSHA-256 of the raw input log bytes, 64 hex characters. Use this or inputLogBase64 or inputLog.
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session
inputLogBase64NoRaw input log bytes as base64; the tool computes the SHA-256 locally. Use this or inputLogHash or inputLog.
leaderboardKeyNoTarget board. Omit to use the board the ticket is bound to; required for a leaderboard write with an unbound ticket.

TDQS

A4.8/5.0
Behavior5/5

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

Far exceeds the annotations (destructiveHint/readOnlyHint/idempotentHint/openWorldHint): it discloses single-use ticket consumption even on rejection, which error classes spend vs. preserve the ticket, the soft-threshold 'sus' flag and review package, dailyCap/maxBalance clamping semantics (credited < requested), the concurrent-spend race where credited==0, and the 24h evidence-upload obligation. This is exactly the behavioral context annotations cannot carry.

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?

Very long, but structured with labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) and front-loaded with the purpose before the routing rules. Given 10 parameters, a stateful ticket lifecycle and dozens of error codes, nearly every sentence earns its place, though some error-code enumeration could be tightened.

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?

With no output schema, the description carries the full return-value burden and does so thoroughly: the response object fields, the meaning of sus, the null state/evidence cases, credited-vs-requested clamping, and the retryability of each HTTP status. Nothing an agent needs to call and interpret this tool correctly is missing.

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?

Schema coverage is already 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema: the log itself is never sent and a hash-only log must be retained by the caller, exactly one of the three log inputs is required, and earned positive/negative amounts map to earn/spend with clamping implications. Score required only when a board is targeted is reinforced with the ignore case.

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?

States a specific verb+resource ('Submits the result of a run started with horizon_start_run') and the server-side validation it triggers. It explicitly distinguishes itself from horizon_submit_score (runs without a ticket) and horizon_get_state (reading balances), so an agent can route without opening a schema.

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?

Has explicit 'Use when', 'Not for' and 'Requires' sections that name the alternatives (horizon_submit_score, horizon_get_state, horizon_signin_*, horizon_upload_evidence) and the exact conditions selecting them. The lifecycle is unambiguous: a validated run ends, send ticket + score + log commitment.

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

horizon_test_connectionTest ConnectionA
Read-onlyIdempotent

Checks that HORIZON_API_KEY and HORIZON_BASE_URL reach the horizOn API by fetching the app's remote configs; takes no input. Use when: first during setup, and whenever other tools fail, to tell a configuration problem from a problem of the call itself. Not for: checking a player's session (use horizon_check_auth) or reading config values for the game (use horizon_get_all_remote_configs). Side effects: None (read only). Returns: {success: true, data} where data holds the app's remote configs; success means key and URL work. Errors: A network error means HORIZON_BASE_URL is wrong or unreachable: check the URL (default https://horizon.pm). Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
successNo

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the annotations (which already declare readOnly, idempotent, open-world and non-destructive), the description discloses the required env vars, the exact failure semantics (401 means bad key, 429 means per-minute rate limit, network error means bad base URL), and the default URL. This is materially more than the annotations convey.

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 and front-loaded with labelled sections (Use when / Not for / Side effects / Returns / Errors) so the agent can scan quickly. It is slightly verbose in the Errors block and repeats the read-only fact already implied by Side effects, so it falls short of maximum conciseness.

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?

Even with an output schema present, the description supplies the auth prerequisite, the success/failure interpretation, and the meaning of key error codes. For a first-run diagnostic in a crowded 33-tool namespace, nothing an agent needs to call it correctly is missing.

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?

The tool takes zero parameters, so the baseline is 4. The description reinforces this with 'takes no input', but there is nothing further to document at the parameter level.

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?

States a specific verb and resource ('Checks that HORIZON_API_KEY and HORIZON_BASE_URL reach the horizOn API by fetching the app's remote configs') and explicitly marks it as a no-input diagnostic. It also distinguishes itself from the two nearest siblings, so the agent can select it without opening either schema.

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?

Gives explicit timing ('first during setup, and whenever other tools fail'), the diagnostic intent ('tell a configuration problem from a problem of the call itself'), and named alternatives for the cases it is not for (horizon_check_auth, horizon_get_all_remote_configs). Nothing is left to inference.

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

horizon_upload_evidenceUpload Validated Run EvidenceA

Uploads the input log of a validated run after horizon_submit_validated answered with evidence.required = true (evidence review). Use when: only when a submit result carries evidence.required: true, before evidence.uploadBefore (24 hours). Not for: runs without an evidence request (the server answers 404 EVIDENCE_NOT_REQUESTED) and sending the log with the submit (the submit takes only its hash). Requires: userId and the player's session: sign in with horizon_signin_email or horizon_signin_anonymous and pass its accessToken as sessionToken. The runId from the submit result and the raw input log as exactly one of inputLogBase64 (raw bytes as base64) or inputLog (UTF-8 text). Its SHA-256 must equal the inputLogHash sent with the run, so pass the same bytes or text that were hashed at submit; at most evidence.maxBytes (32,768 bytes by default). Side effects: stores the log for the developer's review; one upload per run (a second one gets 409). Returns: {runId, status: "UPLOADED", bytes} plus inputLogHash (the SHA-256 of the uploaded bytes, for comparison with the submit). Errors: Errors carry a stable code in the body and the error result names it: 400 EVIDENCE_INVALID_ENCODING (not standard base64), 401 SESSION_REQUIRED, 403 SESSION_FORBIDDEN, 404 EVIDENCE_NOT_REQUESTED (no request for this run and player; also for a run of another player), 409 EVIDENCE_ALREADY_UPLOADED, 410 EVIDENCE_EXPIRED (window passed, slot freed), 413 EVIDENCE_TOO_LARGE (decoded log above maxBytes), 422 EVIDENCE_HASH_MISMATCH (SHA-256 of the log differs from the run's inputLogHash; the request stays open, retry with the correct bytes until uploadBefore), 429 without code (account request limit). Only 422 and network errors are worth a retry; the others are final. Local error (no request sent): INVALID_INPUT_LOG when the log input was missing, doubled, empty or not base64. Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
runIdYesrunId (UUID) from the horizon_submit_validated result (evidence.runId)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*
inputLogNoInput log as UTF-8 text; its UTF-8 bytes are uploaded. Use this or inputLogBase64.
sessionTokenYesaccessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session
inputLogBase64NoRaw input log bytes as standard base64. Use this or inputLog.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare the safety profile (readOnlyHint=false, idempotentHint=false, destructiveHint=false); the description goes well beyond them, disclosing auth prerequisites (signin + accessToken as sessionToken, HORIZON_API_KEY), the one-upload-per-run limit (409), size cap (maxBytes 32,768), rate limiting (429), and a full enumerated error table with retry-worthiness classification. That is exactly the behavioral context annotations cannot carry.

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?

Front-loaded and organized with clear Use when / Not for / Requires / Side effects / Returns / Errors sections, so the agent can scan to what it needs. It is dense and the closing paragraph restates the 401 and 429 semantics already implied above, which is minor redundancy rather than bloat.

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?

There is no output schema, so the description supplies the return shape ({runId, status, bytes, inputLogHash}) and its comparison purpose. Combined with prerequisites, limits, side effects, and error handling, an agent has everything needed to invoke this correctly.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real semantics: the mutual exclusivity of inputLog/inputLogBase64, the requirement that the uploaded bytes' SHA-256 equal the submit's inputLogHash, where each token originates, and a 32,768-byte effective cap that differs from the schema's maxLength. It does not need to do more since the schema documents each field.

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?

States a specific verb and resource ('Uploads the input log of a validated run') and ties it directly to the producing sibling (horizon_submit_validated with evidence.required = true). An agent can distinguish it from submit tools and from unrelated uploads without opening any schema.

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?

Explicit 'Use when' (only after a submit result carries evidence.required: true, before evidence.uploadBefore/24h) and 'Not for' clauses that name the failure the server returns (404 EVIDENCE_NOT_REQUESTED) and the alternative pattern (passing the log with the submit, which only takes a hash). Nothing is left to inference.

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

horizon_validate_gift_codeValidate Gift CodeA
Read-onlyIdempotent

Checks whether a gift code can be redeemed by this player right now, without using it up. Use when: before horizon_redeem_gift_code, for example to confirm a code the player typed and show an error early. Not for: claiming the reward (use horizon_redeem_gift_code; validating alone grants nothing). Requires: a userId from horizon_signup_* or horizon_signin_*; no session token. Side effects: None (read only); no redemption is used. Returns: {valid}. valid false means the code does not exist, has expired, was revoked or reached its limit for this player or in total; tell the player the code does not work. Errors: Needs HORIZON_API_KEY. Every failure returns an error result (isError) with the HTTP status and body: a 401 that horizon_test_connection also returns means HORIZON_API_KEY is wrong, 429 means the account's per-minute rate limit was reached (wait a minute, then retry).

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesGift code as the player typed it (max 50 characters)
userIdYesPlayer user ID (UUID) from horizon_signup_* or horizon_signin_*

Output Schema

ParametersJSON Schema
NameRequiredDescription
validNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent/non-destructive, but the description adds genuinely new behavioral context: no redemption is consumed, no session token is required, the exact error contract (isError with HTTP status/body), how to interpret a 401 vs horizon_test_connection, and 429 rate-limit retry handling. This goes well beyond the structured hints.

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?

Uses labeled sections (Use when / Not for / Requires / Side effects / Returns / Errors) that are strongly front-loaded and skimmable. Despite its length, every sentence carries actionable content with no filler.

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?

Covers prerequisites (userId source), auth requirements (HORIZON_API_KEY), side-effect profile, return interpretation, and error handling. An output schema exists so return details are a bonus rather than a requirement, and the description still clarifies the critical valid=false case.

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 description coverage is 100% and both parameters are already documented in the schema (including the UUID format, pattern, and signup/signin origin). The description restates the userId origin and adds that no session token is needed, but provides no new per-parameter syntax, so the baseline of 3 applies.

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?

States a specific verb ('checks whether...can be redeemed') and resource (gift code), plus explicit scope ('without using it up'). Explicitly distinguishes itself from horizon_redeem_gift_code, so an agent can pick it apart from its sibling without opening either schema.

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?

Provides explicit 'Use when' (before redemption, to confirm a typed code and surface errors early) and 'Not for' (claiming the reward; validating grants nothing) guidance, naming the alternative tool directly. Nothing is left to inference.

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.

  1. 1 tool updatev1.7.0
    • Changedhorizon_start_run6 fields changed
      • addedInput schema / properties / contentDigest
        Added value: +{
        +  "description": "SHA-256 of the game content the run uses, 64 hex characters (sent in lower case). Optional",
        +  "pattern": "^[0-9a-fA-F]{64}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / contentVersion
        Added value: +{
        +  "description": "Version of the game content (levels, balancing data) the run uses (1 to 64 printable ASCII characters), stored in the run's start context. Optional",
        +  "pattern": "^[\\x20-\\x7E]{1,64}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / gameVersion
        Added value: +{
        +  "description": "Game build version, for example \"1.4.2\" (1 to 64 printable ASCII characters), stored in the run's start context. Optional",
        +  "pattern": "^[\\x20-\\x7E]{1,64}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / initialStateBase64
        Added value: +{
        +  "description": "Bytes the simulation starts from as standard base64 (sent as context.initialState); decoded at most the plan's evidenceMaxBytes (32,768 bytes by default). Optional",
        +  "maxLength": 2000000,
        +  "type": "string"
        +}
      • addedInput schema / properties / replayFormatVersion
        Added value: +{
        +  "description": "Format version of the recorded input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional",
        +  "pattern": "^[\\x20-\\x7E]{1,64}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / simulationVersion
        Added value: +{
        +  "description": "Version of the deterministic simulation that replays the input log (1 to 64 printable ASCII characters), stored in the run's start context. Optional",
        +  "pattern": "^[\\x20-\\x7E]{1,64}$",
        +  "type": "string"
        +}
  2. 34 tool updatesv1.6.0
    • Changedhorizon_cancel_email1 field changed
      • changedInput schema / properties / emailId / description
        Previous value: -"ID of the email to cancel (returned by send_email)"New value: +"Email ID (UUID) returned by horizon_send_email"
    • Changedhorizon_check_auth4 fields changed
      • changedInput schema / properties / sessionToken / description
        Previous value: -"accessToken returned by a horizon_signin_* tool (max 256 characters)"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous (max 256 characters)"
      • addedInput schema / properties / sessionToken / minLength
        Added value: +1
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from the result of horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "authStatus": {
        +      "anyOf": [
        +        {
        +          "description": "Server auth status name",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "isAuthenticated": {
        +      "anyOf": [
        +        {
        +          "description": "true when the session is valid",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "message": {
        +      "anyOf": [
        +        {
        +          "description": "Human-readable status message",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "userId": {
        +      "anyOf": [
        +        {
        +          "description": "User ID the session belongs to",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_create_crash_report9 fields changed
      • changedInput schema / properties / breadcrumbs / description
        Previous value: -"Activity trail before the crash (max 50 items)"New value: +"Recent events before the crash, oldest first (max 50)"
      • changedInput schema / properties / breadcrumbs / items / properties / timestamp / description
        Previous value: -"When the event occurred"New value: +"When the event occurred, ISO 8601 (for example 2026-09-29T14:03:12Z)"
      • changedInput schema / properties / customKeys / description
        Previous value: -"Key-value metadata (max 10 entries)"New value: +"String key to string value metadata such as level or build flavor (max 10 entries)"
      • changedInput schema / properties / deviceMemoryMb / description
        Previous value: -"Device RAM in MB"New value: +"Device RAM in MB, for example 8192"
      • changedInput schema / properties / fingerprint / description
        Previous value: -"Grouping key — crashes with the same fingerprint are grouped together (1-128 characters)"New value: +"Grouping key: reports with the same fingerprint form one crash group, for example a hash of exception type and top stack frame (1 to 128 characters)"
      • changedInput schema / properties / message / description
        Previous value: -"Error message (1-5000 characters)"New value: +"Error or exception message (1 to 5000 characters)"
      • changedInput schema / properties / sdkVersion / description
        Previous value: -"horizOn SDK version"New value: +"horizOn SDK version, for example '1.8.2' (1 to 50 characters)"
      • changedInput schema / properties / sessionId / description
        Previous value: -"Session ID from horizon_create_crash_session"New value: +"The sessionId registered with horizon_create_crash_session for this app run (1 to 100 characters)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) who experienced the crash"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in"
    • Changedhorizon_create_crash_session2 fields changed
      • changedInput schema / properties / sessionId / description
        Previous value: -"Unique session identifier (1-100 characters)"New value: +"New unique ID for this app run, for example a UUID generated at start (1 to 100 characters)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) starting the session"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*, if a player is signed in"
    • Changedhorizon_create_log3 fields changed
      • changedInput schema / properties / errorCode / description
        Previous value: -"Error code (max 50 characters)"New value: +"Optional code to group entries in the dashboard, useful with ERROR, for example 'IAP_TIMEOUT' (max 50 characters)"
      • changedInput schema / properties / type / description
        Previous value: -"Log level: INFO, WARN, or ERROR"New value: +"Log level: INFO, WARN or ERROR"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
    • Changedhorizon_get_all_localizations2 fields changed
      • changedInput schema / properties / lang / description
        Previous value: -"ISO 639-1 language code (2 characters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id."New value: +"ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "language": {
        +      "anyOf": [
        +        {
        +          "description": "ISO 639-1 code of the language used",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "total": {
        +      "anyOf": [
        +        {
        +          "description": "Number of translations",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "translations": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": {
        +            "type": "string"
        +          },
        +          "description": "Map of localization key to translated text",
        +          "propertyNames": {
        +            "type": "string"
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_all_remote_configs1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "configs": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": {
        +            "type": "string"
        +          },
        +          "description": "Map of config key to string value",
        +          "propertyNames": {
        +            "type": "string"
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "total": {
        +      "anyOf": [
        +        {
        +          "description": "Number of configs",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_email_status2 fields changed
      • changedInput schema / properties / emailId / description
        Previous value: -"ID of the email to check (returned by send_email)"New value: +"Email ID (UUID) returned by horizon_send_email"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "createdAt": {
        +      "anyOf": [
        +        {
        +          "description": "When the email was queued",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "errorReason": {
        +      "anyOf": [
        +        {
        +          "description": "Why sending failed, null unless failed",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "id": {
        +      "anyOf": [
        +        {
        +          "description": "Email ID",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "language": {
        +      "anyOf": [
        +        {
        +          "description": "Template language",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "processedAt": {
        +      "anyOf": [
        +        {
        +          "description": "When the email was processed, null while pending",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "scheduledAt": {
        +      "anyOf": [
        +        {
        +          "description": "Scheduled send time, null for immediate",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "status": {
        +      "anyOf": [
        +        {
        +          "description": "pending, processing, sent or failed",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "templateSlug": {
        +      "anyOf": [
        +        {
        +          "description": "Template used",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "userId": {
        +      "anyOf": [
        +        {
        +          "description": "Recipient user ID",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_leaderboard_around4 fields changed
      • changedInput schema / properties / leaderboardKey / description
        Previous value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board."
      • changedInput schema / properties / range / description
        Previous value: -"Number of entries around the user (1-50, default 10)"New value: +"How many entries around the player to return, 1 to 50 (default 10)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "entries": {
        +      "anyOf": [
        +        {
        +          "description": "Leaderboard entries in board order",
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "position": {
        +                "anyOf": [
        +                  {
        +                    "description": "1-based position on the board",
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "profile": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": {},
        +                    "description": "The player's displayed cosmetics",
        +                    "properties": {
        +                      "avatarId": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Avatar cosmetic ID, null when not set",
        +                            "type": "string"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      },
        +                      "badges": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Displayed badge cosmetic IDs (0 to 3)",
        +                            "items": {
        +                              "type": "string"
        +                            },
        +                            "type": "array"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      },
        +                      "frameId": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Frame cosmetic ID, null when not set",
        +                            "type": "string"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "score": {
        +                "anyOf": [
        +                  {
        +                    "description": "Best score of the player on this board",
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "username": {
        +                "anyOf": [
        +                  {
        +                    "description": "Player display name",
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_leaderboard_top4 fields changed
      • changedInput schema / properties / leaderboardKey / description
        Previous value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board."
      • changedInput schema / properties / limit / description
        Previous value: -"Number of top entries to return (1-100, default 10)"New value: +"Number of top entries to return, 1 to 100 (default 10)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "entries": {
        +      "anyOf": [
        +        {
        +          "description": "Leaderboard entries in board order",
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "position": {
        +                "anyOf": [
        +                  {
        +                    "description": "1-based position on the board",
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "profile": {
        +                "anyOf": [
        +                  {
        +                    "additionalProperties": {},
        +                    "description": "The player's displayed cosmetics",
        +                    "properties": {
        +                      "avatarId": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Avatar cosmetic ID, null when not set",
        +                            "type": "string"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      },
        +                      "badges": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Displayed badge cosmetic IDs (0 to 3)",
        +                            "items": {
        +                              "type": "string"
        +                            },
        +                            "type": "array"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      },
        +                      "frameId": {
        +                        "anyOf": [
        +                          {
        +                            "description": "Frame cosmetic ID, null when not set",
        +                            "type": "string"
        +                          },
        +                          {
        +                            "type": "null"
        +                          }
        +                        ]
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "score": {
        +                "anyOf": [
        +                  {
        +                    "description": "Best score of the player on this board",
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "username": {
        +                "anyOf": [
        +                  {
        +                    "description": "Player display name",
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_localization4 fields changed
      • changedInput schema / properties / key / description
        Previous value: -"Localization key as defined in the dashboard, e.g. 'ui.play_button' (max 100 characters)"New value: +"Localization key exactly as defined in the dashboard, for example 'ui.play_button' (max 100 characters)"
      • addedInput schema / properties / key / minLength
        Added value: +1
      • changedInput schema / properties / lang / description
        Previous value: -"ISO 639-1 language code (2 characters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id."New value: +"ISO 639-1 language code (2 lowercase letters). One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id. Omit for the app's default language."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "found": {
        +      "anyOf": [
        +        {
        +          "description": "false when the key has no translation",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "language": {
        +      "anyOf": [
        +        {
        +          "description": "ISO 639-1 code of the language used",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "localizationKey": {
        +      "anyOf": [
        +        {
        +          "description": "The requested key",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "value": {
        +      "anyOf": [
        +        {
        +          "description": "The translated text, null when not found",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_localization_languages1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "languages": {
        +      "anyOf": [
        +        {
        +          "description": "ISO 639-1 codes with at least one translation",
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "total": {
        +      "anyOf": [
        +        {
        +          "description": "Number of languages",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_get_news2 fields changed
      • changedInput schema / properties / languageCode / description
        Previous value: -"ISO 639-1 language code (2 characters, e.g. 'en')"New value: +"ISO 639-1 code (2 lowercase letters, for example 'en' or 'de') to return only entries in that language. Omit for all languages"
      • changedInput schema / properties / limit / description
        Previous value: -"Number of news items to return (0-100, default 20)"New value: +"Maximum number of entries to return, 0 to 100 (default 20)"
    • Addedhorizon_get_profile
    • Changedhorizon_get_remote_config3 fields changed
      • changedInput schema / properties / key / description
        Previous value: -"Configuration key as defined in the dashboard, case-sensitive (max 256 characters)"New value: +"Config key exactly as defined in the dashboard, case-sensitive, for example 'max_lives' (max 256 characters)"
      • addedInput schema / properties / key / minLength
        Added value: +1
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "configKey": {
        +      "anyOf": [
        +        {
        +          "description": "The requested key",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "configValue": {
        +      "anyOf": [
        +        {
        +          "description": "The value as a string, null when not found",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "found": {
        +      "anyOf": [
        +        {
        +          "description": "false when the key does not exist",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Addedhorizon_get_state
    • Changedhorizon_get_user_rank3 fields changed
      • changedInput schema / properties / leaderboardKey / description
        Previous value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board."
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "position": {
        +      "anyOf": [
        +        {
        +          "description": "1-based position on the board",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "profile": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": {},
        +          "description": "The player's displayed cosmetics",
        +          "properties": {
        +            "avatarId": {
        +              "anyOf": [
        +                {
        +                  "description": "Avatar cosmetic ID, null when not set",
        +                  "type": "string"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            },
        +            "badges": {
        +              "anyOf": [
        +                {
        +                  "description": "Displayed badge cosmetic IDs (0 to 3)",
        +                  "items": {
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            },
        +            "frameId": {
        +              "anyOf": [
        +                {
        +                  "description": "Frame cosmetic ID, null when not set",
        +                  "type": "string"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            }
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "score": {
        +      "anyOf": [
        +        {
        +          "description": "Best score of the player on this board",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "username": {
        +      "anyOf": [
        +        {
        +          "description": "Player display name",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_list_leaderboards1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "boards": {
        +      "anyOf": [
        +        {
        +          "description": "Boards of the API key",
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "isActive": {
        +                "anyOf": [
        +                  {
        +                    "description": "false when the board is disabled",
        +                    "type": "boolean"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "key": {
        +                "anyOf": [
        +                  {
        +                    "description": "Board key to pass as leaderboardKey",
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "name": {
        +                "anyOf": [
        +                  {
        +                    "description": "Display name",
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "scoreCount": {
        +                "anyOf": [
        +                  {
        +                    "description": "Number of entries",
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "sortOrder": {
        +                "anyOf": [
        +                  {
        +                    "description": "DESC (higher wins) or ASC (lower wins)",
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "validatedOnly": {
        +                "anyOf": [
        +                  {
        +                    "description": "true when only horizon_submit_validated may write scores",
        +                    "type": "boolean"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "totalElements": {
        +      "anyOf": [
        +        {
        +          "description": "Number of boards",
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_load_cloud_data3 fields changed
      • changedInput schema / properties / sessionToken / description
        Previous value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "found": {
        +      "anyOf": [
        +        {
        +          "description": "false when the player never saved",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "saveData": {
        +      "anyOf": [
        +        {
        +          "description": "The stored save string, null when found is false",
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedhorizon_redeem_gift_code5 fields changed
      • changedInput schema / properties / code / description
        Previous value: -"Gift code to redeem (max 50 characters)"New value: +"Gift code as the player typed it (max 50 characters)"
      • addedInput schema / properties / code / minLength
        Added value: +1
      • addedInput schema / properties / sessionToken
        Added value: +{
        +  "description": "accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session",
        +  "maxLength": 256,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedInput schema / required
        Previous value: -[
        -  "code",
        -  "userId"
        -]New value: +[
        +  "code",
        +  "userId",
        +  "sessionToken"
        +]
    • Changedhorizon_save_cloud_data3 fields changed
      • changedInput schema / properties / data / description
        Previous value: -"Save data string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)"New value: +"The complete save as a string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)"
      • changedInput schema / properties / sessionToken / description
        Previous value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
    • Changedhorizon_send_email5 fields changed
      • changedInput schema / properties / language / description
        Previous value: -"ISO 639-1 language code for template rendering (e.g. 'en', 'de')"New value: +"ISO 639-1 code (2 lowercase letters) of the template translation to render, for example 'en' or 'de'"
      • changedInput schema / properties / scheduledAt / description
        Previous value: -"ISO 8601 timestamp for scheduled delivery. Omit to send immediately."New value: +"ISO 8601 timestamp for delayed delivery, at most 30 days ahead, for example 2026-10-01T09:00:00Z. Omit to send immediately"
      • changedInput schema / properties / templateSlug / description
        Previous value: -"Slug of the email template (e.g. 'welcome', 'reminder')"New value: +"Slug of an email template defined in the dashboard, for example 'welcome' or 'reminder'"
      • changedInput schema / properties / userId / description
        Previous value: -"horizOn user ID of the recipient"New value: +"Player user ID (UUID) of the recipient; the player needs a verified email address"
      • changedInput schema / properties / variables / description
        Previous value: -"Template variable values as key-value pairs (e.g. {\"username\": \"John\"})"New value: +"Values for the template's variables as a string map, for example {\"username\": \"John\"}; pass {} when the template has none"
    • Addedhorizon_set_profile
    • Changedhorizon_signin_anonymous3 fields changed
      • changedInput schema / properties / anonymousToken / description
        Previous value: -"anonymousToken returned by horizon_signup_anonymous (max 32 characters)"New value: +"anonymousToken returned by horizon_signup_anonymous (exactly 32 characters: letters, digits, _ and -)"
      • addedInput schema / properties / anonymousToken / minLength
        Added value: +32
      • addedInput schema / properties / anonymousToken / pattern
        Added value: +"^[A-Za-z0-9_-]+$"
    • Changedhorizon_signin_email5 fields changed
      • changedInput schema / properties / email / description
        Previous value: -"Email address"New value: +"Email address the account was registered with (max 40 characters)"
      • addedInput schema / properties / email / maxLength
        Added value: +40
      • changedInput schema / properties / password / description
        Previous value: -"Password"New value: +"Account password (max 128 characters); sent to the API only, never returned"
      • addedInput schema / properties / password / maxLength
        Added value: +128
      • addedInput schema / properties / password / minLength
        Added value: +1
    • Changedhorizon_signup_anonymous1 field changed
      • changedInput schema / properties / displayName / description
        Previous value: -"Display name for the anonymous user (max 30 characters)"New value: +"Display name shown on leaderboards (max 30 characters)"
    • Changedhorizon_signup_email5 fields changed
      • changedInput schema / properties / displayName / description
        Previous value: -"Display name (max 30 characters)"New value: +"Display name shown on leaderboards (max 30 characters)"
      • changedInput schema / properties / email / description
        Previous value: -"Email address (max 40 characters)"New value: +"Player email address (valid format, max 40 characters); must not be registered yet"
      • changedInput schema / properties / password / description
        Previous value: -"Password (4-32 characters)"New value: +"Password, 8 to 128 characters; common passwords such as \"password1\" are rejected. Sent to the API only, never returned"
      • changedInput schema / properties / password / maxLength
        Previous value: -32New value: +128
      • changedInput schema / properties / password / minLength
        Previous value: -4New value: +8
    • Addedhorizon_start_run
    • Changedhorizon_submit_feedback6 fields changed
      • changedInput schema / properties / category / description
        Previous value: -"Feedback category, free text such as BUG, FEATURE or GENERAL (max 50 characters)"New value: +"Free text category (max 50 characters); the horizOn SDKs use BUG, FEATURE and GENERAL. Omit for none"
      • changedInput schema / properties / deviceInfo / description
        Previous value: -"Device information (max 500 characters)"New value: +"Device and OS details for bug reports, for example 'Pixel 8, Android 14' (max 500 characters)"
      • changedInput schema / properties / email / description
        Previous value: -"Contact email address"New value: +"Contact email address for a reply, if the player wants one"
      • changedInput schema / properties / message / description
        Previous value: -"Feedback message (1-2048 characters)"New value: +"Full feedback text (1 to 2048 characters)"
      • changedInput schema / properties / title / description
        Previous value: -"Feedback title (1-100 characters)"New value: +"Short summary shown in the dashboard list (1 to 100 characters)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
    • Changedhorizon_submit_score4 fields changed
      • changedInput schema / properties / leaderboardKey / description
        Previous value: -"Leaderboard key — selects a named board on the API key. Omit to use the default board."New value: +"Board key from horizon_list_leaderboards (1 to 64 characters: a-z, 0-9, _ and -). Omit to use the API key's default board."
      • changedInput schema / properties / score / description
        Previous value: -"Score to submit (non-negative integer)"New value: +"Score to submit, a non-negative integer"
      • changedInput schema / properties / sessionToken / description
        Previous value: -"accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session"New value: +"accessToken from horizon_signin_email or horizon_signin_anonymous for this userId; sent as a Bearer session"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
    • Addedhorizon_submit_validated
    • Changedhorizon_test_connection1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "data": {
        +      "anyOf": [
        +        {
        +          "description": "The app's remote configs as returned by the API"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "success": {
        +      "anyOf": [
        +        {
        +          "description": "true when the API key and base URL work",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Addedhorizon_upload_evidence
    • Changedhorizon_validate_gift_code4 fields changed
      • changedInput schema / properties / code / description
        Previous value: -"Gift code to validate (max 50 characters)"New value: +"Gift code as the player typed it (max 50 characters)"
      • addedInput schema / properties / code / minLength
        Added value: +1
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"New value: +"Player user ID (UUID) from horizon_signup_* or horizon_signin_*"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "valid": {
        +      "anyOf": [
        +        {
        +          "description": "true when the player can redeem the code now",
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
  3. 14 tool updatesv1.5.5
    • Changedhorizon_check_auth2 fields changed
      • changedInput schema / properties / sessionToken / description
        Previous value: -"Session token (max 256 characters)"New value: +"accessToken returned by a horizon_signin_* tool (max 256 characters)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_create_log1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_get_leaderboard_around1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_get_leaderboard_top1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_get_localization1 field changed
      • changedInput schema / properties / key / description
        Previous value: -"Localization key (max 100 characters)"New value: +"Localization key as defined in the dashboard, e.g. 'ui.play_button' (max 100 characters)"
    • Changedhorizon_get_remote_config1 field changed
      • changedInput schema / properties / key / description
        Previous value: -"Configuration key (max 256 characters)"New value: +"Configuration key as defined in the dashboard, case-sensitive (max 256 characters)"
    • Changedhorizon_get_user_rank1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_load_cloud_data3 fields changed
      • addedInput schema / properties / sessionToken
        Added value: +{
        +  "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session",
        +  "maxLength": 256,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
      • changedInput schema / required
        Previous value: -[
        -  "userId"
        -]New value: +[
        +  "userId",
        +  "sessionToken"
        +]
    • Changedhorizon_redeem_gift_code1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_save_cloud_data4 fields changed
      • changedInput schema / properties / data / description
        Previous value: -"Save data string (max 300,000 characters)"New value: +"Save data string, usually serialized JSON (max 300,000 characters; the tier limit is usually lower)"
      • addedInput schema / properties / sessionToken
        Added value: +{
        +  "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session",
        +  "maxLength": 256,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
      • changedInput schema / required
        Previous value: -[
        -  "userId",
        -  "data"
        -]New value: +[
        +  "userId",
        +  "data",
        +  "sessionToken"
        +]
    • Changedhorizon_signin_anonymous1 field changed
      • changedInput schema / properties / anonymousToken / description
        Previous value: -"Anonymous token (max 32 characters)"New value: +"anonymousToken returned by horizon_signup_anonymous (max 32 characters)"
    • Changedhorizon_submit_feedback2 fields changed
      • changedInput schema / properties / category / description
        Previous value: -"Feedback category (max 50 characters)"New value: +"Feedback category, free text such as BUG, FEATURE or GENERAL (max 50 characters)"
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
    • Changedhorizon_submit_score3 fields changed
      • addedInput schema / properties / sessionToken
        Added value: +{
        +  "description": "accessToken returned by horizon_signin_email or horizon_signin_anonymous for this user; sent as a Bearer session",
        +  "maxLength": 256,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
      • changedInput schema / required
        Previous value: -[
        -  "userId",
        -  "score"
        -]New value: +[
        +  "userId",
        +  "score",
        +  "sessionToken"
        +]
    • Changedhorizon_validate_gift_code1 field changed
      • changedInput schema / properties / userId / description
        Previous value: -"User ID (UUID)"New value: +"User ID (UUID) returned by a horizon_signup_* or horizon_signin_* tool"
  4. 28 tool updatesv1.5.4
    • First observedhorizon_cancel_email
    • First observedhorizon_check_auth
    • First observedhorizon_create_crash_report
    • First observedhorizon_create_crash_session
    • First observedhorizon_create_log
    • First observedhorizon_get_all_localizations
    • First observedhorizon_get_all_remote_configs
    • First observedhorizon_get_email_status
    • First observedhorizon_get_leaderboard_around
    • First observedhorizon_get_leaderboard_top
    • First observedhorizon_get_localization
    • First observedhorizon_get_localization_languages
    • First observedhorizon_get_news
    • First observedhorizon_get_remote_config
    • First observedhorizon_get_user_rank
    • First observedhorizon_list_leaderboards
    • First observedhorizon_load_cloud_data
    • First observedhorizon_redeem_gift_code
    • First observedhorizon_save_cloud_data
    • First observedhorizon_send_email
    • First observedhorizon_signin_anonymous
    • First observedhorizon_signin_email
    • First observedhorizon_signup_anonymous
    • First observedhorizon_signup_email
    • First observedhorizon_submit_feedback
    • First observedhorizon_submit_score
    • First observedhorizon_test_connection
    • First observedhorizon_validate_gift_code

TDQS

A4.4/5.0

Scored across 34 tools

Disambiguation5/5

Every tool targets a distinct resource plus action across auth, leaderboards, cloud saves, remote config, localization, news, gift codes, profile, validated runs/evidence, feedback, logs, crash reporting and email. The detailed 'Use when / Not for' notes explicitly separate the few near-neighbors (submit_score vs submit_validated, get_remote_config vs get_all_remote_configs, get_leaderboard_top vs get_leaderboard_around vs get_user_rank, validate vs redeem gift code).

Naming Consistency5/5

All 34 tools share the horizon_ prefix and a consistent snake_case verb_noun pattern (get_, list_, create_, submit_, set_, cancel_, etc.). The only minor quirk is compound verbs like signup_anonymous/signin_email, but they are still uniform across the set.

Tool Count3/5

34 tools is heavy by count, yet the server spans roughly 14 distinct feature areas (auth, leaderboards, cloud save, remote config, localization, news, gift codes, profile, validated runs, evidence, feedback, logging, crash reporting, email), so most tools earn their place. Some consolidation is possible (the one/all config and localization pairs), so it sits at the borderline rather than clearly well-scoped.

Completeness4/5

The surface covers the full player-facing lifecycle for each feature area: signup/signin/check, leaderboard list/submit/top/rank/around, cloud save/load, config and localization reads, gift validate/redeem, profile get/set, validated run start/submit/evidence, feedback, logging, crash session/report, and email send/cancel/status. Minor gaps remain (no read/list for feedback, logs, crash groups or queued emails, no password reset or email verification, no session revoke or cloud-save delete), but these are dashboard-side or workable.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to interact with Godot game projects through real-time error detection, automated testing, code analysis, and safe git-based patching. Provides comprehensive project context and development workflow automation for Godot developers.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides a comprehensive integration between LLMs and the Godot Engine, enabling AI assistants to intelligently manipulate project files, scripts, and the live editor. It supports advanced workflows including version-aware documentation querying, automated E2E game testing, and real-time visual context capture.
    9 npm
    26
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides AI assistants with access to the complete Godot Engine documentation, enabling developers to get answers about Godot classes, tutorials, and features directly in their chat interface.
    73
    MIT
  • A
    license
    C
    quality
    C
    maintenance
    Enables AI agents to interact with the Godot game engine, including project inspection, scene/script parsing, headless exports, runtime control with live scene-tree inspection and evaluation, and API documentation search.
    100
    320 npm
    4
    MIT