@layers/amba-mcp 4.0.11 → 4.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,3 +61,33 @@ export declare function passthroughResult(result: {
61
61
  text: string;
62
62
  }[];
63
63
  };
64
+ /** The fields of a failed API call that `apiErrorResult` passes to the agent. */
65
+ export interface ApiErrorLike {
66
+ /** Human-readable line, e.g. `API error 402: <message>`. */
67
+ message: string;
68
+ status: number;
69
+ code: string | undefined;
70
+ /** The API's `error.message`. */
71
+ apiMessage: string;
72
+ /** The API's `error.details`, when present. */
73
+ details: unknown;
74
+ }
75
+ /**
76
+ * Tool result for a failed API call. The first text item is the
77
+ * human-readable line tools have always returned (`API error 402: ...`). The
78
+ * second is the API's structured error as JSON,
79
+ * `{ "status": 402, "error": { "code", "message", "details" } }`, so an agent
80
+ * can branch on `error.code` and read `details` (a free-tier 402 carries the
81
+ * limit, the reset date, the billing URL and the one-call upgrade there).
82
+ *
83
+ * Code mode joins an error result's text items with a newline into the
84
+ * exception it throws in the sandbox, so the same JSON reaches that surface
85
+ * after the first line of the error message.
86
+ */
87
+ export declare function apiErrorResult(err: ApiErrorLike): {
88
+ content: {
89
+ type: "text";
90
+ text: string;
91
+ }[];
92
+ isError: true;
93
+ };
@@ -43,7 +43,7 @@
43
43
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
44
44
  import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
45
45
  import { z, type ZodRawShape } from 'zod';
46
- import type { ApiClient } from '../api-client.js';
46
+ import { type ApiClient } from '../api-client.js';
47
47
  /** Wire-shape returned by an MCP tool handler. */
48
48
  export interface ToolResult {
49
49
  content: Array<{
@@ -53,6 +53,16 @@ export interface ToolResult {
53
53
  /** MCP-native failure signal. Tool transports still return HTTP 200. */
54
54
  isError?: boolean;
55
55
  }
56
+ /**
57
+ * Attach the account notices the API sent with this call's responses
58
+ * (`X-Amba-Notice`, collected by `ApiClient`), so an agent sees "claim this
59
+ * account" next to what it asked for. A successful result gets them as extra
60
+ * text items. An error result gets them as a `notices` array inside its
61
+ * trailing JSON error, so that item stays the last one and stays parseable
62
+ * (code mode joins the text items into the message of the Error it throws).
63
+ * A result without notices is returned unchanged.
64
+ */
65
+ export declare function withAccountNotices(result: ToolResult, client: ApiClient): ToolResult;
56
66
  /** Context passed to handlers registered via `registerTool`. */
57
67
  export interface WithPatHandlerContext {
58
68
  /**
@@ -40,7 +40,7 @@
40
40
  * The body is plain CommonMark — no MDX, no JSX — so it renders
41
41
  * identically wherever it lands.
42
42
  */
43
- export declare const AMBA_SETUP_GUIDE_MD = "# Amba\n\n## What Amba is\n\nAmba is the backend your app calls at runtime via the SDK. The MCP tools (`amba_*`) are for provisioning at build time \u2014 call them as the coding agent.\n\nOne Amba project = one isolated tenant database + one set of API keys + a hosted MCP at `mcp.amba.dev` for agent-driven provisioning. The runtime traffic goes through an SDK (`@layers/amba-*` on npm, `Amba` on SPM / Maven / pub.dev). The provisioning traffic \u2014 what you're about to do \u2014 goes through the tools listed below.\n\nYour job is to take the user from \"I have an app\" to \"Amba is wired in and the features are real\" in one pass, without 12 follow-up questions. The journey below is the standard playbook. Don't deviate without a reason.\n\n## Step 0 \u2014 Bootstrap credentials\n\nYou're in an MCP client (Claude.ai web, Claude Desktop, Cursor, Windsurf, etc.) without a local CLI. The MCP server has one tool that works **without** a Bearer token: `amba_developer_signup`. Use it to mint a personal access token (PAT), project, and client/server keys in a single round trip \u2014 no browser, no email verification.\n\nCall:\n\n```\namba_developer_signup({\n email: \"sandbox-<unix-seconds>-<6char-nonce>@layers.com\",\n password: \"<32 random base64url chars>\",\n name: \"amba-sandbox-agent\"\n})\n```\n\nThe response shape:\n\n```json\n{\n \"data\": {\n \"pat\": \"amb_dpat_\u2026\",\n \"developer\": { \"id\": \"\u2026\", \"email\": \"\u2026\", \"tier\": \"agent_sandbox\" },\n \"project\": {\n \"project_id\": \"\u2026\",\n \"client_key\": \"amb_ck_\u2026\",\n \"server_key\": \"amb_sk_\u2026\",\n \"provisioning_status\": \"provisioning\",\n \"verify_url\": \"https://app.amba.dev/verify?token=\u2026\",\n \"verify_token\": \"\u2026\"\n }\n }\n}\n```\n\nAfter signup, the PAT is in your hand \u2014 keep building in THIS session immediately. Pass `pat: \"<the PAT from the response>\"` as an inline argument on every subsequent `amba_*` tool call; the inline arg overrides the inbound Bearer for that one call so no client config change is needed mid-session. For future sessions, write the matching snippet from `mcp_config` to the customer's MCP-client config file so the static Bearer takes over automatically on the next launch.\n\nThe project status is `\"provisioning\"` immediately after signup; the per-tenant DB activates within ~5 seconds. Don't block \u2014 your next call may briefly retry, that's fine. If you want to be polite, call `amba_projects_get_provisioning_status({ project_id })` once and proceed when it returns `\"active\"` (or after 15s, whichever first).\n\nTell the user where their credentials live:\n\n- `pat` \u2014 the Bearer they should configure in this MCP client's settings (and treat like a password).\n- `project_id`, `client_key` \u2014 the values they paste into their app's `.env.local` / `.env`.\n- `server_key` \u2014 never ship to user devices; only into a server `.env` or a secret manager. The `amb_dev_sk_` / `amb_live_sk_` prefix is the marker.\n\n**Already have a PAT?** Skip the signup. Call `amba_developer_me({})` to verify the Bearer; if it succeeds, either reuse the most recent project (`amba_projects_list`) or call `amba_projects_create({ name: \"<app-name>\", platform: \"all\" })` and then `amba_api_keys_create` twice to mint client + server keys for `environment: \"development\"`.\n\n**Can't reach `amba_developer_signup` \u2014 it's not in your tool list, or your harness blocks the call?** Do NOT try to work around it by adding the MCP server yourself, running an installer, or editing your own settings/permissions \u2014 refusing to self-modify or widen your own permissions is the correct call, and you should not circumvent it. Instead, hand the developer **one** command to run in **their own** terminal (which is not subject to your sandbox):\n\n```bash\nnpx @layers/amba init\n```\n\nIt creates the account with no browser and writes `AMBA_PROJECT_ID` + `AMBA_CLIENT_KEY` to `.env.local` (and wires this MCP server up for your next session). Ask them to run it, tell you when it's done, then resume from this Step 0 by reading `.env.local`. Asking the developer to paste an `amb_ck_\u2026` client key is the last-resort lite path \u2014 it's enough to wire `Amba.configure()` + runtime calls and verify events land, but a client key alone can't do admin provisioning (creating achievements, collections, segments, etc.), which needs the PAT or server key.\n\n## Step 1 \u2014 Classify the app\n\nLook at what the user told you and at any files they shared. You're trying to pick one of ten presets in 30 seconds, not write a treatise. Inputs:\n\n- The user's prompt \u2014 \"I'm building a fitness tracker\" / \"a marketplace for\u2026\" / \"a Duolingo for X\".\n- README content if shared.\n- `package.json` / `pubspec.yaml` / `build.gradle.kts` / `Package.swift` \u2014 framework + dependencies.\n- Screen / view names \u2014 `WorkoutScreen`, `MatchView`, `LessonPage`, `CartView`, `ProductDetail`, `ChatThread`.\n\nPick the closest match:\n\n| Preset | When | Default Amba surfaces |\n| --- | --- | --- |\n| **fitness** | health / fitness tracker (workouts, steps, meditation) | identity (Apple+Google), push, XP, achievements, streaks, leaderboards, content (daily tips) |\n| **social** | social network / community (friends, feeds, groups) | identity, push, friends, groups, feeds, messaging, moderation, content |\n| **marketplace** | commerce / marketplace (catalog, stores, payments) | identity, push, catalog, stores, currencies (loyalty), reviews, segments |\n| **productivity** | productivity / SaaS tool (collaboration, milestones) | identity (Apple+Google+OTP), push, collections, achievements, content (changelog), segments |\n| **education** | education / learning app (courses, progress, rewards) | identity, push, XP, achievements, streaks, leaderboards, content (lessons), onboarding |\n| **game** | game / casual gaming | identity (anon-first), push, XP, achievements, currencies, inventory, leaderboards, challenges, stores |\n| **dating** | dating / matching app | identity (phone-OTP), push, friends (matches), messaging, moderation (heavy), reviews |\n| **content_creator** | content platform (feeds, subscriptions, tips) | identity, push, feeds, content, currencies (tips), referrals, stores (subscriptions) |\n| **ai_chatbot** | AI / chatbot / assistant app | identity, push, AI prompts, currencies (credits), content (system prompts), onboarding |\n| **custom** | none of the above | pick features individually |\n\nDetection heuristics, in priority order:\n\n1. The user's own description \u2014 most direct signal.\n2. Filename match in `screens/` or `views/` (high signal).\n3. Dependency in `package.json` \u2014 `react-native-health` \u2192 fitness, `@stream-io/*` \u2192 social or dating, `@stripe/*` \u2192 marketplace, `revenuecat` \u2192 marketplace or content_creator.\n4. README copy \u2014 \"fitness\", \"habit\", \"match\", \"chat\", \"store\", \"subscription\".\n\nIf two presets tie, pick the one the user's filenames match more closely. If still tied or no signal, fall back to **custom** and let them pick.\n\n## Step 2 \u2014 Confirm with the user\n\nUse a single multi-choice. Quote the surfaces from the table above so they know what they're getting.\n\n**Question 1: classification + scope**\n\n> I'm reading this as a **\\{kind\\}** app. I'd wire up: **\\{surfaces\\}**. Sound right?\n>\n> 1. Yes, wire it up as proposed (Recommended)\n> 2. Same kind but I want to pick features individually\n> 3. Wrong kind \u2014 let me pick from the list\n> 4. Custom \u2014 I'll pick features manually\n\nIf the user picks 1, go to Step 3. If 2 or 4, follow up with a multi-select of surfaces. If 3, present the table again and pick a different preset.\n\n**Question 2 (preset-specific):** see the per-surface sub-resources (`amba://setup/<surface>`) for the full \"Common follow-ups\" list. Examples:\n\n- **fitness / game / education** \u2014 leaderboard scope? (all-time, weekly, daily, none)\n- **game / content_creator** \u2014 virtual currency name? (`gold`, `gems`, `coins`, `credits` \u2014 defaults to `coins`)\n- **content_creator** \u2014 monetization? (tips, subscriptions, both)\n- **dating** \u2014 phone OTP or email-only? (phone strongly recommended)\n- **ai_chatbot** \u2014 daily free credit cap?\n\nBatch the follow-ups into one or two multi-choice rounds. Don't drip-feed six separate questions.\n\n## Step 3 \u2014 Wire it up\n\nFor each surface in the confirmed set, read the relevant sub-resource and execute its procedure. Each sub-resource is the full per-surface playbook (MCP tools + SDK init per stack + common follow-ups + re-run behavior):\n\n- **identity** (auth, anonymous/Apple/Google/OTP/magic-link, link/unlink) \u2192 `amba://setup/identity`\n- **engagement** (push, segments, content libraries, onboarding flows, deeplinks, referrals, tracked links) \u2192 `amba://setup/engagement`\n- **gamification** (XP rules, achievements, streaks, leaderboards, challenges) \u2192 `amba://setup/gamification`\n- **economy** (currencies, catalog, stores, inventory) \u2192 `amba://setup/economy`\n- **social** (friends, groups, feeds, messaging, moderation, reviews) \u2192 `amba://setup/social`\n- **infrastructure** (collections / DB tables, functions, analytics, AI prompts, media, secrets, configs, integrations, sites) \u2192 `amba://setup/infrastructure`\n\nThe general flow for every surface:\n\n1. **Detect stack.** Look at `package.json`, `pubspec.yaml`, `build.gradle.kts`, `ios/*.xcodeproj`. The detection rules:\n - `pubspec.yaml` present \u2192 Flutter.\n - `package.json` with `expo` \u2192 Expo.\n - `package.json` with `react-native` (no `expo`) \u2192 bare React Native.\n - `package.json` with `react` (no `react-native`) \u2192 web (or Next.js \u2014 same SDK).\n - `Package.swift` or `*.xcodeproj` only \u2192 iOS Swift.\n - `build.gradle.kts` or `build.gradle` with `com.android.application` \u2192 Android Kotlin.\n - Multiple (e.g. `ios/` + `android/` inside an Expo repo) \u2192 Expo wins.\n\n2. **Create resources via MCP.** Call the `amba_<surface>_create` tools to mint the definitions. Always include `project_id` from the project you created in Step 0. Always show the user the tool call before making destructive changes (creating a resource isn't destructive \u2014 but creating 30 of them is noisy).\n\n3. **Write SDK init code.** Drop the per-stack snippet (from the sub-resource) into the user's entry file. Detection:\n - Expo / React Native: `app/_layout.tsx`, `App.tsx`, `index.js` (in that order)\n - web / Next.js: `app/layout.tsx`, `pages/_app.tsx`, `src/main.tsx`, `src/App.tsx`\n - iOS Swift: `Sources/<App>/<App>App.swift`, `App/AppDelegate.swift`\n - Android Kotlin: `app/src/main/java/.../<App>.kt` (the `Application` subclass \u2014 create one if missing)\n - Flutter: `lib/main.dart`\n\n Always make additive edits \u2014 `await Amba.configure(...)` next to existing init, not replacing it. Never refactor existing auth or storage code; if the user has Firebase Auth or Supabase, leave it. Amba's auth is opt-in per call.\n\n4. **Run the project's existing test command** to confirm nothing broke. Detection:\n - `package.json` `scripts.test` \u2192 `npm test` (or `pnpm test` if `pnpm-lock.yaml` present)\n - `pubspec.yaml` \u2192 `flutter test`\n - `build.gradle.kts` \u2192 `./gradlew test` (skip on first wire-up \u2014 slow)\n - iOS \u2014 skip (need a simulator).\n\n If tests fail because of your edits, undo the offending edit and surface a clear error. If they fail for unrelated reasons (pre-existing red), note it and proceed.\n\n5. **Verify with the SDK.** Tell the user to call `Amba.diagnostics.ping()` (`Amba.Diagnostics.Ping()` on Unity) in their entry file. It returns `{ ok, server_project_id, environment, key_fingerprint, latency_ms }`. `ok: true` with the expected `server_project_id` confirms the wiring.\n\n## Step 4 \u2014 Report\n\nTell the user a structured summary. Use this exact shape so they can skim it fast:\n\n```\nAmba is wired in. Here's what changed:\n\nDONE\n - identity: Apple + Google sign-in available; signInAnonymously() called at app start\n - gamification: 3 achievements, 1 streak, 1 leaderboard created\n resources: first_workout, week_warrior, century_club / daily_workout / weekly_xp\n - engagement: push registration wired; default segment \"active_users\" created\n\nSKIPPED (low signal \u2014 re-run with /amba <feature> if you want them)\n - economy: no in-app currency UI found in your screens\n - social: no friends/feed surfaces found\n\nNEEDS YOUR INPUT\n - Apple Sign In: add the \"Sign in with Apple\" capability in Xcode > Signing & Capabilities.\n - Google Sign In: paste your Google OAuth client ID into amba_projects_update({ google_oauth_client_id: \"...\" }).\n - APNs / FCM: configure credentials with amba_integrations_configure (paste the .p8 / service-account JSON inline) before push delivers.\n\nNEXT STEPS\n - Paste AMBA_CLIENT_KEY into your build env (already shown above)\n - Trigger a workout in your existing flow \u2014 watch the achievement unlock + XP land\n - Open https://app.amba.dev to see users pour in\n```\n\nBe specific. List resources by key, not \"some achievements\". If something needs the user's input (third-party credentials, OAuth client IDs, push certs), say it clearly with the exact next action.\n\n## Stance (read this once)\n\n- **Don't ask which surfaces to use.** Classify, then confirm in one multi-choice. The taxonomy is the whole point.\n- **Default to additive, non-breaking changes.** Don't refactor existing auth, storage, or networking code. Drop in `await Amba.configure(...)` next to whatever the user already has.\n- **Never create resources without the user's confirmation in Step 2.** A 3rd-party \"convenience\" achievement called `first_login` is debt.\n- **If something is genuinely ambiguous** (leaderboard scope, currency real-money vs virtual, dating phone vs email), ask via a follow-up multi-choice. Don't guess and don't paragraph-it.\n- **clientKey vs serverKey.** `AMBA_CLIENT_KEY` (`amb_dev_ck_\u2026` in dev, `amb_live_ck_\u2026` in prod) ships to user devices. `AMBA_SERVER_KEY` (`amb_dev_sk_\u2026` / `amb_live_sk_\u2026`) never does \u2014 only into server `.env` or a secret manager. Mixing them is the #1 security mistake; if you're writing into a file that ships with the app binary, it's the client key, period.\n- **Don't echo the PAT in chat output on every call.** Showing it once after signup is fine; do not repeat it.\n\n## Get credentials (cheat sheet)\n\n- No terminal, in an MCP client: call `amba_developer_signup` (no Bearer required) \u2014 this guide's Step 0.\n- With a terminal: `npx -y @layers/amba init` signs up, mints a project + client/server keys, writes `.env.local` + `AMBA.md`, installs the `/amba` skill, and wires `mcpServers.amba` into every detected MCP-client config in one command. Auto-detects non-TTY invocations (the coding-agent bash-tool case) and runs headlessly.\n- Bind the sandbox account to a real email later: `npx @layers/amba claim me@example.com`. The backend emails a one-click magic link; clicking it lifts the sandbox cap to the Free tier.\n- Hosted MCP endpoint: `https://mcp.amba.dev/mcp` (Streamable HTTP, Bearer auth).\n\n## SDKs\n\n| Stack | Registry | Package |\n|---|---|---|\n| Browser / Node / React / React Native / Expo | npm | `@layers/amba-{web,node,react,react-native,expo}` |\n| Swift | SPM | `https://github.com/layers/amba-sdk-ios` |\n| Kotlin | Maven Central | `com.layers.amba:amba-sdk-android` |\n| Flutter | pub.dev | `amba` |\n| Unity | UPM (git) | `https://github.com/layers/amba-sdk-unity.git` |\n\nAll SDKs expose the same surface: `Amba.configure({ projectId, apiKey })`, then `Amba.events.track(...)`, `Amba.users.*`, `Amba.collections.*`, etc. Per-stack quickstart pages with the exact initialization snippet: `https://docs.amba.dev/sdk/<framework>`.\n\n## What Amba does\n\n### Identity\n- **users** \u2014 app-user registry. Auto-created on first SDK call; admin via `amba_users_*`.\n- **roles + permissions** \u2014 RBAC. Define with `amba_roles_create`; assign via `amba_roles_assign`.\n- **api_keys** \u2014 client + server keys per project. Mint via `amba_api_keys_create`.\n\n### Engagement\n- **onboarding** \u2014 multi-step first-run flows. Define with `amba_onboarding_create`; SDK `Amba.onboarding.next()`.\n- **segments** \u2014 user cohorts. Define with `amba_segments_create`; used as push/feed targets.\n- **push** \u2014 scheduled or triggered notifications. Chain: configure integrations (apns/fcm) \u2192 `amba_push_campaigns_create` \u2192 `amba_push_campaigns_send` (or schedule).\n- **referrals** \u2014 referral codes. Define with `amba_referrals_create`.\n- **deeplinks** \u2014 universal links. Set domain with `amba_deeplinks_set_config`.\n- **tracked_links** \u2014 UTM-tagged outbound links. Define with `amba_tracked_links_create`.\n- **content** \u2014 episodic delivery (lessons, quotes, daily prompts). Chain: `amba_content_libraries_create` \u2192 `amba_content_items_add` \u2192 `amba_content_schedules_create`.\n\n### Gamification\n- **xp** \u2014 experience points + level. Define rules with `amba_xp_rules_create`; SDK `Amba.xp.getBalance`.\n- **achievements** \u2014 earnable badges. Define with `amba_achievements_create`; unlock via xp rules or `amba_inventory_grant_item`.\n- **streaks** \u2014 recurring engagement counters. Define with `amba_streaks_create`; client calls `Amba.streaks.qualify(key)`.\n- **leaderboards** \u2014 ranked user lists. Define with `amba_leaderboards_create`; populated from events.\n- **challenges** \u2014 time-bounded goals. Define with `amba_challenges_create`; progress via SDK.\n\n### Economy\n- **currencies** \u2014 virtual currencies (coins, gems). Define with `amba_currencies_create`; grant via `amba_currencies_grant` or event rules via `amba_currency_grant_rules_create`; debit via `amba_currencies_spend` (atomic, rejects on insufficient funds).\n- **catalog + stores** \u2014 purchasable items + storefronts. Chain: `amba_catalog_items_create` \u2192 `amba_catalog_items_set_price` \u2192 `amba_stores_create` \u2192 `amba_stores_add_listing`. (Define currency first.)\n- **inventory** \u2014 items users own. Read via SDK `Amba.inventory.*`; grant with `amba_inventory_grant_item`.\n\n### Social\n- **friendships** \u2014 friend graph. SDK `Amba.friends.*`; admin via `amba_friendships_*`.\n- **groups** \u2014 guilds/parties/chats. Define with `amba_groups_create`; members managed via SDK + admin tools.\n- **messaging** \u2014 DMs + group chat. Enabled by default; moderate via `amba_messaging_*`.\n- **feeds** \u2014 algorithmic activity feeds. Define ranking with `amba_feeds_rules_create`.\n- **reviews** \u2014 user-submitted reviews. Enabled by default; moderate via `amba_reviews_*`.\n- **moderation** \u2014 content review queue + trust scores. Configure with `amba_moderation_configure`; review via `amba_moderation_queue_list`.\n\n### Analytics\n- **events** \u2014 track user actions. SDK `Amba.events.track()`; query via `amba_events_count`.\n- **sessions** \u2014 session telemetry. Tracked automatically; query via `amba_sessions_list`.\n- **analytics** \u2014 funnels + retention. Query via `amba_analytics_get`.\n\n### Infrastructure\n- **collections** \u2014 your own relational Postgres tables (typed columns, foreign keys, transactions, unique indexes, vector search). Define with `amba_collections_create`; read/write from SDK `Amba.client.*`.\n- **functions** \u2014 serverless TypeScript handlers. Deploy with `amba_functions_deploy`; schedule with `amba_functions_schedule`.\n- **sites** \u2014 static site hosting at `*.app.amba.host`. Deploy with `amba_sites_deploy`.\n- **media** \u2014 file storage + CDN. Upload via `amba_media_upload`.\n- **secrets** \u2014 env vars for functions. Set via `amba_secrets_set`.\n- **configs** \u2014 remote config flags. Define with `amba_remote_configs_create`.\n- **integrations** \u2014 third-party webhooks (RevenueCat, Superwall, AppsFlyer, etc.). Configure with `amba_integrations_configure`.\n- **ai_prompts** \u2014 versioned LLM prompts callable from SDK. Define with `amba_ai_prompts_create`; call via `amba_ai_prompts_invoke`.\n";
43
+ export declare const AMBA_SETUP_GUIDE_MD = "# Amba\n\n## What Amba is\n\nAmba is the backend your app calls at runtime via the SDK. The MCP tools (`amba_*`) are for provisioning at build time \u2014 call them as the coding agent.\n\nOne Amba project = one isolated tenant database + one set of API keys + a hosted MCP at `mcp.amba.dev` for agent-driven provisioning. The runtime traffic goes through an SDK (`@layers/amba-*` on npm, `Amba` on SPM / Maven / pub.dev). The provisioning traffic \u2014 what you're about to do \u2014 goes through the tools listed below.\n\nYour job is to take the user from \"I have an app\" to \"Amba is wired in and the features are real\" in one pass, without 12 follow-up questions. The journey below is the standard playbook. Don't deviate without a reason.\n\n## Step 0 \u2014 Bootstrap credentials\n\nYou're in an MCP client (Claude.ai web, Claude Desktop, Cursor, Windsurf, etc.) without a local CLI. The MCP server has one tool that works **without** a Bearer token: `amba_developer_signup`. Use it to mint a personal access token (PAT), project, and client/server keys in a single round trip \u2014 no browser, no email verification.\n\nCall:\n\n```\namba_developer_signup({\n email: \"sandbox-<unix-seconds>-<6char-nonce>@layers.com\",\n password: \"<32 random base64url chars>\",\n name: \"amba-sandbox-agent\"\n})\n```\n\nThe response shape:\n\n```json\n{\n \"data\": {\n \"pat\": \"amb_dpat_\u2026\",\n \"developer\": { \"id\": \"\u2026\", \"email\": \"\u2026\", \"tier\": \"agent_sandbox\" },\n \"project\": {\n \"project_id\": \"\u2026\",\n \"client_key\": \"amb_ck_\u2026\",\n \"server_key\": \"amb_sk_\u2026\",\n \"provisioning_status\": \"provisioning\",\n \"verify_url\": \"https://app.amba.dev/verify?token=\u2026\",\n \"verify_token\": \"\u2026\"\n }\n }\n}\n```\n\nAfter signup, the PAT is in your hand \u2014 keep building in THIS session immediately. Pass `pat: \"<the PAT from the response>\"` as an inline argument on every subsequent `amba_*` tool call; the inline arg overrides the inbound Bearer for that one call so no client config change is needed mid-session. For future sessions, write the matching snippet from `mcp_config` to the customer's MCP-client config file so the static Bearer takes over automatically on the next launch.\n\nThe project status is `\"provisioning\"` immediately after signup; the per-tenant DB activates within ~5 seconds. Don't block \u2014 your next call may briefly retry, that's fine. If you want to be polite, call `amba_projects_get_provisioning_status({ project_id })` once and proceed when it returns `\"active\"` (or after 15s, whichever first).\n\nTell the user where their credentials live:\n\n- `pat` \u2014 the Bearer they should configure in this MCP client's settings (and treat like a password).\n- `project_id`, `client_key` \u2014 the values they paste into their app's `.env.local` / `.env`.\n- `server_key` \u2014 never ship to user devices; only into a server `.env` or a secret manager. The `amb_dev_sk_` / `amb_live_sk_` prefix is the marker.\n\n**Signup refused with 403 `INVITE_REQUIRED` or `INVITE_INVALID`?** New accounts need an invite code right now. Ask the developer for theirs (it starts with `AMBA-` and arrives in their invite email) and call `amba_developer_signup` again with the same arguments plus `invite_code`. If they have no code, or the answer is `SIGNUPS_CLOSED`, offer to request access for them: `POST https://api.amba.dev/v1/auth/developer/waitlist` with `{ \"email\": \"<their own email>\", \"note\": \"<optional>\" }`, or send them to the `error.details.request_access_url` page. Tell them the invite code arrives by email, then stop. Retry only with a code the developer hands you; never retry in a loop, invent codes, or try other email addresses. From a terminal, the code goes to `npx @layers/amba init --invite <code>` (or the `AMBA_INVITE_CODE` env var).\n\n**Already have a PAT?** Skip the signup. Call `amba_developer_me({})` to verify the Bearer; if it succeeds, either reuse the most recent project (`amba_projects_list`) or call `amba_projects_create({ name: \"<app-name>\", platform: \"all\" })` and then `amba_api_keys_create` twice to mint client + server keys for `environment: \"development\"`.\n\n**Can't reach `amba_developer_signup` \u2014 it's not in your tool list, or your harness blocks the call?** Do NOT try to work around it by adding the MCP server yourself, running an installer, or editing your own settings/permissions \u2014 refusing to self-modify or widen your own permissions is the correct call, and you should not circumvent it. Instead, hand the developer **one** command to run in **their own** terminal (which is not subject to your sandbox):\n\n```bash\nnpx @layers/amba init\n```\n\nIt creates the account with no browser and writes `AMBA_PROJECT_ID` + `AMBA_CLIENT_KEY` to `.env.local` (and wires this MCP server up for your next session). Ask them to run it, tell you when it's done, then resume from this Step 0 by reading `.env.local`. Asking the developer to paste an `amb_ck_\u2026` client key is the last-resort lite path \u2014 it's enough to wire `Amba.configure()` + runtime calls and verify events land, but a client key alone can't do admin provisioning (creating achievements, collections, segments, etc.), which needs the PAT or server key.\n\n## Step 1 \u2014 Classify the app\n\nLook at what the user told you and at any files they shared. You're trying to pick one of ten presets in 30 seconds, not write a treatise. Inputs:\n\n- The user's prompt \u2014 \"I'm building a fitness tracker\" / \"a marketplace for\u2026\" / \"a Duolingo for X\".\n- README content if shared.\n- `package.json` / `pubspec.yaml` / `build.gradle.kts` / `Package.swift` \u2014 framework + dependencies.\n- Screen / view names \u2014 `WorkoutScreen`, `MatchView`, `LessonPage`, `CartView`, `ProductDetail`, `ChatThread`.\n\nPick the closest match:\n\n| Preset | When | Default Amba surfaces |\n| --- | --- | --- |\n| **fitness** | health / fitness tracker (workouts, steps, meditation) | identity (Apple+Google), push, XP, achievements, streaks, leaderboards, content (daily tips) |\n| **social** | social network / community (friends, feeds, groups) | identity, push, friends, groups, feeds, messaging, moderation, content |\n| **marketplace** | commerce / marketplace (catalog, stores, payments) | identity, push, catalog, stores, currencies (loyalty), reviews, segments |\n| **productivity** | productivity / SaaS tool (collaboration, milestones) | identity (Apple+Google+OTP), push, collections, achievements, content (changelog), segments |\n| **education** | education / learning app (courses, progress, rewards) | identity, push, XP, achievements, streaks, leaderboards, content (lessons), onboarding |\n| **game** | game / casual gaming | identity (anon-first), push, XP, achievements, currencies, inventory, leaderboards, challenges, stores |\n| **dating** | dating / matching app | identity (phone-OTP), push, friends (matches), messaging, moderation (heavy), reviews |\n| **content_creator** | content platform (feeds, subscriptions, tips) | identity, push, feeds, content, currencies (tips), referrals, stores (subscriptions) |\n| **ai_chatbot** | AI / chatbot / assistant app | identity, push, AI prompts, currencies (credits), content (system prompts), onboarding |\n| **custom** | none of the above | pick features individually |\n\nDetection heuristics, in priority order:\n\n1. The user's own description \u2014 most direct signal.\n2. Filename match in `screens/` or `views/` (high signal).\n3. Dependency in `package.json` \u2014 `react-native-health` \u2192 fitness, `@stream-io/*` \u2192 social or dating, `@stripe/*` \u2192 marketplace, `revenuecat` \u2192 marketplace or content_creator.\n4. README copy \u2014 \"fitness\", \"habit\", \"match\", \"chat\", \"store\", \"subscription\".\n\nIf two presets tie, pick the one the user's filenames match more closely. If still tied or no signal, fall back to **custom** and let them pick.\n\n## Step 2 \u2014 Confirm with the user\n\nUse a single multi-choice. Quote the surfaces from the table above so they know what they're getting.\n\n**Question 1: classification + scope**\n\n> I'm reading this as a **\\{kind\\}** app. I'd wire up: **\\{surfaces\\}**. Sound right?\n>\n> 1. Yes, wire it up as proposed (Recommended)\n> 2. Same kind but I want to pick features individually\n> 3. Wrong kind \u2014 let me pick from the list\n> 4. Custom \u2014 I'll pick features manually\n\nIf the user picks 1, go to Step 3. If 2 or 4, follow up with a multi-select of surfaces. If 3, present the table again and pick a different preset.\n\n**Question 2 (preset-specific):** see the per-surface sub-resources (`amba://setup/<surface>`) for the full \"Common follow-ups\" list. Examples:\n\n- **fitness / game / education** \u2014 leaderboard scope? (all-time, weekly, daily, none)\n- **game / content_creator** \u2014 virtual currency name? (`gold`, `gems`, `coins`, `credits` \u2014 defaults to `coins`)\n- **content_creator** \u2014 monetization? (tips, subscriptions, both)\n- **dating** \u2014 phone OTP or email-only? (phone strongly recommended)\n- **ai_chatbot** \u2014 daily free credit cap?\n\nBatch the follow-ups into one or two multi-choice rounds. Don't drip-feed six separate questions.\n\n## Step 3 \u2014 Wire it up\n\nFor each surface in the confirmed set, read the relevant sub-resource and execute its procedure. Each sub-resource is the full per-surface playbook (MCP tools + SDK init per stack + common follow-ups + re-run behavior):\n\n- **identity** (auth, anonymous/Apple/Google/OTP/magic-link, link/unlink) \u2192 `amba://setup/identity`\n- **engagement** (push, segments, content libraries, onboarding flows, deeplinks, referrals, tracked links) \u2192 `amba://setup/engagement`\n- **gamification** (XP rules, achievements, streaks, leaderboards, challenges) \u2192 `amba://setup/gamification`\n- **economy** (currencies, catalog, stores, inventory) \u2192 `amba://setup/economy`\n- **social** (friends, groups, feeds, messaging, moderation, reviews) \u2192 `amba://setup/social`\n- **infrastructure** (collections / DB tables, functions, analytics, AI prompts, media, secrets, configs, integrations, sites) \u2192 `amba://setup/infrastructure`\n\nThe general flow for every surface:\n\n1. **Detect stack.** Look at `package.json`, `pubspec.yaml`, `build.gradle.kts`, `ios/*.xcodeproj`. The detection rules:\n - `pubspec.yaml` present \u2192 Flutter.\n - `package.json` with `expo` \u2192 Expo.\n - `package.json` with `react-native` (no `expo`) \u2192 bare React Native.\n - `package.json` with `react` (no `react-native`) \u2192 web (or Next.js \u2014 same SDK).\n - `Package.swift` or `*.xcodeproj` only \u2192 iOS Swift.\n - `build.gradle.kts` or `build.gradle` with `com.android.application` \u2192 Android Kotlin.\n - Multiple (e.g. `ios/` + `android/` inside an Expo repo) \u2192 Expo wins.\n\n2. **Create resources via MCP.** Call the `amba_<surface>_create` tools to mint the definitions. Always include `project_id` from the project you created in Step 0. Always show the user the tool call before making destructive changes (creating a resource isn't destructive \u2014 but creating 30 of them is noisy).\n\n3. **Write SDK init code.** Drop the per-stack snippet (from the sub-resource) into the user's entry file. Detection:\n - Expo / React Native: `app/_layout.tsx`, `App.tsx`, `index.js` (in that order)\n - web / Next.js: `app/layout.tsx`, `pages/_app.tsx`, `src/main.tsx`, `src/App.tsx`\n - iOS Swift: `Sources/<App>/<App>App.swift`, `App/AppDelegate.swift`\n - Android Kotlin: `app/src/main/java/.../<App>.kt` (the `Application` subclass \u2014 create one if missing)\n - Flutter: `lib/main.dart`\n\n Always make additive edits \u2014 `await Amba.configure(...)` next to existing init, not replacing it. Never refactor existing auth or storage code; if the user has Firebase Auth or Supabase, leave it. Amba's auth is opt-in per call.\n\n4. **Run the project's existing test command** to confirm nothing broke. Detection:\n - `package.json` `scripts.test` \u2192 `npm test` (or `pnpm test` if `pnpm-lock.yaml` present)\n - `pubspec.yaml` \u2192 `flutter test`\n - `build.gradle.kts` \u2192 `./gradlew test` (skip on first wire-up \u2014 slow)\n - iOS \u2014 skip (need a simulator).\n\n If tests fail because of your edits, undo the offending edit and surface a clear error. If they fail for unrelated reasons (pre-existing red), note it and proceed.\n\n5. **Verify with the SDK.** Tell the user to call `Amba.diagnostics.ping()` (`Amba.Diagnostics.Ping()` on Unity) in their entry file. It returns `{ ok, server_project_id, environment, key_fingerprint, latency_ms }`. `ok: true` with the expected `server_project_id` confirms the wiring.\n\n## Step 4 \u2014 Report\n\nTell the user a structured summary. Use this exact shape so they can skim it fast:\n\n```\nAmba is wired in. Here's what changed:\n\nDONE\n - identity: Apple + Google sign-in available; signInAnonymously() called at app start\n - gamification: 3 achievements, 1 streak, 1 leaderboard created\n resources: first_workout, week_warrior, century_club / daily_workout / weekly_xp\n - engagement: push registration wired; default segment \"active_users\" created\n\nSKIPPED (low signal \u2014 re-run with /amba <feature> if you want them)\n - economy: no in-app currency UI found in your screens\n - social: no friends/feed surfaces found\n\nNEEDS YOUR INPUT\n - Apple Sign In: add the \"Sign in with Apple\" capability in Xcode > Signing & Capabilities.\n - Google Sign In: paste your Google OAuth client ID into amba_projects_update({ google_oauth_client_id: \"...\" }).\n - APNs / FCM: configure credentials with amba_integrations_configure (paste the .p8 / service-account JSON inline) before push delivers.\n\nNEXT STEPS\n - Paste AMBA_CLIENT_KEY into your build env (already shown above)\n - Trigger a workout in your existing flow \u2014 watch the achievement unlock + XP land\n - Open https://app.amba.dev to see users pour in\n```\n\nBe specific. List resources by key, not \"some achievements\". If something needs the user's input (third-party credentials, OAuth client IDs, push certs), say it clearly with the exact next action.\n\n## Stance (read this once)\n\n- **Don't ask which surfaces to use.** Classify, then confirm in one multi-choice. The taxonomy is the whole point.\n- **Default to additive, non-breaking changes.** Don't refactor existing auth, storage, or networking code. Drop in `await Amba.configure(...)` next to whatever the user already has.\n- **Never create resources without the user's confirmation in Step 2.** A 3rd-party \"convenience\" achievement called `first_login` is debt.\n- **If something is genuinely ambiguous** (leaderboard scope, currency real-money vs virtual, dating phone vs email), ask via a follow-up multi-choice. Don't guess and don't paragraph-it.\n- **clientKey vs serverKey.** `AMBA_CLIENT_KEY` (`amb_dev_ck_\u2026` in dev, `amb_live_ck_\u2026` in prod) ships to user devices. `AMBA_SERVER_KEY` (`amb_dev_sk_\u2026` / `amb_live_sk_\u2026`) never does \u2014 only into server `.env` or a secret manager. Mixing them is the #1 security mistake; if you're writing into a file that ships with the app binary, it's the client key, period.\n- **Don't echo the PAT in chat output on every call.** Showing it once after signup is fine; do not repeat it.\n\n## Get credentials (cheat sheet)\n\n- No terminal, in an MCP client: call `amba_developer_signup` (no Bearer required) \u2014 this guide's Step 0.\n- With a terminal: `npx -y @layers/amba init` signs up, mints a project + client/server keys, writes `.env.local` + `AMBA.md`, installs the `/amba` skill, and wires `mcpServers.amba` into every detected MCP-client config in one command. Auto-detects non-TTY invocations (the coding-agent bash-tool case) and runs headlessly. While signups are invite-only, add `--invite <code>` (or set `AMBA_INVITE_CODE`).\n- Bind the sandbox account to its human owner as soon as you know who that is: `amba_developer_claim` with their email (or `npx @layers/amba claim me@example.com`). The backend emails a one-click magic link; clicking it lifts the sandbox cap to the Free tier. Each free project of an unclaimed sandbox runs its own clock from when it was created: a claim notice from day 7, a hold on day 14, and an archive on day 90 after a full hold (archiving deletes nothing); claiming lifts all of it.\n- Hosted MCP endpoint: `https://mcp.amba.dev/mcp` (Streamable HTTP, Bearer auth).\n\n## SDKs\n\n| Stack | Registry | Package |\n|---|---|---|\n| Browser / Node / React / React Native / Expo | npm | `@layers/amba-{web,node,react,react-native,expo}` |\n| Swift | SPM | `https://github.com/layers/amba-sdk-ios` |\n| Kotlin | Maven Central | `com.layers.amba:amba-sdk-android` |\n| Flutter | pub.dev | `amba` |\n| Unity | UPM (git) | `https://github.com/layers/amba-sdk-unity.git` |\n\nAll SDKs expose the same surface: `Amba.configure({ projectId, apiKey })`, then `Amba.events.track(...)`, `Amba.users.*`, `Amba.collections.*`, etc. Per-stack quickstart pages with the exact initialization snippet: `https://docs.amba.dev/sdk/<framework>`.\n\n## What Amba does\n\n### Identity\n- **users** \u2014 app-user registry. Auto-created on first SDK call; admin via `amba_users_*`.\n- **roles + permissions** \u2014 RBAC. Define with `amba_roles_create`; assign via `amba_roles_assign`.\n- **api_keys** \u2014 client + server keys per project. Mint via `amba_api_keys_create`.\n\n### Engagement\n- **onboarding** \u2014 multi-step first-run flows. Define with `amba_onboarding_create`; SDK `Amba.onboarding.next()`.\n- **segments** \u2014 user cohorts. Define with `amba_segments_create`; used as push/feed targets.\n- **push** \u2014 scheduled or triggered notifications. Chain: configure integrations (apns/fcm) \u2192 `amba_push_campaigns_create` \u2192 `amba_push_campaigns_send` (or schedule).\n- **referrals** \u2014 referral codes. Define with `amba_referrals_create`.\n- **deeplinks** \u2014 universal links. Set domain with `amba_deeplinks_set_config`.\n- **tracked_links** \u2014 UTM-tagged outbound links. Define with `amba_tracked_links_create`.\n- **content** \u2014 episodic delivery (lessons, quotes, daily prompts). Chain: `amba_content_libraries_create` \u2192 `amba_content_items_add` \u2192 `amba_content_schedules_create`.\n\n### Gamification\n- **xp** \u2014 experience points + level. Define rules with `amba_xp_rules_create`; SDK `Amba.xp.getBalance`.\n- **achievements** \u2014 earnable badges. Define with `amba_achievements_create`; unlock via xp rules or `amba_inventory_grant_item`.\n- **streaks** \u2014 recurring engagement counters. Define with `amba_streaks_create`; client calls `Amba.streaks.qualify(key)`.\n- **leaderboards** \u2014 ranked user lists. Define with `amba_leaderboards_create`; populated from events.\n- **challenges** \u2014 time-bounded goals. Define with `amba_challenges_create`; progress via SDK.\n\n### Economy\n- **currencies** \u2014 virtual currencies (coins, gems). Define with `amba_currencies_create`; grant via `amba_currencies_grant` or event rules via `amba_currency_grant_rules_create`; debit via `amba_currencies_spend` (atomic, rejects on insufficient funds).\n- **catalog + stores** \u2014 purchasable items + storefronts. Chain: `amba_catalog_items_create` \u2192 `amba_catalog_items_set_price` \u2192 `amba_stores_create` \u2192 `amba_stores_add_listing`. (Define currency first.)\n- **inventory** \u2014 items users own. Read via SDK `Amba.inventory.*`; grant with `amba_inventory_grant_item`.\n\n### Social\n- **friendships** \u2014 friend graph. SDK `Amba.friends.*`; admin via `amba_friendships_*`.\n- **groups** \u2014 guilds/parties/chats. Define with `amba_groups_create`; members managed via SDK + admin tools.\n- **messaging** \u2014 DMs + group chat. Enabled by default; moderate via `amba_messaging_*`.\n- **feeds** \u2014 algorithmic activity feeds. Define ranking with `amba_feeds_rules_create`.\n- **reviews** \u2014 user-submitted reviews. Enabled by default; moderate via `amba_reviews_*`.\n- **moderation** \u2014 content review queue + trust scores. Configure with `amba_moderation_configure`; review via `amba_moderation_queue_list`.\n\n### Analytics\n- **events** \u2014 track user actions. SDK `Amba.events.track()`; query via `amba_events_count`.\n- **sessions** \u2014 session telemetry. Tracked automatically; query via `amba_sessions_list`.\n- **analytics** \u2014 funnels + retention. Query via `amba_analytics_get`.\n\n### Infrastructure\n- **collections** \u2014 your own relational Postgres tables (typed columns, foreign keys, transactions, unique indexes, vector search). Define with `amba_collections_create`; read/write from SDK `Amba.client.*`.\n- **functions** \u2014 serverless TypeScript handlers. Deploy with `amba_functions_deploy`; schedule with `amba_functions_schedule`.\n- **sites** \u2014 static site hosting at `*.app.amba.host`. Deploy with `amba_sites_deploy`.\n- **media** \u2014 file storage + CDN. Upload via `amba_media_upload`.\n- **secrets** \u2014 env vars for functions. Set via `amba_secrets_set`.\n- **configs** \u2014 remote config flags. Define with `amba_remote_configs_create`.\n- **integrations** \u2014 third-party webhooks (RevenueCat, Superwall, AppsFlyer, etc.). Configure with `amba_integrations_configure`.\n- **ai_prompts** \u2014 versioned LLM prompts callable from SDK. Define with `amba_ai_prompts_create`; call via `amba_ai_prompts_invoke`.\n";
44
44
  /** Canonical URI for the MCP resource. */
45
45
  export declare const AMBA_SETUP_GUIDE_URI = "amba://setup";
46
46
  /** Canonical MIME type for the guide body. */
@@ -5,7 +5,7 @@
5
5
  * each metered axis, and what (if anything) needs a human in the loop
6
6
  * before the next step.
7
7
  *
8
- * Three tools land here:
8
+ * Four tools land here:
9
9
  *
10
10
  * - `amba_billing_status` — live per-project state (call before
11
11
  * provisioning data-heavy workloads).
@@ -15,6 +15,10 @@
15
15
  * - `amba_billing_set_ceiling` — write-side: cap the monthly bill or
16
16
  * remove the cap. Surface to the human
17
17
  * before calling.
18
+ * - `amba_billing_upgrade` — write-side: the one call that moves a
19
+ * project to a paid plan (returns the
20
+ * checkout link the owner opens). Lifts
21
+ * the free-tier database compute cap.
18
22
  *
19
23
  * The status + set-ceiling tools call REST endpoints that W2-B is
20
24
  * shipping in parallel (`GET/PUT /v1/admin/projects/:id/billing/...`).
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `amba_developer_claim` — hand an agent-created sandbox account to a human.
3
+ *
4
+ * `amba_developer_signup` gives an agent a working account with a
5
+ * `sandbox-…@layers.com` address and no inbox. Nobody can be reached about
6
+ * an account like that, so each of its free projects runs a clock from when
7
+ * it was created: from day 7 every response carries a claim notice, on day 14
8
+ * the project goes on hold, and on day 90 (after a full hold) it is archived,
9
+ * with nothing deleted. This tool is the one call that ends all of it: it emails the
10
+ * human a single-use link, and clicking it binds their address, verifies the
11
+ * account, and lifts any hold or archive immediately.
12
+ */
13
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
14
+ import type { ApiClient } from '../api-client.js';
15
+ export declare function registerTools(server: McpServer, apiClient: ApiClient): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layers/amba-mcp",
3
- "version": "4.0.11",
3
+ "version": "4.0.12",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": ">=22"