Server definition
- Hash
- sha256:a92a4c1e7214e42733c78d692aff789c8b162eb4947bf381ae13b8e6a1c95ab1
- What it is
- What a remote MCP server returned when asked what it offers: 57 tools
The blob, as servednamed by its sha256
{
"instructions": null,
"tools": [
{
"description": "Archive an app nobody uses: its data is bundled onto the CDN and cleared from Neblla's database. It stays in the gallery and is restored automatically the next time anyone opens it (first open is slower). Neblla also does this on its own for long-unused apps.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_archive_app",
"outputSchema": null
},
{
"description": "Read the message banned players see in this app, or change it by passing `defaultMessage`.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"defaultMessage": {
"description": "New message shown to banned players",
"maxLength": 1000,
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_ban_settings",
"outputSchema": null
},
{
"description": "Bring-your-own-database: move where this app stores its players' data (saves, rooms, community) from Neblla's default store to the developer's own database. Actions: \"status\" (current engine + migration progress); \"validate\" (engine + config, tests the connection, changes nothing); \"migrate\" (validates again, then starts a 3-phase background migration of ALL player data — confirm with the developer first); \"cancel\" (only before the last phase). Engines and config: mongo {uri, dbName}, turso {url, authToken}, postgres {uri}, mysql {uri}. Credentials are stored encrypted and never returned.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"status",
"validate",
"migrate",
"cancel"
],
"type": "string"
},
"appId": {
"description": "The app public ID",
"type": "string"
},
"config": {
"additionalProperties": true,
"description": "For validate / migrate: the connection settings of the engine",
"properties": {},
"type": "object"
},
"engine": {
"description": "For validate / migrate",
"enum": [
"mongo",
"turso",
"postgres",
"mysql"
],
"type": "string"
}
},
"required": [
"appId",
"action"
],
"type": "object"
},
"name": "neblla_byodb",
"outputSchema": null
},
{
"description": "Consume units of a player's purchased product from the backoffice (e.g. refund-by-hand, support fixes). Atomic: fails with insufficient_amount if the player has fewer units. The player's game gets a live `purchase` event.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"amount": {
"description": "Units to consume (default 1)",
"minimum": 1,
"type": "integer"
},
"appId": {
"description": "The app public ID",
"type": "string"
},
"productName": {
"description": "Product id (A-Z a-z 0-9 _ -, max 64)",
"type": "string"
},
"userId": {
"description": "The player's `_id` from neblla_list_users",
"type": "string"
}
},
"required": [
"appId",
"userId",
"productName"
],
"type": "object"
},
"name": "neblla_consume_purchase",
"outputSchema": null
},
{
"description": "Copy the behavioural settings (features, rooms policy, matchmaking, inbox, p2p, serverMode, permissions, theme, connections, ai…) from one of your apps onto another. Name, files, domains, slug, gallery and billing are never copied. Overwrites those settings on the target — confirm first.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "Target app (gets the settings)",
"type": "string"
},
"fromAppId": {
"description": "Source app (settings are read from it)",
"type": "string"
}
},
"required": [
"appId",
"fromAppId"
],
"type": "object"
},
"name": "neblla_copy_app_config",
"outputSchema": null
},
{
"description": "Create a new Neblla app. Returns the app ID (appId) to use in subsequent file upload operations. \n\nRecommended flow for a NEW app: 1) Call neblla_validate_requirements with the decisions you can infer from the request — it walks the same decision map as the dashboard wizard; answer what you can yourself, ask the user only what it flags, repeat until have_enough_context. 2) Call neblla_get_llms to read the SDK reference (the core section at minimum). 3) Call neblla_create_app (this tool) with the display name AND the validated `decisions` — that scaffolds the matching pattern with a themed UI piece per enabled feature (login, store, AI box, friends, inbox…) and writes the full app config, so you only EDIT files instead of writing from scratch. Omit `decisions` only if you genuinely want a blank app (just index.html). 4) Edit/replace the scaffolded files (or upload new ones). The server-side files live under server/ — index.html references only main.css and client.js (NEVER the server/ files — the SDK loads them); client.js wraps code in window.onNeblla; the server/ files are top-level code with no DOM access; client and server communicate only via events (tellServer / tellPresenter / sendMessage / setState / on('messageToServer'|'messageFromServer'|'message'|'state')). 5) Call neblla_get_app_url(appId) to get the correct public URL — NEVER construct it manually. Apps are served at play.neblla.com/<slug>, not under any /apps/ path.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"decisions": {
"additionalProperties": {},
"description": "The COMPLETE decision set from neblla_validate_requirements (have_enough_context: true → pass its `decisions` verbatim). Scaffolds the matching pattern with the themed UI pieces for each enabled feature AND writes the app config (features, connections, serverMode, rooms policy, matchmaking mode, AI payer, theme). The recommended way to create any non-blank app.",
"type": "object"
},
"name": {
"description": "Display name for the app",
"minLength": 1,
"type": "string"
},
"serverMode": {
"description": "Where the server/ files run: \"js\" (default — plain JS on a connected peer), \"wasm\" (AssemblyScript .ts → WASM on a peer, opaque to DevTools), or \"infra\" (JS on a Neblla worker per room — Beta — for ranked/real-money). The template is scaffolded in JS for \"js\"/\"infra\" and in AssemblyScript for \"wasm\". Most apps want \"js\". With `decisions`, omit — it is derived.",
"enum": [
"js",
"wasm",
"infra"
],
"type": "string"
},
"template": {
"description": "Legacy alternative to `decisions`: scaffold the six canonical files wired to this pattern, with no feature pieces and no theme. Prefer `decisions`. Omit both for a blank app.",
"enum": [
"turn-based",
"host-controllers",
"collab-realtime",
"solo-save"
],
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "neblla_create_app",
"outputSchema": null
},
{
"description": "Create a purchasable product for a Neblla app. type must be \"one_time\" (single purchase, fixed price) or \"consumable\" (quantity selector, price per unit). name should be a multi-language object e.g. { en: \"Gold Coins\", es: \"Monedas de Oro\" }. price (one_time) and pricePerUnit (consumable) are in cents (e.g. 499 = $4.99).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"currency": {
"description": "ISO 4217 code, e.g. \"eur\" (default usd)",
"pattern": "^[a-zA-Z]{3}$",
"type": "string"
},
"defaultLang": {
"enum": [
"en",
"es",
"fr",
"de",
"it",
"pt",
"ja",
"ko",
"zh",
"ar"
],
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
],
"description": "Description, string or per-language object"
},
"image": {
"description": "Product image URL",
"type": "string"
},
"max": {
"description": "Maximum quantity for consumable",
"type": "number"
},
"min": {
"description": "Minimum quantity for consumable",
"type": "number"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
],
"description": "Product name, string or { en: \"...\", es: \"...\" }"
},
"price": {
"description": "Price in cents — required for one_time",
"type": "number"
},
"pricePerUnit": {
"description": "Price per unit in cents — required for consumable",
"type": "number"
},
"published": {
"description": "Buyable right away (default true; forced false until Stripe Connect is active)",
"type": "boolean"
},
"step": {
"description": "Quantity step for consumable selector",
"type": "number"
},
"type": {
"enum": [
"one_time",
"consumable"
],
"type": "string"
}
},
"required": [
"appId",
"name",
"type"
],
"type": "object"
},
"name": "neblla_create_product",
"outputSchema": null
},
{
"description": "Create a predefined room (it exists before anyone joins). Name: A-Z 0-9 _ - (stored uppercase); LOBBY is reserved. `permanent: true` keeps it (and its data) when it empties.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"moderators": {
"description": "Per-app user ids that moderate this room",
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"description": "Room name",
"type": "string"
},
"permanent": {
"description": "Keep the room when empty",
"type": "boolean"
}
},
"required": [
"appId",
"name"
],
"type": "object"
},
"name": "neblla_create_room",
"outputSchema": null
},
{
"description": "For safety the MCP never deletes accounts directly. Returns a URL for the user to visit and confirm deletion from the Neblla dashboard.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {},
"type": "object"
},
"name": "neblla_delete_account",
"outputSchema": null
},
{
"description": "Permanently delete an app and all its files.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_delete_app",
"outputSchema": null
},
{
"description": "Permanently remove a communication from a user's thread. The end user is notified via a `communicationDeleted` socket event so their UI updates in real time.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"commId": {
"description": "Communication id to delete",
"type": "string"
},
"userId": {
"description": "User's mongo ObjectId hex string",
"type": "string"
}
},
"required": [
"appId",
"userId",
"commId"
],
"type": "object"
},
"name": "neblla_delete_communication",
"outputSchema": null
},
{
"description": "Delete a single file from an app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"path": {
"description": "File path to delete, e.g. \"old-page.html\"",
"type": "string"
}
},
"required": [
"appId",
"path"
],
"type": "object"
},
"name": "neblla_delete_file",
"outputSchema": null
},
{
"description": "Permanently delete a product from a Neblla app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"productId": {
"description": "The product ID returned by neblla_create_product",
"type": "string"
}
},
"required": [
"productId"
],
"type": "object"
},
"name": "neblla_delete_product",
"outputSchema": null
},
{
"description": "Delete a persistent room and its stored data. If people are inside it right now the session continues and the room disappears when it empties. LOBBY cannot be deleted. Irreversible — confirm with the developer first.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"name": {
"description": "Room name",
"type": "string"
}
},
"required": [
"appId",
"name"
],
"type": "object"
},
"name": "neblla_delete_room",
"outputSchema": null
},
{
"description": "Delete (soft) one chat message from a room, as the developer. Players see it removed.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"messageId": {
"description": "Message id from neblla_get_room_history",
"type": "string"
}
},
"required": [
"appId",
"messageId"
],
"type": "object"
},
"name": "neblla_delete_room_message",
"outputSchema": null
},
{
"description": "Add an email to the developer's account (it stays pending until its inbox owner clicks the confirmation link), or resend that confirmation. Removing emails and changing the primary one are done in the web dashboard.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"add",
"resend_confirmation"
],
"type": "string"
},
"email": {
"format": "email",
"type": "string"
}
},
"required": [
"action",
"email"
],
"type": "object"
},
"name": "neblla_developer_email",
"outputSchema": null
},
{
"description": "Read the developer's profile (name shown as app owner, dashboard language, whether a Claude API key is saved, emails on the account) or change `name` / `lang`. Changing the name also updates the owner name on all their apps.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"lang": {
"description": "Dashboard language",
"enum": [
"en",
"es",
"fr",
"de",
"it",
"pt",
"ja",
"ko",
"zh",
"ar"
],
"type": "string"
},
"name": {
"description": "New display name",
"maxLength": 50,
"type": "string"
}
},
"type": "object"
},
"name": "neblla_developer_profile",
"outputSchema": null
},
{
"description": "Drafts: a private copy of an app (id \"_<appId>\") to change files and settings without touching the live app. \"info\" says whether one exists; \"create\" makes it (edit it by passing its id to the file/app tools); \"apply\" promotes the draft over the live app (replaces its files and settings — confirm first; a rooms change that loses data needs confirmRoomsChange); \"discard\" deletes the draft.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"info",
"create",
"apply",
"discard"
],
"type": "string"
},
"appId": {
"description": "The LIVE (master) app id",
"type": "string"
},
"confirmRoomsChange": {
"description": "For \"apply\": accept a rooms change that discards saved rooms data",
"type": "boolean"
}
},
"required": [
"appId",
"action"
],
"type": "object"
},
"name": "neblla_draft",
"outputSchema": null
},
{
"description": "Everything about ONE app: its full config and state (features, rooms, quota and credits today, subscription, gallery, community, ai…), every URL it answers at (by id and slug on each Neblla host and its Cloudflare deploy), the custom domains registered, and whether a TURN relay is available for the P2P \"media\" option.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_get_app",
"outputSchema": null
},
{
"description": "Returns the canonical public URL for a Neblla app in the gallery. ALWAYS call this after neblla_create_app — never construct the URL yourself. Apps are published and browsed at play.neblla.com. The URL format is https://play.neblla.com/<slug>, where <slug> is auto-generated from the app name at creation time and can be renamed in the dashboard.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_get_app_url",
"outputSchema": null
},
{
"description": "The app's resolved community configuration (mode, who publishes, limits, categories, content types, report threshold) plus how much of its community storage cap is used.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_get_community_config",
"outputSchema": null
},
{
"description": "Fetch one community entry WITH its payload (the dev-defined JSON), whatever its status, plus its user reports (open count, count by reason, and each report with an opaque reporter id). Stats carry favorites, rating and reviews.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"entryId": {
"description": "The entry id",
"type": "string"
}
},
"required": [
"appId",
"entryId"
],
"type": "object"
},
"name": "neblla_get_community_entry",
"outputSchema": null
},
{
"description": "Get the content of a specific file. Text files (HTML, CSS, JS, JSON, SVG, plain text) are ALWAYS returned as UTF-8 strings — never base64. Binary files (images, fonts, audio) are returned as base64. The response includes an `encoding` field (\"utf8\" or \"base64\") so you know how to interpret `content`. Always returns the real current source, including for apps you created or published in a previous session. Use this to resume editing an existing app across sessions.\n\nLarge files are returned in CHUNKS — `content` may be only PART of the file. After each call, check `hasMore`: if true, call this tool again with `offset` set to the returned `nextOffset`, then concatenate the chunks in order. Decode (for binary) or edit only the FULLY reassembled string. `totalLength` is the total length of `content` across all chunks; `length` is this chunk's length.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"maxLength": {
"default": 20000,
"description": "Maximum length of `content` to return in this chunk. The default (20000) stays comfortably under the response-size limit of MCP clients; lower it further if your client still truncates the reply.",
"maximum": 65536,
"minimum": 1024,
"type": "integer"
},
"offset": {
"default": 0,
"description": "Where to start reading, in units of the returned `content` (characters for utf8 text, base64 characters for binary). 0 = start of file. Pass the previous response's `nextOffset` to get the next chunk.",
"minimum": 0,
"type": "integer"
},
"path": {
"description": "File path, e.g. \"index.html\"",
"type": "string"
}
},
"required": [
"appId",
"path"
],
"type": "object"
},
"name": "neblla_get_file",
"outputSchema": null
},
{
"description": "Fetch the Neblla developer guide (llms.txt), split by topic so you read only what the app uses. Call this BEFORE designing or writing any code for a Neblla app — at minimum the `core` section (the default): the canonical six-file structure, the events-only client/server contract, and the five app patterns. Then fetch the sections matching the features you enabled: salas (rooms, lobby, matchmaking), servidor (the 3 server modes, setState, anti-cheat), identidad (login/SSO/scopes/save), social (friends + dev↔user communications), comunidad (user-published entries: neblla.community, moderation), pagos (products/Stripe), ia (neblla.ai routes), publicar (gallery + quota table), referencia (the full API/events tables), mcp (this server's tools + creation flow), index (the table of contents), full (everything at once). Skipping core risks producing incorrect Neblla apps.\n\nEach response lists the available `sections`. Most sections fit in one response; for long ones check `hasMore` and re-call with `offset` = `nextOffset`, concatenating chunks in order.\n\nSTALENESS CHECK — you connected to Neblla build 36. Each response carries the LIVE `latestBuild`. If `latestBuild` is greater than 36 (the build noted here), the server was redeployed AFTER you connected, so your loaded Neblla tool list is STALE. In that case, tell the developer plainly: \"⚠️ The Neblla MCP updated to build <latestBuild> since this session started (you are on build 36). Restart/reconnect Claude Code to get the latest tools.\"",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"maxLength": {
"default": 20000,
"description": "Maximum length of `guide` to return in this chunk. The default stays under the response-size limit of MCP clients.",
"maximum": 65536,
"minimum": 1024,
"type": "integer"
},
"offset": {
"default": 0,
"description": "Character position to start reading from. 0 = start. Pass the previous response's `nextOffset` for the next chunk.",
"minimum": 0,
"type": "integer"
},
"section": {
"default": "core",
"description": "Which part of the guide to read. Default \"core\" — the mandatory contract. \"index\" = table of contents, \"full\" = the whole guide.",
"enum": [
"index",
"full",
"core",
"salas",
"servidor",
"identidad",
"social",
"comunidad",
"pagos",
"ia",
"publicar",
"referencia",
"mcp"
],
"type": "string"
}
},
"type": "object"
},
"name": "neblla_get_llms",
"outputSchema": null
},
{
"description": "Read a room's chat history (newest first, paginated) for moderation. Returns the players' messages in clear: only use it when the developer asks to review a room.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"before": {
"description": "Pagination cursor: the id/date of the oldest message already seen",
"type": "string"
},
"limit": {
"description": "Messages per page (default 50)",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"name": {
"description": "Room name",
"type": "string"
}
},
"required": [
"appId",
"name"
],
"type": "object"
},
"name": "neblla_get_room_history",
"outputSchema": null
},
{
"description": "Fetch the full record of a single end user — their saved data, public info, purchases, and communications thread. Use the `_id` from neblla_list_users / neblla_search_users_by_email as `userId`.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"userId": {
"description": "The user's mongo ObjectId hex string (the `_id` returned by neblla_list_users)",
"type": "string"
}
},
"required": [
"appId",
"userId"
],
"type": "object"
},
"name": "neblla_get_user",
"outputSchema": null
},
{
"description": "Keep an app files in sync with a GitHub repo. The repo becomes the source of truth: editing the app files in Neblla is blocked while linked (edit in the repo and push). Actions: \"repos\" — the developer GitHub repos (needs \"Sign in with GitHub\"); \"branches\" (url) — branches of a repo; \"status\"; \"link\" (url, optional branch, subdir, syncMode manual|auto, token only if the developer has not signed in with GitHub) — first sync, and in auto mode the push webhook is registered automatically when GitHub is linked; \"sync\" — pull now (only changed files are downloaded); \"set_mode\" manual|auto; \"test_branch\" (branch, or null to remove) — a private copy <appId>_test with the same settings that follows another branch, never in the gallery; \"unlink\". Each pull costs quota credits.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"repos",
"branches",
"status",
"link",
"sync",
"set_mode",
"test_branch",
"unlink"
],
"type": "string"
},
"appId": {
"description": "The app public ID (not needed for \"repos\" / \"branches\")",
"type": "string"
},
"branch": {
"description": "For link: live branch (default: the repo default); for test_branch: the test branch, null removes it",
"type": [
"string",
"null"
]
},
"subdir": {
"description": "For link: folder inside the repo that holds the app (default \"dist\"; \"\" = repo root)",
"type": "string"
},
"syncMode": {
"description": "For link / set_mode",
"enum": [
"manual",
"auto"
],
"type": "string"
},
"token": {
"description": "For link: GitHub token, only if the developer has not signed in with GitHub (stored encrypted, never returned)",
"type": "string"
},
"url": {
"description": "For link / branches: https://github.com/<owner>/<repo>",
"type": "string"
}
},
"required": [
"action"
],
"type": "object"
},
"name": "neblla_git",
"outputSchema": null
},
{
"description": "List all apps owned by the authenticated developer.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {},
"type": "object"
},
"name": "neblla_list_apps",
"outputSchema": null
},
{
"description": "List communications across ALL users of an app, filtered and sorted. The most useful tool for triaging an inbox: show only unread, only messages from users (not the dev), only flagged-important, or only those mentioning a given email. Returns flat items with userId so you can follow up via neblla_send_communication on each thread.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"emailFilter": {
"description": "Case-insensitive email substring filter",
"type": "string"
},
"fromFilter": {
"default": "all",
"description": "\"user\" = sent by end-user, \"dev\" = sent by you, \"all\" = both",
"enum": [
"all",
"user",
"dev"
],
"type": "string"
},
"importantOnly": {
"default": false,
"type": "boolean"
},
"limit": {
"default": 50,
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"readFilter": {
"default": "all",
"enum": [
"all",
"read",
"unread"
],
"type": "string"
},
"skip": {
"default": 0,
"minimum": 0,
"type": "integer"
},
"sort": {
"default": "date_desc",
"enum": [
"date_desc",
"date_asc",
"email_asc",
"email_desc"
],
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_communications",
"outputSchema": null
},
{
"description": "List the community entries (user-published content, neblla.community) of an app from the backoffice, any status. Use it to triage the moderation queue: status \"pending\" is what awaits approval in review mode. Returns indexed metadata only (title, summary, category, tags, contentType, owner, status, moderation record); fetch a payload with neblla_get_community_entry. Paginate with `cursor` = the previous `next`.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"cursor": {
"description": "Opaque pagination cursor from a previous call",
"type": "string"
},
"limit": {
"default": 20,
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"ownerId": {
"description": "Filter by the author id shown as entry.owner.id",
"type": "string"
},
"q": {
"description": "Text search over title / summary / tags",
"type": "string"
},
"status": {
"description": "Filter by status (omit for all)",
"enum": [
"published",
"pending",
"rejected",
"removed"
],
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_community_entries",
"outputSchema": null
},
{
"description": "List all files staged for an app. Returns path, mimeType, size, and timestamps for each file.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_files",
"outputSchema": null
},
{
"description": "List the app-level moderators (per-app user ids). App moderators manage rooms of any type and moderate the community.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_moderators",
"outputSchema": null
},
{
"description": "List all products for a Neblla app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_products",
"outputSchema": null
},
{
"description": "List the gallery reviews of an app (rating 1–5, text, language, author display name, the developer's reply) plus the average, count and 1–5 distribution. Newest first.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"limit": {
"description": "Max reviews returned (default 100); aggregates always cover all",
"maximum": 500,
"minimum": 1,
"type": "integer"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_reviews",
"outputSchema": null
},
{
"description": "List the persistent / predefined rooms of an app with their type, owners, whitelist, moderators, data, message count, last activity and how many users are in each one right now.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_rooms",
"outputSchema": null
},
{
"description": "List end users of an app — the people who connected through the SDK, NOT the developer's own account. Use this as the entry point for the backoffice flow: it returns a paginated list with each user's mongo `_id` (needed for every other backoffice tool), email, name, language, and stats. Pass `withCommunicationsOnly: true` to get only users who have communication threads — useful when triaging support.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"emailFilter": {
"description": "Substring match against the user's email (case-insensitive). Ignored if withCommunicationsOnly is true.",
"type": "string"
},
"limit": {
"default": 50,
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"skip": {
"default": 0,
"minimum": 0,
"type": "integer"
},
"sort": {
"default": "date_desc",
"enum": [
"date_desc",
"date_asc",
"email_asc",
"email_desc"
],
"type": "string"
},
"withCommunicationsOnly": {
"default": false,
"description": "Only return users with a non-empty communications array",
"type": "boolean"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_list_users",
"outputSchema": null
},
{
"description": "Moderate a community entry as the app owner: approve or reject a pending entry, remove a published one, or restore a rejected/removed one. `reject` and `remove` require a `reason` from the fixed taxonomy; the author receives the reason and your `message` live (communityUpdated) and in their own list. `remove` keeps the entry and its payload so an appeal can be honoured.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"approve",
"reject",
"remove",
"restore"
],
"type": "string"
},
"appId": {
"description": "The app public ID",
"type": "string"
},
"entryId": {
"description": "The entry id",
"type": "string"
},
"message": {
"description": "Plain-text explanation the author will read",
"maxLength": 1000,
"type": "string"
},
"reason": {
"enum": [
"copyright",
"inappropriate",
"hate",
"harassment",
"spam",
"illegal",
"privacy",
"other"
],
"type": "string"
}
},
"required": [
"appId",
"entryId",
"action"
],
"type": "object"
},
"name": "neblla_moderate_community_entry",
"outputSchema": null
},
{
"description": "Rename or move a file within an app. oldPath is the current path, newPath is the destination.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"newPath": {
"description": "New file path, e.g. \"new-name.html\" or \"subfolder/file.html\"",
"type": "string"
},
"oldPath": {
"description": "Current file path, e.g. \"old-name.html\"",
"type": "string"
}
},
"required": [
"appId",
"oldPath",
"newPath"
],
"type": "object"
},
"name": "neblla_move_file",
"outputSchema": null
},
{
"description": "The developer's payout account (Stripe Connect), needed to sell products inside their apps. \"status\": none | pending | active | restricted, with chargesEnabled / payoutsEnabled. \"onboarding_link\": a one-time URL the developer opens to verify identity and add a bank account (a human must do it). \"dashboard_link\": a one-time login URL to the Stripe Express dashboard (payouts, balance). Products stay hidden from players until the status is active.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"enum": [
"status",
"onboarding_link",
"dashboard_link"
],
"type": "string"
}
},
"required": [
"action"
],
"type": "object"
},
"name": "neblla_payments_account",
"outputSchema": null
},
{
"description": "Publish a Neblla app to the public gallery. BEFORE calling this tool you MUST follow these steps with the user: 1) Ask for the app title and a short description (1-3 sentences) in the user's language. 2) Ask for the gallery section: \"multiplayer\" (games/apps where users interact in real time), \"singleplayer\" (games/tools for one person at a time), or \"app\" (everything else — utilities, tools, sites). 3) Ask for tags that describe the app (e.g. \"puzzle\", \"multiplayer\", \"drawing\"). 4) Ask what devices the app is best suited for: \"mobile\", \"desktop\", or omit for both. 5) Ask if the user wants to upload a cover image — pass an http(s) URL, a data: URI, or raw base64 JPEG/PNG. It will be auto-scaled to 400x400. 6) Provide the title and description in at least the user's language. You SHOULD also translate into other supported languages (en, es, fr, de, it, pt, ja, ko, zh, ar) for wider reach, but only the original language is required. Set defaultLang to the language the user originally provided the content in. titles and descriptions MUST each contain at least one entry in the same language.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"bestOn": {
"description": "Device the app is best suited for. Omit for both mobile and desktop.",
"enum": [
"mobile",
"desktop"
],
"type": "string"
},
"defaultLang": {
"default": "en",
"enum": [
"en",
"es",
"fr",
"de",
"it",
"pt",
"ja",
"ko",
"zh",
"ar"
],
"type": "string"
},
"descriptions": {
"additionalProperties": {
"type": "string"
},
"description": "Description per language code (max 500 chars each). At least one entry required.",
"type": "object"
},
"portrait": {
"description": "Cover image. Accepts an http(s) URL, a data: URI, or raw base64 (JPEG/PNG/GIF/BMP/TIFF). Auto-scaled to 400x400 JPEG, stored as portrait.jpg, and set as cover_image.",
"maxLength": 262144,
"type": "string"
},
"section": {
"description": "Gallery section: \"multiplayer\" (real-time/social), \"singleplayer\" (one player at a time), or \"app\" (utilities/tools/sites)",
"enum": [
"singleplayer",
"multiplayer",
"app"
],
"type": "string"
},
"tags": {
"description": "Tags describing the app",
"items": {
"type": "string"
},
"type": "array"
},
"titles": {
"additionalProperties": {
"type": "string"
},
"description": "Title per language code, e.g. { en: \"My App\", es: \"Mi App\" }. At least one entry required.",
"type": "object"
}
},
"required": [
"appId",
"section",
"titles",
"descriptions"
],
"type": "object"
},
"name": "neblla_publish_app",
"outputSchema": null
},
{
"description": "Publish a community entry AS YOURSELF — owned by your own user in the app (the app user whose email is your developer email; log into the app once first). Use it to seed a community with starter content. It skips the review queue (you are a moderator of your app) and obeys the same rules as neblla.community.publish: community must be enabled, contentType/category must be allowed, payload ≤ maxPayloadBytes, no \"$\"/\".\" keys.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"category": {
"maxLength": 40,
"type": "string"
},
"contentType": {
"description": "One of the app's community.contentTypes (any when the list is empty)",
"maxLength": 64,
"type": "string"
},
"lang": {
"maxLength": 8,
"type": "string"
},
"parentId": {
"description": "Id of the entry this one derives from",
"type": "string"
},
"payload": {
"description": "The dev-defined JSON the app stores for this entry"
},
"summary": {
"maxLength": 500,
"type": "string"
},
"tags": {
"items": {
"maxLength": 32,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"title": {
"maxLength": 120,
"type": "string"
}
},
"required": [
"appId",
"title",
"contentType"
],
"type": "object"
},
"name": "neblla_publish_community_entry",
"outputSchema": null
},
{
"description": "Publish (or replace) the developer's public reply to a review; pass `text: \"\"` to delete the reply. The reply is shown in the gallery, translated into the reviewer's language when `developerLang` differs. Public text: show the developer the wording before sending.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"developerLang": {
"description": "Language the reply is written in (e.g. \"es\"), for auto-translation",
"type": "string"
},
"reviewId": {
"description": "Review id from neblla_list_reviews",
"type": "string"
},
"text": {
"description": "Reply text; empty string deletes the reply",
"maxLength": 2000,
"type": "string"
}
},
"required": [
"appId",
"reviewId",
"text"
],
"type": "object"
},
"name": "neblla_reply_review",
"outputSchema": null
},
{
"description": "Find users of an app by a partial email match (min 2 characters). Returns the matching user docs with email, communications, data, stats, and language. Use neblla_list_users for full pagination instead when no email is known.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"emailPart": {
"description": "At least 2 characters of the email to match",
"minLength": 2,
"type": "string"
},
"limit": {
"default": 50,
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"skip": {
"default": 0,
"minimum": 0,
"type": "integer"
}
},
"required": [
"appId",
"emailPart"
],
"type": "object"
},
"name": "neblla_search_users_by_email",
"outputSchema": null
},
{
"description": "Send a message from the developer to a specific end user. The user receives it live via the SDK's `communicationUpdated` event if connected, and on next reconnect otherwise. Optionally attach a `data` JSON payload (rendered by the app), or a calendar/appointment proposal via dateFrom/dateTo. Set `thread` to the id of an earlier communication to group replies. BEFORE calling: confirm the message wording with the developer (you are speaking to their users on their behalf).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"data": {
"description": "Optional JSON payload attached to the communication"
},
"dateFrom": {
"description": "Optional calendar/appointment proposal start (ISO 8601)",
"type": "string"
},
"dateTo": {
"description": "Optional calendar/appointment proposal end (ISO 8601)",
"type": "string"
},
"message": {
"description": "Plain-text message body",
"minLength": 1,
"type": "string"
},
"thread": {
"description": "Id of the parent communication to thread under",
"type": "string"
},
"userId": {
"description": "Target user's mongo ObjectId hex string",
"type": "string"
}
},
"required": [
"appId",
"userId",
"message"
],
"type": "object"
},
"name": "neblla_send_communication",
"outputSchema": null
},
{
"description": "Set a player's ban state in this app: \"none\" (lift), \"banned\" (the app shows the ban message and blocks play), \"terminated\" (wipes the player's local data in the browser and disconnects them — irreversible for that data), \"community_muted\" (can play but cannot publish, rate or report in the community). Takes effect live. Confirm with the developer before banned/terminated.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"status": {
"description": "New ban state",
"enum": [
"none",
"banned",
"terminated",
"community_muted"
],
"type": "string"
},
"userId": {
"description": "The player's `_id` from neblla_list_users",
"type": "string"
}
},
"required": [
"appId",
"userId",
"status"
],
"type": "object"
},
"name": "neblla_set_ban_status",
"outputSchema": null
},
{
"description": "Toggle the \"important\" flag on a communication. This is dev-only metadata and is NOT broadcast to the end user — use it to bubble messages to the top of your own triage view.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"commId": {
"description": "Communication id",
"type": "string"
},
"important": {
"default": true,
"type": "boolean"
},
"userId": {
"description": "User's mongo ObjectId hex string",
"type": "string"
}
},
"required": [
"appId",
"userId",
"commId"
],
"type": "object"
},
"name": "neblla_set_communication_important",
"outputSchema": null
},
{
"description": "Mark a specific communication as read or unread (from the developer's side). The end user is notified live via a `communicationRead` socket event if connected.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"commId": {
"description": "Communication id (the ISO timestamp returned when the message was created)",
"type": "string"
},
"read": {
"default": true,
"type": "boolean"
},
"userId": {
"description": "User's mongo ObjectId hex string",
"type": "string"
}
},
"required": [
"appId",
"userId",
"commId"
],
"type": "object"
},
"name": "neblla_set_communication_read",
"outputSchema": null
},
{
"description": "Make a player an app moderator (`moderator: true`) or remove them (`false`). `userId` is the per-app user id (from neblla_list_users), not an email.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"moderator": {
"description": "true = add, false = remove",
"type": "boolean"
},
"userId": {
"description": "Per-app user id",
"type": "string"
}
},
"required": [
"appId",
"userId",
"moderator"
],
"type": "object"
},
"name": "neblla_set_moderator",
"outputSchema": null
},
{
"description": "Check, set or clear the app's public slug (the readable name in play.neblla.com/<slug>). `checkOnly: true` only tells whether it is valid and free. `slug: null` removes it (old slug links stop working). Changing it changes the public URL — confirm with the developer.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"checkOnly": {
"description": "Only check availability, change nothing",
"type": "boolean"
},
"slug": {
"description": "Wanted slug (lowercase letters, digits, dashes), or null to clear",
"type": [
"string",
"null"
]
}
},
"required": [
"appId",
"slug"
],
"type": "object"
},
"name": "neblla_set_slug",
"outputSchema": null
},
{
"description": "Local backup of an app's files before risky edits. action \"create\" copies every file to <path>_copy (replacing any previous snapshot); \"rollback\" restores the copies over the current files (overwrites them — confirm first); \"discard\" deletes the copies. Use create before a large refactor, rollback if it goes wrong.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action": {
"description": "What to do with the snapshot",
"enum": [
"create",
"rollback",
"discard"
],
"type": "string"
},
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId",
"action"
],
"type": "object"
},
"name": "neblla_snapshot",
"outputSchema": null
},
{
"description": "Remove an app from the public gallery. The app keeps its files and URL — only its public listing is hidden. Use neblla_publish_app to re-publish.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_unpublish_app",
"outputSchema": null
},
{
"description": "Update an app's configuration. Pass only the fields you want to change. Use addDomain/removeDomain to mutate the allowed-origins list atomically without overwriting other entries. `sandbox: true` lets the app load on localhost / non-https origins for development. `ai` is the AI proxy config for the SDK's neblla.ai() — set { model, maxOutputTokens, userTokenMode, presets, limitsEnabled, tokensPerDay } or null to disable. userTokenMode is one of: 'off' (server uses dev key only), 'browser' (user key, browser-direct), 'server' (user key, server-side with private preset prefixes). presets is a {name: prefix} map of named prompt prefixes invoked via neblla.ai({preset:'name'}). limitsEnabled + tokensPerDay cap how many Claude tokens each end-user can spend per day; only applied when userTokenMode = off. `inbox`: true/false, or { maxPerUser, maxOutboundPerUser } to tune the in-app communications inbox (null = defaults). `serverMode`: \"js\" | \"wasm\" | \"infra\" (infra needs an active Pro subscription). `rooms`: the rooms policy object ({ policy, allowedTypes, defaultType, public, private, … }, as returned in the app). A rooms change that discards saved rooms data answers error \"rooms_data_loss\" with the warnings — show them to the developer and, if they agree, repeat with `confirmRoomsChange: true`. `p2p` (P2P/TURN settings, e.g. { media: true }), `connections` (\"all\"|\"p2p\"|\"server\"|\"none\"), `theme` (palette/typography/layout), `permissionJustifications` ({ microphone: \"why\", … }), `guestTtl` (days a guest account lives), `pattern` (app pattern id). Writing to an app that has an unapplied draft discards that draft (the answer says `draftDiscarded: true`). `community` configures user-published entries (neblla.community, see the comunidad guide section): { mode: \"open\"|\"review\"|\"closed\", whoPublishes: \"users\"|\"moderators\", maxPayloadBytes, categories[], contentTypes[], maxEntriesPerUser, rules }. The community feature itself is enabled with `features: { community: true }` (it needs login).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"addDomain": {
"description": "Append a domain entry (URL or origin) to the allowed list",
"type": "string"
},
"ai": {
"anyOf": [
{
"additionalProperties": true,
"properties": {},
"type": "object"
},
{
"type": "null"
}
],
"description": "AI proxy config: { model, maxOutputTokens, userTokenMode, presets, limitsEnabled, tokensPerDay } — pass null to disable"
},
"appId": {
"description": "The app public ID",
"type": "string"
},
"community": {
"additionalProperties": true,
"description": "Community config (user-published entries): { mode, whoPublishes, maxPayloadBytes, categories, contentTypes, maxEntriesPerUser, rules }. Merged over the stored config.",
"properties": {},
"type": "object"
},
"confirmRoomsChange": {
"description": "Set true to apply a rooms change that discards saved rooms data (only after the developer agreed)",
"type": "boolean"
},
"connections": {
"description": "Allowed connection kinds",
"enum": [
"all",
"p2p",
"server",
"none"
],
"type": "string"
},
"features": {
"additionalProperties": true,
"description": "Feature switches to merge into the app: { multiplayer, communications, purchases, ai, friends, login, anticheat, community } as booleans. Only the keys you pass change.",
"properties": {},
"type": "object"
},
"guestTtl": {
"description": "Days a guest (no-login) account is kept",
"minimum": 0,
"type": "integer"
},
"inbox": {
"anyOf": [
{
"type": "boolean"
},
{
"additionalProperties": true,
"properties": {},
"type": "object"
},
{
"type": "null"
}
],
"description": "Inbox: true/false, or { maxPerUser, maxOutboundPerUser }; null = defaults"
},
"matchmaking": {
"anyOf": [
{
"additionalProperties": true,
"properties": {},
"type": "object"
},
{
"type": "null"
}
],
"description": "No-code matchmaking config: { mode: \"nocode\"|\"custom\", rule: \"count\"|\"timer\"|\"count_then_timer\"|\"button\", minPlayers, maxPlayers (0=unlimited), waitSeconds, allowPresenterStart }. In \"nocode\" mode this regenerates server/gathering.js from the rules; in \"custom\" mode you own that file."
},
"name": {
"description": "New display name",
"type": "string"
},
"p2p": {
"anyOf": [
{
"additionalProperties": true,
"properties": {},
"type": "object"
},
{
"type": "null"
}
],
"description": "P2P / TURN settings, e.g. { media: true }"
},
"pattern": {
"description": "App pattern id",
"type": "string"
},
"permissionJustifications": {
"additionalProperties": true,
"description": "Why the app needs each browser permission: { microphone, camera, geolocation, midi }",
"properties": {},
"type": "object"
},
"removeDomain": {
"description": "Remove a domain entry exactly matching this string",
"type": "string"
},
"rooms": {
"additionalProperties": true,
"description": "Rooms policy object (same shape the app returns in `rooms`)",
"properties": {},
"type": "object"
},
"sandbox": {
"description": "Allow non-https / localhost loads for development",
"type": "boolean"
},
"serverMode": {
"description": "Where server/*.js runs: js (a player device), wasm, infra (Neblla servers, Pro only)",
"enum": [
"js",
"wasm",
"infra"
],
"type": "string"
},
"theme": {
"anyOf": [
{
"additionalProperties": true,
"properties": {},
"type": "object"
},
{
"type": "null"
}
],
"description": "Theme: { palette, typography, layout }"
}
},
"required": [
"appId"
],
"type": "object"
},
"name": "neblla_update_app",
"outputSchema": null
},
{
"description": "Update an existing product. Pass only the fields to change. Use this to adjust price, rename, or republish a product without losing its productId — changing the id would break checkout flows already wired into the app.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"currency": {
"description": "ISO 4217 code, e.g. \"usd\"",
"type": "string"
},
"defaultLang": {
"enum": [
"en",
"es",
"fr",
"de",
"it",
"pt",
"ja",
"ko",
"zh",
"ar"
],
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
],
"description": "Description, string or per-language object"
},
"image": {
"description": "Product image URL",
"type": "string"
},
"max": {
"description": "Maximum quantity for consumable",
"type": "number"
},
"min": {
"description": "Minimum quantity for consumable",
"type": "number"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
],
"description": "Product name, string or { en: \"...\", es: \"...\" }"
},
"price": {
"description": "Price in cents (one_time)",
"type": "number"
},
"pricePerUnit": {
"description": "Price per unit in cents (consumable)",
"type": "number"
},
"productId": {
"description": "The product ID returned by neblla_create_product",
"type": "string"
},
"published": {
"description": "Whether the product is buyable",
"type": "boolean"
},
"step": {
"description": "Quantity step for consumable selector",
"type": "number"
}
},
"required": [
"productId"
],
"type": "object"
},
"name": "neblla_update_product",
"outputSchema": null
},
{
"description": "Change a room: replace its shared `data` (players in the room receive it live) and/or its `moderators` list. Replacing data overwrites the live game state of that room — confirm with the developer first.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"data": {
"additionalProperties": true,
"description": "New room data (replaces the whole object)",
"properties": {},
"type": "object"
},
"moderators": {
"description": "New moderators list (per-app user ids)",
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"description": "Room name",
"type": "string"
}
},
"required": [
"appId",
"name"
],
"type": "object"
},
"name": "neblla_update_room",
"outputSchema": null
},
{
"description": "Replace the `data` object for a specific end user (the same object the SDK's neblla.save() reads/writes). Use sparingly: this overwrites the user's saved state and the change is broadcast live. Useful for support (unstuck a player), moderation (clear a corrupted save), or admin tooling. If the app has a \"bring your own database\" target configured, this writes there. Mongo-reserved keys (starting with $ or containing \".\") are rejected; total JSON size is capped at ~100KB and 10 levels deep.",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"data": {
"additionalProperties": {},
"description": "The replacement data object (must be a plain object, not array/null)",
"type": "object"
},
"userId": {
"description": "User's mongo ObjectId hex string",
"type": "string"
}
},
"required": [
"appId",
"userId",
"data"
],
"type": "object"
},
"name": "neblla_update_user_data",
"outputSchema": null
},
{
"description": "Upload or update a file for an app. Pass text files (HTML, CSS, JS, TS, JSON, SVG) as raw UTF-8 text with encoding=\"utf8\" (the default) — do NOT base64-encode them, even if they contain quotes, backticks, ${...} or newlines; send the source verbatim. For binary files (images, fonts, audio, video) you have TWO options: (a) pass a public URL via `contentUrl` — Neblla downloads the bytes server-side (recommended: no need to spend tokens base64-encoding the file in this conversation), OR (b) pass a base64 string via `content` with encoding=\"base64\". Always prefer `contentUrl` when you have one. Uploading the same path again overwrites the previous version. \n\nCanonical paths for a Neblla app are index.html, main.css, client.js (front-end) plus server/lobby.js, server/gathering.js, server/room.js (server-side). The server/ files are special: the SDK loads them itself and runs them in an isolated scope with no DOM access — never reference them from index.html, and never put DOM code or window.onNeblla in them (they must be top-level code where `neblla` is in scope as a global). client.js, by contrast, uses window.onNeblla = (neblla) => {…}. Communication between client.js and the server files is events-only (sendMessage / tellPresenter / tellServer / messageToServer / messageFromServer / setState / on('message')) — never direct function calls. All three server/ files run on the room's SERVER PEER (a device the SDK picks, never the presenter): server/lobby.js for the lobby (matchmaking); server/gathering.js while a non-lobby room is in 'gathering' state (decide when to call neblla.startRoom() to start the game); server/room.js post-startRoom (authoritative game logic — handle messageToServer, broadcast with sendMessage / setState).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"appId": {
"description": "The app public ID",
"type": "string"
},
"content": {
"description": "File content. For text files: the raw source as-is (NOT base64). For binary files: a base64 string. Required UNLESS `contentUrl` is set.",
"type": "string"
},
"contentUrl": {
"description": "Public URL of the file to upload. Neblla downloads it server-side (no need to base64-encode in this conversation). Use this for any binary asset (images, fonts, audio, video) when you have a URL. Mutually exclusive with `content`.",
"type": "string"
},
"encoding": {
"default": "utf8",
"description": "Content encoding for `content`. Ignored when `contentUrl` is used. Use \"utf8\" for all text files (HTML/CSS/JS/TS/JSON/SVG); \"base64\" only for binary assets.",
"enum": [
"utf8",
"base64"
],
"type": "string"
},
"path": {
"description": "File path within the app. Canonical: \"index.html\", \"main.css\", \"client.js\", \"server.js\". Subfolders allowed for assets.",
"type": "string"
}
},
"required": [
"appId",
"path"
],
"type": "object"
},
"name": "neblla_upload_file",
"outputSchema": null
},
{
"description": "Walk the SAME decision map the Neblla dashboard wizard uses, before creating an app. STRONGLY RECOMMENDED before neblla_create_app on any new-app request (skip it only for edits/fixes to existing code). It front-loads every structural decision so the app is born configured right. \n\nHow to use it: pass the `decisions` you can already answer from the user's request. The tool returns every still-pending decision, each with `how_to_infer` (how to answer it YOURSELF from context) and `ask_user` (whether it deserves a question to the human). The contract: ANSWER EVERY DECISION YOU CAN YOURSELF — only surface the ones in `ask_user_questions` to the user, and only when you genuinely cannot infer them; ask them all in ONE message. Then call this tool again with the full set. When `have_enough_context` is true, pass the returned `decisions` straight to neblla_create_app({ name, decisions }) — it scaffolds the matching pattern + themed UI pieces and writes the app config in one go. `plan` previews exactly what that will build. \n\nDecision ids: kind (game|app), players (single|lobby-only|multi — single = one device; lobby-only = everyone in one shared space with no separate rooms; multi = separate rooms), structure (turn-based|host-controllers|collab-realtime; multi only), login/friends/purchases/ai/communications (booleans — the feature pieces), connections (all|p2p|server), serverMode (js|wasm), roomsPolicy (ephemeral|public|private|mixed), matchmakingMode (nocode|custom), aiPayer (off|browser|server; when ai is on), palette ({primary, secondary, alert} hex colors — PICK THEM YOURSELF to match the app's character), typography (modern|editorial|techy|serif|playful — pick it yourself too).",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"decisions": {
"additionalProperties": {},
"default": {},
"description": "Decisions answered so far, keyed by decision id. Example: { kind: \"game\", players: \"multi\", structure: \"turn-based\", login: true, palette: { primary: \"#0F7BD7\", secondary: \"#15C2B0\", alert: \"#FF8552\" }, typography: \"techy\" }. Include everything the user stated plus everything you inferred.",
"type": "object"
}
},
"type": "object"
},
"name": "neblla_validate_requirements",
"outputSchema": null
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:a92a4c1e7214e42733c78d692aff789c8b162eb4947bf381ae13b8e6a1c95ab1 | sha256sum