@layers/amba-mcp 4.0.9 → 4.0.11
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.
package/dist/api-client.d.ts
CHANGED
|
@@ -34,11 +34,19 @@ export interface ApiClientOptions {
|
|
|
34
34
|
* tokens transparently. Sync values should be wrapped in `() => Promise.resolve(token)`.
|
|
35
35
|
*/
|
|
36
36
|
getToken?: () => Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Signup token forwarded on `/auth/developer/signup` as
|
|
39
|
+
* `X-Amba-Signup-Token`. The hosted MCP server copies it from the inbound
|
|
40
|
+
* request header of the same name so Amba's CI can sign up through MCP
|
|
41
|
+
* while public signup is closed. Unset for every other caller.
|
|
42
|
+
*/
|
|
43
|
+
signupToken?: string;
|
|
37
44
|
}
|
|
38
45
|
export declare class ApiClient {
|
|
39
46
|
private baseUrl;
|
|
40
47
|
private apiRoot;
|
|
41
48
|
private tokenProvider?;
|
|
49
|
+
private signupToken?;
|
|
42
50
|
constructor(options?: ApiClientOptions);
|
|
43
51
|
/**
|
|
44
52
|
* Return a sibling `ApiClient` bound to a different Bearer token.
|
|
@@ -54,6 +62,8 @@ export declare class ApiClient {
|
|
|
54
62
|
* routing stays identical — only the token provider differs.
|
|
55
63
|
*/
|
|
56
64
|
withToken(token: string): ApiClient;
|
|
65
|
+
/** The signup token to forward on `/auth/developer/signup`, if any. */
|
|
66
|
+
getSignupToken(): string | undefined;
|
|
57
67
|
/**
|
|
58
68
|
* Returns the configured admin-prefixed base URL (e.g.
|
|
59
69
|
* `https://api.amba.dev/admin`). Auth tools (`amba_developer_signup`,
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare function registerAllTools(server: McpServer, apiClient: ApiClient
|
|
|
38
38
|
export declare function createApiClient(options: {
|
|
39
39
|
baseUrl?: string;
|
|
40
40
|
token?: string;
|
|
41
|
+
signupToken?: string;
|
|
41
42
|
}): ApiClient;
|
|
42
43
|
export { ApiClient } from './api-client.js';
|
|
43
44
|
export type { ApiClientOptions } from './api-client.js';
|
package/dist/index.js
CHANGED
|
@@ -60,12 +60,15 @@ var ApiClient = class ApiClient {
|
|
|
60
60
|
baseUrl;
|
|
61
61
|
apiRoot;
|
|
62
62
|
tokenProvider;
|
|
63
|
+
signupToken;
|
|
63
64
|
constructor(options) {
|
|
64
65
|
const raw = (options?.baseUrl ?? BASE_URL).replace(/\/+$/, "");
|
|
65
66
|
if (!/\/admin$/.test(raw)) throw new Error(`ApiClient baseUrl must end in /admin (got ${JSON.stringify(raw)}). Set AMBA_API_URL=https://api.amba.dev/v1/admin (or your equivalent versioned host).`);
|
|
66
67
|
this.baseUrl = raw;
|
|
67
68
|
this.apiRoot = raw.replace(/\/admin$/, "");
|
|
68
69
|
this.tokenProvider = options?.getToken;
|
|
70
|
+
const signupToken = options?.signupToken?.trim();
|
|
71
|
+
if (signupToken) this.signupToken = signupToken;
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
71
74
|
* Return a sibling `ApiClient` bound to a different Bearer token.
|
|
@@ -81,10 +84,16 @@ var ApiClient = class ApiClient {
|
|
|
81
84
|
* routing stays identical — only the token provider differs.
|
|
82
85
|
*/
|
|
83
86
|
withToken(token) {
|
|
84
|
-
|
|
87
|
+
const opts = {
|
|
85
88
|
baseUrl: this.baseUrl,
|
|
86
89
|
getToken: async () => token
|
|
87
|
-
}
|
|
90
|
+
};
|
|
91
|
+
if (this.signupToken !== void 0) opts.signupToken = this.signupToken;
|
|
92
|
+
return new ApiClient(opts);
|
|
93
|
+
}
|
|
94
|
+
/** The signup token to forward on `/auth/developer/signup`, if any. */
|
|
95
|
+
getSignupToken() {
|
|
96
|
+
return this.signupToken;
|
|
88
97
|
}
|
|
89
98
|
/**
|
|
90
99
|
* Returns the configured admin-prefixed base URL (e.g.
|
|
@@ -685,7 +694,7 @@ function registerTools$42(server, apiClient) {
|
|
|
685
694
|
text: JSON.stringify(result, null, 2)
|
|
686
695
|
}] };
|
|
687
696
|
}, ["amba_create_project"]);
|
|
688
|
-
registerTool(server, apiClient, "amba_projects_update", "Update a project
|
|
697
|
+
registerTool(server, apiClient, "amba_projects_update", "Update a project, including passwordless-auth routing. `magic_link_redirect_url` is the exact HTTPS callback that receives the one-time `token` query parameter. `auth_email_brand_name` controls auth-email copy and sender attribution (`<brand> via Amba`) while the mailbox remains on Amba’s verified sending domain. Pass null to either auth field to restore its fallback.", {
|
|
689
698
|
project_id: z.string().describe("The project ID"),
|
|
690
699
|
name: z.string().optional().describe("Human-readable project name."),
|
|
691
700
|
bundle_id: z.string().optional().describe("App bundle identifier (e.g. \"com.example.myapp\"). Audience for Apple Sign In identity tokens."),
|
|
@@ -695,14 +704,18 @@ function registerTools$42(server, apiClient) {
|
|
|
695
704
|
"android",
|
|
696
705
|
"all"
|
|
697
706
|
]).optional().describe("Target platform."),
|
|
698
|
-
environment: z.enum(["development", "production"]).optional().describe("Project environment.")
|
|
699
|
-
|
|
707
|
+
environment: z.enum(["development", "production"]).optional().describe("Project environment."),
|
|
708
|
+
magic_link_redirect_url: z.string().url().nullable().optional().describe("Exact HTTPS callback URL for magic-link sign-in. Amba appends the one-time token query parameter. Pass null to restore the legacy fallback."),
|
|
709
|
+
auth_email_brand_name: z.string().max(80).nullable().optional().describe("Brand shown in auth-email copy and `<brand> via Amba` sender attribution. Pass null to fall back to the project name.")
|
|
710
|
+
}, async ({ project_id, name, bundle_id, google_oauth_client_id, platform, environment, magic_link_redirect_url, auth_email_brand_name }, { client }) => {
|
|
700
711
|
const payload = {};
|
|
701
712
|
if (name !== void 0) payload.name = name;
|
|
702
713
|
if (bundle_id !== void 0) payload.bundle_id = bundle_id;
|
|
703
714
|
if (google_oauth_client_id !== void 0) payload.google_oauth_client_id = google_oauth_client_id;
|
|
704
715
|
if (platform !== void 0) payload.platform = platform;
|
|
705
716
|
if (environment !== void 0) payload.environment = environment;
|
|
717
|
+
if (magic_link_redirect_url !== void 0) payload.magic_link_redirect_url = magic_link_redirect_url;
|
|
718
|
+
if (auth_email_brand_name !== void 0) payload.auth_email_brand_name = auth_email_brand_name;
|
|
706
719
|
const result = await client.patch(`/projects/${project_id}`, payload);
|
|
707
720
|
return { content: [{
|
|
708
721
|
type: "text",
|
|
@@ -4558,6 +4571,7 @@ async function authFetch(apiClient, options) {
|
|
|
4558
4571
|
const headers = { Accept: "application/json" };
|
|
4559
4572
|
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
4560
4573
|
if (options.bearer) headers["Authorization"] = `Bearer ${options.bearer}`;
|
|
4574
|
+
if (options.signupToken) headers["X-Amba-Signup-Token"] = options.signupToken;
|
|
4561
4575
|
const res = await fetch(url, {
|
|
4562
4576
|
method: options.method,
|
|
4563
4577
|
headers,
|
|
@@ -4701,10 +4715,12 @@ function registerTools$20(server, apiClient) {
|
|
|
4701
4715
|
};
|
|
4702
4716
|
if (name !== void 0) body.name = name;
|
|
4703
4717
|
if (referral_code !== void 0) body.referral_code = referral_code;
|
|
4718
|
+
const signupToken = apiClient.getSignupToken();
|
|
4704
4719
|
return enrichedAuthResult(await authFetch(apiClient, {
|
|
4705
4720
|
method: "POST",
|
|
4706
4721
|
path: "/auth/developer/signup",
|
|
4707
|
-
body
|
|
4722
|
+
body,
|
|
4723
|
+
...signupToken ? { signupToken } : {}
|
|
4708
4724
|
}), SIGNUP_AGENT_INSTRUCTIONS);
|
|
4709
4725
|
});
|
|
4710
4726
|
registerPublicTool(server, "amba_affiliate_signup", [
|
|
@@ -4726,10 +4742,12 @@ function registerTools$20(server, apiClient) {
|
|
|
4726
4742
|
password
|
|
4727
4743
|
};
|
|
4728
4744
|
if (name !== void 0) body.name = name;
|
|
4745
|
+
const signupToken = apiClient.getSignupToken();
|
|
4729
4746
|
return enrichedAuthResult(await authFetch(apiClient, {
|
|
4730
4747
|
method: "POST",
|
|
4731
4748
|
path: "/auth/developer/signup",
|
|
4732
|
-
body
|
|
4749
|
+
body,
|
|
4750
|
+
...signupToken ? { signupToken } : {}
|
|
4733
4751
|
}), SIGNUP_AGENT_INSTRUCTIONS);
|
|
4734
4752
|
});
|
|
4735
4753
|
registerPublicTool(server, "amba_developer_login", [
|
|
@@ -5942,6 +5960,7 @@ function registerTools$17(server, apiClient) {
|
|
|
5942
5960
|
"Deploy a static site to an Amba project. Creates the site if it does not yet exist, then uploads the supplied files as a new deployment.",
|
|
5943
5961
|
"The deployment is immutable — its files live forever under the site's storage prefix — and the site flips to serve the new deployment atomically. Older deployments are kept for rollback via `amba_sites_list`.",
|
|
5944
5962
|
"Site name must match /^[a-z][a-z0-9_-]{0,49}$/. Per-file cap: 25 MiB. The site's public URL is `https://{slug}.app.amba.host` where `slug` is `{first 8 chars of project_id}-{name}`.",
|
|
5963
|
+
"Routing follows common static-host conventions, so directory-style exports work as-is: `/a/` serves `a/index.html`; `/a` serves the exact file, then `a.html`, then 308-redirects to `/a/` when only `a/index.html` exists. Include a top-level `404.html` to answer unknown paths with status 404; without one, extensionless paths fall back to `index.html` (single-page-app mode).",
|
|
5945
5964
|
"Returns the deployment record + public URL + file/byte counts."
|
|
5946
5965
|
].join(" "), {
|
|
5947
5966
|
project_id: z.string().describe("The Amba project ID."),
|
|
@@ -6193,11 +6212,12 @@ function registerTools$14(server, apiClient) {
|
|
|
6193
6212
|
"Writes a new version to the backing secret store and enqueues the sync. Subsequent function invocations see the new value once sync_status flips to \"synced\" (typically <30s).",
|
|
6194
6213
|
"Secret name must match /^[A-Z][A-Z0-9_]{0,62}$/. Function name (when given) must match /^[a-z][a-z0-9_-]{0,57}$/.",
|
|
6195
6214
|
"The complete AMBA_ and EDGE_ namespaces, plus the exact names STORAGE and EDGE_DB_PROXY, are platform-managed. MCP rejects them before an API/provider call; the API also returns 400 RESERVED_BINDING.",
|
|
6215
|
+
"Every function already receives AMBA_API_URL, AMBA_PROJECT_ID, AMBA_INTERNAL_TOKEN (project-scoped admin token), and AMBA_AI_GATEWAY_URL in `env`, so never set those. For your own values, use an app prefix: store the project client key as APP_CLIENT_KEY, for example.",
|
|
6196
6216
|
"Secrets may be set BEFORE deploying the function — the sync drains once a deployment lands, so you can set every secret first and deploy once.",
|
|
6197
6217
|
"Value cap: 64 KiB. Plaintext is never returned afterwards."
|
|
6198
6218
|
].join(" "), {
|
|
6199
6219
|
project_id: z.string().describe("The Amba project ID."),
|
|
6200
|
-
name: SET_SECRET_NAME.describe("Secret name. UPPER_SNAKE_CASE. The AMBA_ and EDGE_ prefixes and exact names STORAGE and EDGE_DB_PROXY are reserved."),
|
|
6220
|
+
name: SET_SECRET_NAME.describe("Secret name. UPPER_SNAKE_CASE. The AMBA_ and EDGE_ prefixes and exact names STORAGE and EDGE_DB_PROXY are reserved; use an app prefix such as APP_ (APP_CLIENT_KEY)."),
|
|
6201
6221
|
value: z.string().describe("Secret value. Stored encrypted at rest; never returned in plaintext afterwards."),
|
|
6202
6222
|
function: z.string().optional().describe("Function this secret binds to. OMIT for a project-wide secret (applied to every function in the project).")
|
|
6203
6223
|
}, async ({ project_id, name, value, function: functionName }, { pat }) => {
|
|
@@ -8014,7 +8034,7 @@ There is no separate "identity provisioning" step — \`auth\` is the default su
|
|
|
8014
8034
|
| --- | --- | --- |
|
|
8015
8035
|
| \`amba_developer_me\` | Verify the developer PAT and read the developer's profile. Pre-flight check before any provisioning. | \`{}\` |
|
|
8016
8036
|
| \`amba_projects_get\` | Read a project's config (bundle id, OAuth client id, platform). | \`{ project_id }\` |
|
|
8017
|
-
| \`amba_projects_update\` | Set
|
|
8037
|
+
| \`amba_projects_update\` | Set social-login audiences plus the exact magic-link callback and auth-email brand. | \`{ project_id, magic_link_redirect_url: "https://app.example.com/auth/callback", auth_email_brand_name: "My App" }\` |
|
|
8018
8038
|
| \`amba_users_list\` | Browse end-users (app_users) of the project — useful as a smoke check after the first sign-in. | \`{ project_id, limit: 20 }\` |
|
|
8019
8039
|
| \`amba_users_get\` | Fetch a single app_user by id. | \`{ project_id, user_id }\` |
|
|
8020
8040
|
| \`amba_users_bulk_update\` | Set custom properties on many users at once. | \`{ project_id, user_ids: [...], properties: { tier: "trial" } }\` |
|
|
@@ -11316,6 +11336,7 @@ function registerAllTools(server, apiClient) {
|
|
|
11316
11336
|
function createApiClient(options) {
|
|
11317
11337
|
const opts = {};
|
|
11318
11338
|
if (options.baseUrl !== void 0) opts.baseUrl = options.baseUrl;
|
|
11339
|
+
if (options.signupToken !== void 0) opts.signupToken = options.signupToken;
|
|
11319
11340
|
if (options.token !== void 0) {
|
|
11320
11341
|
const token = options.token;
|
|
11321
11342
|
opts.getToken = async () => token;
|
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
* canonical names (`amba_api_keys_create`) so agents pattern-match
|
|
16
16
|
* against the modern shape. Drift gate in `amba-setup.test.ts`.
|
|
17
17
|
*/
|
|
18
|
-
export declare const AMBA_SETUP_IDENTITY_MD = "# Identity\n\nEnd-user authentication for an Amba project: anonymous sessions, email/password, email OTP, SMS OTP, magic links, Sign in with Apple, Sign in with Google, and account linking. All flows return an `AuthResult` containing a `user` + a session token; the SDK persists tokens to the platform's native secure storage and replays them on the next launch. Subsequent SDK calls (collections, push, XP, etc.) are authenticated as the signed-in user automatically.\n\nThere is no separate \"identity provisioning\" step \u2014 `auth` is the default surface for every project. Your job here is to (a) wire `Amba.configure(...)` plus the right sign-in calls into the user's entry file, and (b) where the user wants social sign-in, set the audience identifiers on the project so the server can verify identity tokens.\n\n## MCP tools\n\n| Tool | Purpose | Example args |\n| --- | --- | --- |\n| `amba_developer_me` | Verify the developer PAT and read the developer's profile. Pre-flight check before any provisioning. | `{}` |\n| `amba_projects_get` | Read a project's config (bundle id, OAuth client id, platform). | `{ project_id }` |\n| `amba_projects_update` | Set
|
|
18
|
+
export declare const AMBA_SETUP_IDENTITY_MD = "# Identity\n\nEnd-user authentication for an Amba project: anonymous sessions, email/password, email OTP, SMS OTP, magic links, Sign in with Apple, Sign in with Google, and account linking. All flows return an `AuthResult` containing a `user` + a session token; the SDK persists tokens to the platform's native secure storage and replays them on the next launch. Subsequent SDK calls (collections, push, XP, etc.) are authenticated as the signed-in user automatically.\n\nThere is no separate \"identity provisioning\" step \u2014 `auth` is the default surface for every project. Your job here is to (a) wire `Amba.configure(...)` plus the right sign-in calls into the user's entry file, and (b) where the user wants social sign-in, set the audience identifiers on the project so the server can verify identity tokens.\n\n## MCP tools\n\n| Tool | Purpose | Example args |\n| --- | --- | --- |\n| `amba_developer_me` | Verify the developer PAT and read the developer's profile. Pre-flight check before any provisioning. | `{}` |\n| `amba_projects_get` | Read a project's config (bundle id, OAuth client id, platform). | `{ project_id }` |\n| `amba_projects_update` | Set social-login audiences plus the exact magic-link callback and auth-email brand. | `{ project_id, magic_link_redirect_url: \"https://app.example.com/auth/callback\", auth_email_brand_name: \"My App\" }` |\n| `amba_users_list` | Browse end-users (app_users) of the project \u2014 useful as a smoke check after the first sign-in. | `{ project_id, limit: 20 }` |\n| `amba_users_get` | Fetch a single app_user by id. | `{ project_id, user_id }` |\n| `amba_users_bulk_update` | Set custom properties on many users at once. | `{ project_id, user_ids: [...], properties: { tier: \"trial\" } }` |\n| `amba_api_keys_create` | Mint additional client/server keys (e.g. a separate `production` key). | `{ project_id, key_type: \"client\", environment: \"production\" }` |\n| `amba_api_keys_delete` | Revoke a leaked key. | `{ project_id, api_key_id }` |\n| `amba_roles_assign` | Grant an RBAC role to an app_user (admin / moderator / etc.). | `{ project_id, user_id, role_id }` |\n\nThere's no `amba_auth_*` namespace \u2014 auth is owned by the SDK on the client side, and there are no provisioning calls for it beyond setting the project's audience identifiers. If the user wants Apple / Google sign-in, the **mandatory** preflight is:\n\n```\namba_projects_update({\n project_id: \"<from Step 0>\",\n bundle_id: \"<their iOS bundle id>\",\n google_oauth_client_id: \"<their Google OAuth client id>\"\n})\n```\n\nWithout this, the server rejects identity tokens with `AUDIENCE_NOT_CONFIGURED` and the user thinks Amba is broken. If they don't know their bundle id, ask; if they don't have a Google OAuth client yet, tell them to create one at `console.cloud.google.com` and link it later via `amba_projects_update`.\n\n## SDK init per stack\n\n### Expo\n\n```bash\nnpx expo install @layers/amba-expo @react-native-async-storage/async-storage\n```\n\nIn `app/_layout.tsx` (or whatever your root layout is):\n\n```tsx\nimport { useEffect } from 'react';\nimport { Amba } from '@layers/amba-expo';\n\nexport default function RootLayout() {\n useEffect(() => {\n (async () => {\n await Amba.configure({\n apiKey: process.env.EXPO_PUBLIC_AMBA_CLIENT_KEY!,\n });\n await Amba.auth.signInAnonymously();\n })();\n }, []);\n return /* \u2026 */ null;\n}\n```\n\nFor Sign in with Apple, add `expo-apple-authentication`; capture the identity token and call `Amba.auth.signInWithApple(identityToken)`. For Sign in with Google, use `expo-auth-session/providers/google` and call `Amba.auth.signInWithGoogle(id_token)`.\n\n### React Native (bare)\n\n```bash\nnpm install @layers/amba-react-native @react-native-async-storage/async-storage\n```\n\n```tsx\nimport { Amba } from '@layers/amba-react-native';\n\nawait Amba.configure({ apiKey: process.env.AMBA_CLIENT_KEY! });\nawait Amba.auth.signInAnonymously();\n\n// Email OTP\nawait Amba.auth.requestEmailOtp(email);\nawait Amba.auth.verifyEmailOtp(email, code);\n\n// SMS OTP (E.164, leading \"+\")\nawait Amba.auth.requestSmsOtp('+14155551234');\nawait Amba.auth.verifySmsOtp('+14155551234', code);\n```\n\n### Web (browser / Next.js / Vite / Remix)\n\n```bash\nnpm install @layers/amba-web\n# Optional React hooks:\nnpm install @layers/amba-react\n```\n\n```ts\nimport { Amba } from '@layers/amba-web';\n\nawait Amba.configure({ apiKey: import.meta.env.VITE_AMBA_CLIENT_KEY });\nawait Amba.auth.signInAnonymously();\n\n// Magic link\nawait Amba.auth.requestMagicLink('user@example.com');\nconst token = new URLSearchParams(window.location.search).get('token');\nif (token) await Amba.auth.verifyMagicLink(token);\n```\n\nNext.js \u2014 call `Amba.configure(...)` once at the top of `app/layout.tsx` (or `pages/_app.tsx`). Anonymous sign-in should happen on the client; do not call SDK functions in server components.\n\n### iOS (Swift, SPM)\n\nIn `Package.swift` (or Xcode \u2192 File \u2192 Add Package Dependencies):\n\n```swift\n.package(url: \"https://github.com/layers/amba-sdk-ios\", from: \"1.0.0\")\n```\n\n```swift\nimport SwiftUI\nimport Amba\n\n@main\nstruct MyApp: App {\n init() {\n Task {\n try await Amba.configure(apiKey: ProcessInfo.processInfo.environment[\"AMBA_CLIENT_KEY\"]!)\n try await Amba.auth.signInAnonymously()\n }\n }\n var body: some Scene { WindowGroup { ContentView() } }\n}\n```\n\nSign in with Apple \u2014 use Apple's `AuthenticationServices` framework; pass the `identityToken` to `Amba.auth.signInWithApple`. Sign in with Google \u2014 use Google's `GoogleSignIn-iOS` SDK; pass the `idToken` to `Amba.auth.signInWithGoogle`.\n\n> Add the \"Sign in with Apple\" capability in **Xcode \u2192 target \u2192 Signing & Capabilities \u2192 + Capability**. Without it, the Apple auth call fails before it reaches Amba.\n\n### Android (Kotlin)\n\nIn `app/build.gradle.kts`:\n\n```kotlin\ndependencies {\n implementation(\"com.layers.amba:amba-sdk-android:0.1.0\")\n}\n```\n\nIn your `Application` subclass:\n\n```kotlin\nimport android.app.Application\nimport com.layers.amba.Amba\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.launch\n\nclass MyApp : Application() {\n override fun onCreate() {\n super.onCreate()\n GlobalScope.launch {\n Amba.configure(apiKey = BuildConfig.AMBA_CLIENT_KEY)\n Amba.auth.signInAnonymously()\n }\n }\n}\n```\n\nSign in with Google \u2014 use Google's Credential Manager flow, capture `idToken`, then `Amba.auth.signInWithGoogle(idToken = idToken)`.\n\n### Flutter\n\n```yaml\ndependencies:\n amba: ^1.0.0\n```\n\n```dart\nimport 'package:amba/amba.dart';\n\nFuture<void> main() async {\n WidgetsFlutterBinding.ensureInitialized();\n await Amba.configure(apiKey: const String.fromEnvironment('AMBA_CLIENT_KEY'));\n await Amba.auth.signInAnonymously();\n runApp(const MyApp());\n}\n```\n\nPass the key in: `flutter run --dart-define=AMBA_CLIENT_KEY=$AMBA_CLIENT_KEY`. Apple: `sign_in_with_apple` plugin \u2192 `Amba.auth.signInWithApple`. Google: `google_sign_in` plugin \u2192 `Amba.auth.signInWithGoogle`.\n\n## Common follow-ups\n\nAsk one bundled multi-choice \u2014 don't drip-feed.\n\n1. **Which sign-in methods do you want?** (multi-select)\n - [x] Anonymous (recommended \u2014 call at app start, lets users use the app immediately)\n - [ ] Email + password\n - [ ] Email OTP (6-digit code emailed)\n - [ ] Magic link (single click email)\n - [ ] Phone OTP / SMS (E.164, requires SMS provider configured)\n - [ ] Sign in with Apple (iOS / web; required for iOS apps that have any third-party auth per App Store guideline 4.8)\n - [ ] Sign in with Google (Android / iOS / web)\n\n2. **If Apple is selected:** what's your iOS bundle id?\n\n3. **If Google is selected:** what's your Google OAuth client id? Format: `123456789-abc.apps.googleusercontent.com`. If they don't have one, point them at `console.cloud.google.com` and proceed without it \u2014 they can paste it later via `amba_projects_update`.\n\n4. **If anonymous is selected:** when do you want users to upgrade?\n - On a \"Save your progress\" prompt (offer Apple/Google linking)\n - Behind a paywall / premium gate\n - Never auto-prompt (user upgrades from settings)\n - Defaults to \"never auto-prompt\".\n\n## Re-run behavior\n\nOn a second invocation that targets identity:\n\n1. Call `amba_projects_get({ project_id })` to read current `bundle_id` and `google_oauth_client_id`. Compare to what the user gave you:\n - If both already set \u2192 no `amba_projects_update` needed.\n - If user is adding a new social provider that needs an audience \u2192 call `amba_projects_update` with just the new field. Don't blow away the existing one.\n\n2. For new sign-in methods, append the per-method code block to the existing entry file *without* re-emitting `Amba.configure(...)` (it's already there). Detection: search for `Amba.configure` in the entry file; if present, skip the configure block.\n\n3. If the user asks to \"switch from anonymous to email-only\" or similar destructive change, **don't auto-do it**. Explain that existing anonymous user data would be unreachable without a link flow, then offer:\n - Add the new method alongside anonymous (recommended)\n - Add a forced upgrade prompt in onboarding\n - Migrate manually via `Amba.auth.linkEmailOtp(email, code)` \u2014 keeps existing user data\n";
|
|
19
19
|
export declare const AMBA_SETUP_IDENTITY_URI = "amba://setup/identity";
|
|
20
20
|
export declare const AMBA_SETUP_IDENTITY_MIME = "text/markdown";
|
|
@@ -53,7 +53,7 @@ export declare const AMBA_SETUP_SUB_RESOURCES: readonly [{
|
|
|
53
53
|
readonly name: "amba-setup-identity";
|
|
54
54
|
readonly uri: "amba://setup/identity";
|
|
55
55
|
readonly mime: "text/markdown";
|
|
56
|
-
readonly body: "# Identity\n\nEnd-user authentication for an Amba project: anonymous sessions, email/password, email OTP, SMS OTP, magic links, Sign in with Apple, Sign in with Google, and account linking. All flows return an `AuthResult` containing a `user` + a session token; the SDK persists tokens to the platform's native secure storage and replays them on the next launch. Subsequent SDK calls (collections, push, XP, etc.) are authenticated as the signed-in user automatically.\n\nThere is no separate \"identity provisioning\" step — `auth` is the default surface for every project. Your job here is to (a) wire `Amba.configure(...)` plus the right sign-in calls into the user's entry file, and (b) where the user wants social sign-in, set the audience identifiers on the project so the server can verify identity tokens.\n\n## MCP tools\n\n| Tool | Purpose | Example args |\n| --- | --- | --- |\n| `amba_developer_me` | Verify the developer PAT and read the developer's profile. Pre-flight check before any provisioning. | `{}` |\n| `amba_projects_get` | Read a project's config (bundle id, OAuth client id, platform). | `{ project_id }` |\n| `amba_projects_update` | Set
|
|
56
|
+
readonly body: "# Identity\n\nEnd-user authentication for an Amba project: anonymous sessions, email/password, email OTP, SMS OTP, magic links, Sign in with Apple, Sign in with Google, and account linking. All flows return an `AuthResult` containing a `user` + a session token; the SDK persists tokens to the platform's native secure storage and replays them on the next launch. Subsequent SDK calls (collections, push, XP, etc.) are authenticated as the signed-in user automatically.\n\nThere is no separate \"identity provisioning\" step — `auth` is the default surface for every project. Your job here is to (a) wire `Amba.configure(...)` plus the right sign-in calls into the user's entry file, and (b) where the user wants social sign-in, set the audience identifiers on the project so the server can verify identity tokens.\n\n## MCP tools\n\n| Tool | Purpose | Example args |\n| --- | --- | --- |\n| `amba_developer_me` | Verify the developer PAT and read the developer's profile. Pre-flight check before any provisioning. | `{}` |\n| `amba_projects_get` | Read a project's config (bundle id, OAuth client id, platform). | `{ project_id }` |\n| `amba_projects_update` | Set social-login audiences plus the exact magic-link callback and auth-email brand. | `{ project_id, magic_link_redirect_url: \"https://app.example.com/auth/callback\", auth_email_brand_name: \"My App\" }` |\n| `amba_users_list` | Browse end-users (app_users) of the project — useful as a smoke check after the first sign-in. | `{ project_id, limit: 20 }` |\n| `amba_users_get` | Fetch a single app_user by id. | `{ project_id, user_id }` |\n| `amba_users_bulk_update` | Set custom properties on many users at once. | `{ project_id, user_ids: [...], properties: { tier: \"trial\" } }` |\n| `amba_api_keys_create` | Mint additional client/server keys (e.g. a separate `production` key). | `{ project_id, key_type: \"client\", environment: \"production\" }` |\n| `amba_api_keys_delete` | Revoke a leaked key. | `{ project_id, api_key_id }` |\n| `amba_roles_assign` | Grant an RBAC role to an app_user (admin / moderator / etc.). | `{ project_id, user_id, role_id }` |\n\nThere's no `amba_auth_*` namespace — auth is owned by the SDK on the client side, and there are no provisioning calls for it beyond setting the project's audience identifiers. If the user wants Apple / Google sign-in, the **mandatory** preflight is:\n\n```\namba_projects_update({\n project_id: \"<from Step 0>\",\n bundle_id: \"<their iOS bundle id>\",\n google_oauth_client_id: \"<their Google OAuth client id>\"\n})\n```\n\nWithout this, the server rejects identity tokens with `AUDIENCE_NOT_CONFIGURED` and the user thinks Amba is broken. If they don't know their bundle id, ask; if they don't have a Google OAuth client yet, tell them to create one at `console.cloud.google.com` and link it later via `amba_projects_update`.\n\n## SDK init per stack\n\n### Expo\n\n```bash\nnpx expo install @layers/amba-expo @react-native-async-storage/async-storage\n```\n\nIn `app/_layout.tsx` (or whatever your root layout is):\n\n```tsx\nimport { useEffect } from 'react';\nimport { Amba } from '@layers/amba-expo';\n\nexport default function RootLayout() {\n useEffect(() => {\n (async () => {\n await Amba.configure({\n apiKey: process.env.EXPO_PUBLIC_AMBA_CLIENT_KEY!,\n });\n await Amba.auth.signInAnonymously();\n })();\n }, []);\n return /* … */ null;\n}\n```\n\nFor Sign in with Apple, add `expo-apple-authentication`; capture the identity token and call `Amba.auth.signInWithApple(identityToken)`. For Sign in with Google, use `expo-auth-session/providers/google` and call `Amba.auth.signInWithGoogle(id_token)`.\n\n### React Native (bare)\n\n```bash\nnpm install @layers/amba-react-native @react-native-async-storage/async-storage\n```\n\n```tsx\nimport { Amba } from '@layers/amba-react-native';\n\nawait Amba.configure({ apiKey: process.env.AMBA_CLIENT_KEY! });\nawait Amba.auth.signInAnonymously();\n\n// Email OTP\nawait Amba.auth.requestEmailOtp(email);\nawait Amba.auth.verifyEmailOtp(email, code);\n\n// SMS OTP (E.164, leading \"+\")\nawait Amba.auth.requestSmsOtp('+14155551234');\nawait Amba.auth.verifySmsOtp('+14155551234', code);\n```\n\n### Web (browser / Next.js / Vite / Remix)\n\n```bash\nnpm install @layers/amba-web\n# Optional React hooks:\nnpm install @layers/amba-react\n```\n\n```ts\nimport { Amba } from '@layers/amba-web';\n\nawait Amba.configure({ apiKey: import.meta.env.VITE_AMBA_CLIENT_KEY });\nawait Amba.auth.signInAnonymously();\n\n// Magic link\nawait Amba.auth.requestMagicLink('user@example.com');\nconst token = new URLSearchParams(window.location.search).get('token');\nif (token) await Amba.auth.verifyMagicLink(token);\n```\n\nNext.js — call `Amba.configure(...)` once at the top of `app/layout.tsx` (or `pages/_app.tsx`). Anonymous sign-in should happen on the client; do not call SDK functions in server components.\n\n### iOS (Swift, SPM)\n\nIn `Package.swift` (or Xcode → File → Add Package Dependencies):\n\n```swift\n.package(url: \"https://github.com/layers/amba-sdk-ios\", from: \"1.0.0\")\n```\n\n```swift\nimport SwiftUI\nimport Amba\n\n@main\nstruct MyApp: App {\n init() {\n Task {\n try await Amba.configure(apiKey: ProcessInfo.processInfo.environment[\"AMBA_CLIENT_KEY\"]!)\n try await Amba.auth.signInAnonymously()\n }\n }\n var body: some Scene { WindowGroup { ContentView() } }\n}\n```\n\nSign in with Apple — use Apple's `AuthenticationServices` framework; pass the `identityToken` to `Amba.auth.signInWithApple`. Sign in with Google — use Google's `GoogleSignIn-iOS` SDK; pass the `idToken` to `Amba.auth.signInWithGoogle`.\n\n> Add the \"Sign in with Apple\" capability in **Xcode → target → Signing & Capabilities → + Capability**. Without it, the Apple auth call fails before it reaches Amba.\n\n### Android (Kotlin)\n\nIn `app/build.gradle.kts`:\n\n```kotlin\ndependencies {\n implementation(\"com.layers.amba:amba-sdk-android:0.1.0\")\n}\n```\n\nIn your `Application` subclass:\n\n```kotlin\nimport android.app.Application\nimport com.layers.amba.Amba\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.launch\n\nclass MyApp : Application() {\n override fun onCreate() {\n super.onCreate()\n GlobalScope.launch {\n Amba.configure(apiKey = BuildConfig.AMBA_CLIENT_KEY)\n Amba.auth.signInAnonymously()\n }\n }\n}\n```\n\nSign in with Google — use Google's Credential Manager flow, capture `idToken`, then `Amba.auth.signInWithGoogle(idToken = idToken)`.\n\n### Flutter\n\n```yaml\ndependencies:\n amba: ^1.0.0\n```\n\n```dart\nimport 'package:amba/amba.dart';\n\nFuture<void> main() async {\n WidgetsFlutterBinding.ensureInitialized();\n await Amba.configure(apiKey: const String.fromEnvironment('AMBA_CLIENT_KEY'));\n await Amba.auth.signInAnonymously();\n runApp(const MyApp());\n}\n```\n\nPass the key in: `flutter run --dart-define=AMBA_CLIENT_KEY=$AMBA_CLIENT_KEY`. Apple: `sign_in_with_apple` plugin → `Amba.auth.signInWithApple`. Google: `google_sign_in` plugin → `Amba.auth.signInWithGoogle`.\n\n## Common follow-ups\n\nAsk one bundled multi-choice — don't drip-feed.\n\n1. **Which sign-in methods do you want?** (multi-select)\n - [x] Anonymous (recommended — call at app start, lets users use the app immediately)\n - [ ] Email + password\n - [ ] Email OTP (6-digit code emailed)\n - [ ] Magic link (single click email)\n - [ ] Phone OTP / SMS (E.164, requires SMS provider configured)\n - [ ] Sign in with Apple (iOS / web; required for iOS apps that have any third-party auth per App Store guideline 4.8)\n - [ ] Sign in with Google (Android / iOS / web)\n\n2. **If Apple is selected:** what's your iOS bundle id?\n\n3. **If Google is selected:** what's your Google OAuth client id? Format: `123456789-abc.apps.googleusercontent.com`. If they don't have one, point them at `console.cloud.google.com` and proceed without it — they can paste it later via `amba_projects_update`.\n\n4. **If anonymous is selected:** when do you want users to upgrade?\n - On a \"Save your progress\" prompt (offer Apple/Google linking)\n - Behind a paywall / premium gate\n - Never auto-prompt (user upgrades from settings)\n - Defaults to \"never auto-prompt\".\n\n## Re-run behavior\n\nOn a second invocation that targets identity:\n\n1. Call `amba_projects_get({ project_id })` to read current `bundle_id` and `google_oauth_client_id`. Compare to what the user gave you:\n - If both already set → no `amba_projects_update` needed.\n - If user is adding a new social provider that needs an audience → call `amba_projects_update` with just the new field. Don't blow away the existing one.\n\n2. For new sign-in methods, append the per-method code block to the existing entry file *without* re-emitting `Amba.configure(...)` (it's already there). Detection: search for `Amba.configure` in the entry file; if present, skip the configure block.\n\n3. If the user asks to \"switch from anonymous to email-only\" or similar destructive change, **don't auto-do it**. Explain that existing anonymous user data would be unreachable without a link flow, then offer:\n - Add the new method alongside anonymous (recommended)\n - Add a forced upgrade prompt in onboarding\n - Migrate manually via `Amba.auth.linkEmailOtp(email, code)` — keeps existing user data\n";
|
|
57
57
|
readonly surface: "identity";
|
|
58
58
|
readonly title: "Amba setup — identity";
|
|
59
59
|
readonly description: string;
|
package/dist/tools/secrets.d.ts
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* The complete AMBA_ and EDGE_ namespaces, plus the exact names STORAGE
|
|
18
18
|
* and EDGE_DB_PROXY, are platform-reserved. MCP rejects these before an
|
|
19
19
|
* API/provider call; the API independently enforces the same shared rule.
|
|
20
|
+
* The shared helper's message names the rule, lists the bindings every
|
|
21
|
+
* function already receives, and suggests an `APP_`-prefixed name.
|
|
20
22
|
*
|
|
21
23
|
* Plaintext values are NEVER returned. `amba_secrets_list` returns
|
|
22
24
|
* name + version + sync_status (pending/syncing/synced/failed) only.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layers/amba-mcp",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.11",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
28
28
|
"zod": "^3.25.0",
|
|
29
|
-
"@layers/amba-shared": "4.0.
|
|
29
|
+
"@layers/amba-shared": "4.0.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22.10.2",
|