@layers/amba-mcp 4.0.6 → 4.0.7

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.
@@ -2,27 +2,35 @@
2
2
  * `registerCollectionToolsFor` — project ONE collection into a set of
3
3
  * typed MCP tools and register them on a server.
4
4
  *
5
- * Phase 1 = admin scope. Each tool is a thin proxy over the EXISTING
6
- * authoritative admin collection routes (`/v1/admin/projects/:p/
7
- * collections/:name/...`) — we do NOT reimplement any query logic. The
8
- * tool's value is the *projection*: typed per-column input + an SDK-grade
9
- * description, generated from the live schema (`schema-to-zod.ts` +
10
- * `describe.ts`).
5
+ * Two scopes, two enforcement paths — both thin proxies over EXISTING
6
+ * authoritative routes (we do NOT reimplement any query logic):
11
7
  *
12
- * Tools generated (verbs that map to a real admin route):
13
- * <ns>_<coll>_list → GET /collections/:name/rows?query=…
14
- * <ns>_<coll>_get → GET /collections/:name/rows/:id
15
- * <ns>_<coll>_find → GET /collections/:name/rows?query=… (typed where)
16
- * <ns>_<coll>_insert → POST /collections/:name/rows
17
- * <ns>_<coll>_update → PATCH /collections/:name/rows/:id
18
- * <ns>_<coll>_delete → DELETE /collections/:name/rows/:id
19
- * <ns>_<coll>_aggregate → POST /collections/:name/rows/aggregate
8
+ * - `admin` → `/v1/admin/projects/:p/collections/:name/rows*` with the
9
+ * developer Bearer (pat-as-argument machinery). No per-user scoping —
10
+ * the developer sees every row.
11
+ * - `client` → `/v1/client/collections/:name*` with the project API key
12
+ * + the end-user session Bearer. The client routes derive their SQL
13
+ * predicate from the migration-053 access policies
14
+ * (`_amba_collection_policies`) on every call, so the generated tools
15
+ * inherit RLS enforcement byte-for-byte from the REST surface — the
16
+ * MCP layer can't bypass a policy because it never compiles a query.
20
17
  *
21
- * `find_nearest` is intentionally Phase 2 (client scope + vector route).
18
+ * Tools generated (verbs that map to a real route):
19
+ * <ns>_<coll>_list → list rows (cursor pagination)
20
+ * <ns>_<coll>_get → one row by id
21
+ * <ns>_<coll>_find → typed per-column `where`
22
+ * <ns>_<coll>_insert → insert one row
23
+ * <ns>_<coll>_update → merge-patch one row
24
+ * <ns>_<coll>_delete → delete one row (hard-delete admin-only)
25
+ * <ns>_<coll>_aggregate → count/sum/avg/min/max
26
+ * <ns>_<coll>_find_nearest → vector search (client scope, only when the
27
+ * collection has a vector column — the route
28
+ * lives on the client surface)
22
29
  *
23
- * Auth: every tool goes through `registerTool` (the pat-as-argument
24
- * helper), so the developer Bearer flows from the inbound request OR a
25
- * per-call `pat` arg, exactly like the platform collection tools.
30
+ * Pagination: list/find default to `created_at desc` ordering when the
31
+ * caller gives no `order` — a deterministic single-column order is what
32
+ * makes the route hand back a bootstrap `next_cursor` on the FIRST page,
33
+ * so an agent can paginate without ever reading docs.
26
34
  */
27
35
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
28
36
  import type { ApiClient } from '../api-client.js';
@@ -33,6 +41,18 @@ export interface CollectionPolicy {
33
41
  read_policy: 'owner' | 'public';
34
42
  write_policy: 'owner' | 'authenticated';
35
43
  }
44
+ /**
45
+ * Client-scope credentials + addressing. `baseUrl` points at the client
46
+ * API surface (e.g. `https://api.amba.dev/v1/client`); `sessionToken` is
47
+ * the END-USER session JWT — absent for key-only callers, in which case
48
+ * the routes reject user-scoped operations themselves (thin proxy, no
49
+ * local policy logic).
50
+ */
51
+ export interface AppMcpClientAuth {
52
+ apiKey: string;
53
+ sessionToken?: string;
54
+ baseUrl: string;
55
+ }
36
56
  export interface RegisterCollectionToolsOptions {
37
57
  /** Project the collection belongs to. */
38
58
  projectId: string;
@@ -44,8 +64,10 @@ export interface RegisterCollectionToolsOptions {
44
64
  schema: CollectionSchemaPayload;
45
65
  /** The collection's effective access policy. */
46
66
  policy: CollectionPolicy;
47
- /** Scope to generate for. Phase 1 ships `admin`. */
67
+ /** Scope to generate for. */
48
68
  scope: ToolScope;
69
+ /** REQUIRED when `scope === 'client'` — the credentials to proxy with. */
70
+ clientAuth?: AppMcpClientAuth;
49
71
  }
50
72
  /**
51
73
  * Tool-name fragment regex. MCP + `tool-naming.test.ts` require lowercase
@@ -58,6 +80,6 @@ export declare function sanitizeNameFragment(raw: string): string;
58
80
  export declare function collectionToolName(namespace: string, collection: string, verb: string): string;
59
81
  /**
60
82
  * Register the typed CRUD tools for a single collection on `server`,
61
- * proxying to the existing admin routes via `apiClient`.
83
+ * proxying to the existing authoritative routes for the requested scope.
62
84
  */
63
85
  export declare function registerCollectionToolsFor(server: McpServer, apiClient: ApiClient, options: RegisterCollectionToolsOptions): void;
@@ -8,9 +8,10 @@
8
8
  * column names, types, nullability, the access policy in plain words, and
9
9
  * a worked example per verb.
10
10
  *
11
- * Pure string builders — snapshot-friendly, no I/O. NO provider leakage:
12
- * "collection", "row", "column", "function" only — never the underlying
13
- * storage engine.
11
+ * Pure string builders — snapshot-friendly, no I/O. Collections are named as
12
+ * what they are — relational Postgres tables. The hosting supplier (Neon) and
13
+ * the rest of the infra stack stay hidden: "collection", "row", "column",
14
+ * and "function" are the customer vocabulary, never a supplier name.
14
15
  */
15
16
  import { type MappedCollection } from './schema-to-zod.js';
16
17
  /** The verbs a collection projects into tools. */
@@ -35,5 +36,22 @@ export interface DescribeContext {
35
36
  export declare function describeCollectionTool(verb: CollectionVerb, ctx: DescribeContext): string;
36
37
  /** Description for the `<ns>_list_collections` meta tool. */
37
38
  export declare function describeListCollections(namespace: string): string;
39
+ /** Context for a function tool description. */
40
+ export interface DescribeFunctionContext {
41
+ /** Function name (customer-facing). */
42
+ fn: string;
43
+ /** Customer-declared tool description (deploy annotation), if any. */
44
+ declaredDescription: string | null;
45
+ /** Whether a declared input schema typed this tool. */
46
+ hasDeclaredSchema: boolean;
47
+ /** Whether the function was deployed `public: true`. */
48
+ isPublic: boolean;
49
+ }
50
+ /**
51
+ * Generate the description string for a function tool. Honest-confidence
52
+ * rule: a tool with a declared schema reads like a hand-built SDK call; a
53
+ * tool WITHOUT one says so plainly instead of over-claiming.
54
+ */
55
+ export declare function describeFunctionTool(ctx: DescribeFunctionContext): string;
38
56
  /** Description for the `<ns>_whoami` meta tool. */
39
57
  export declare function describeWhoami(namespace: string): string;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `registerFunctionToolsFor` — project ONE deployed function into an MCP
3
+ * tool (auto-MCP Phase 2, slices C/I).
4
+ *
5
+ * Execution is the EXISTING function-execution path: the tool handler
6
+ * POSTs to the function's `invoke_url` (from the manifest — the same URL
7
+ * every other caller uses) with the connection's client credential
8
+ * (`X-Api-Key` + optional end-user session Bearer). The execution edge
9
+ * remains authoritative for auth, rate limits, and identity-header
10
+ * signing — the MCP layer adds nothing it would have to keep in sync.
11
+ *
12
+ * CLIENT SCOPE ONLY. The function-execution path authenticates callers
13
+ * with a project API key (+ optional session); a developer Bearer is not
14
+ * a credential it accepts, so an admin-scoped connection gets no function
15
+ * tools (the meta tools say so) rather than tools that can only fail.
16
+ *
17
+ * Input typing (honest-confidence tiers):
18
+ * - declared `input_schema` (deploy annotation, validated subset) →
19
+ * fully typed tool; args ARE the request body.
20
+ * - no declared schema → generic `{ body?, query? }` wrapper with a
21
+ * description that says exactly that.
22
+ *
23
+ * Tool name: `<ns>_fn_<name>`. The `fn` infix keeps the function
24
+ * namespace disjoint from `<ns>_<collection>_<verb>` — a function named
25
+ * `recipes_list` can never collide with the typed tools of a collection
26
+ * named `recipes`.
27
+ */
28
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
29
+ import { type AppMcpClientAuth } from './collection-tools.js';
30
+ /** One exposed function from the app-MCP manifest. */
31
+ export interface AppMcpManifestFunction {
32
+ name: string;
33
+ description?: string | null;
34
+ input_schema?: Record<string, unknown> | null;
35
+ public?: boolean;
36
+ invoke_url: string;
37
+ }
38
+ export interface RegisterFunctionToolsOptions {
39
+ /** Tool-name namespace (sanitized app slug or project id). */
40
+ namespace: string;
41
+ /** Manifest entry for the function. */
42
+ fn: AppMcpManifestFunction;
43
+ /** Connection credentials proxied to the execution path. */
44
+ clientAuth: Pick<AppMcpClientAuth, 'apiKey' | 'sessionToken'>;
45
+ }
46
+ /** Build the `<ns>_fn_<name>` tool name. */
47
+ export declare function functionToolName(namespace: string, fn: string): string;
48
+ /**
49
+ * Register the tool for a single exposed function on `server`.
50
+ */
51
+ export declare function registerFunctionToolsFor(server: McpServer, options: RegisterFunctionToolsOptions): void;
@@ -2,46 +2,87 @@
2
2
  * Auto-MCP wedge entry — `registerAutoMcpTools`.
3
3
  *
4
4
  * The per-tenant MCP surface: instead of Amba's own platform tools, this
5
- * registers tools that ARE the customer's own collections, projected into
6
- * typed per-collection tools (`<ns>_<coll>_list/get/find/insert/update/
7
- * delete/aggregate`) plus two meta tools:
5
+ * registers tools that ARE the customer's own collections and deployed
6
+ * functions, projected into typed tools (`<ns>_<coll>_list/get/find/
7
+ * insert/update/delete/aggregate[/find_nearest]`, `<ns>_fn_<name>`) plus
8
+ * two meta tools:
8
9
  *
9
- * - `<ns>_list_collections` — the index of exposed collections.
10
+ * - `<ns>_list_collections` — the index of exposed collections/functions.
10
11
  * - `<ns>_whoami` — which project + scope this surface serves.
11
12
  *
12
- * Generation is LIVE (design doc §2.3): on registration we list the
13
- * project's collections and introspect each via the existing admin
14
- * routes, then project them. Stateless-per-request (the handler builds a
15
- * fresh server per HTTP request) makes this clean — no cache in Phase 1.
13
+ * GENERATION IS MANIFEST-ONLY (Phase 2). The `/app-mcp/manifest` payload
14
+ * is the single source of truth for what this surface exposes: it is
15
+ * built server-side from the project's EXPLICIT exposure allowlist
16
+ * (default-deny — slice H), so the tool layer can never register
17
+ * something the allowlist didn't opt in. The Phase-1 live-introspection
18
+ * fallback is gone for exactly that reason: a fallback that enumerates
19
+ * every collection would silently bypass the allowlist whenever the
20
+ * manifest endpoint hiccuped. Without a manifest, the meta tools register
21
+ * a clear diagnostic instead.
16
22
  *
17
- * Phase 1 = admin scope, collections only. Function tools, client scope,
18
- * and the manifest cache are later phases.
23
+ * Scopes:
24
+ * - `admin` — developer Bearer; collection tools proxy
25
+ * `/v1/admin/.../rows*`. Function tools do NOT register (the
26
+ * function-execution path authenticates with client keys, not
27
+ * developer Bearers).
28
+ * - `client` — project API key + optional end-user session
29
+ * (`options.clientAuth`); collection tools proxy
30
+ * `/v1/client/collections/*` (migration-053 policy enforcement on
31
+ * every call), function tools invoke through the function-execution
32
+ * path with the same credential.
19
33
  */
20
34
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
21
35
  import type { ApiClient } from '../api-client.js';
36
+ import { type AppMcpClientAuth } from './collection-tools.js';
37
+ import { type AppMcpManifestFunction } from './function-tools.js';
22
38
  import { type ToolScope } from './describe.js';
23
39
  import { mapCollectionSchema, type CollectionSchemaPayload } from './schema-to-zod.js';
40
+ /**
41
+ * One collection entry in the app-MCP manifest (the
42
+ * `GET /app-mcp/manifest` payload — see apps/api/src/lib/app-mcp-manifest.ts).
43
+ */
44
+ export interface AppMcpManifestCollection extends CollectionSchemaPayload {
45
+ read_policy?: 'owner' | 'public';
46
+ write_policy?: 'owner' | 'authenticated';
47
+ }
48
+ /** The app-MCP manifest payload. */
49
+ export interface AppMcpManifestPayload {
50
+ project_id: string;
51
+ version: number;
52
+ collections: AppMcpManifestCollection[];
53
+ /** Exposed deployed functions (Phase 2; older APIs omit the field). */
54
+ functions?: AppMcpManifestFunction[];
55
+ /** Surface config echo (Phase 2; older APIs omit these). */
56
+ enabled?: boolean;
57
+ auth_mode?: 'all' | 'client_only' | 'developer_only';
58
+ slug?: string | null;
59
+ }
24
60
  export interface RegisterAutoMcpOptions {
25
61
  /** Project whose collections become the tool surface. */
26
62
  projectId: string;
27
- /** Scope to generate. Phase 1 ships `admin`. */
63
+ /** Scope to generate. */
28
64
  scope: ToolScope;
29
65
  /**
30
- * Tool-name namespace. Defaults to a sanitized project id. A future
31
- * phase passes the project slug here so multiple connected apps don't
32
- * collide.
66
+ * The manifest (slice F cache). REQUIRED for any data tool to register
67
+ * — the manifest carries the server-enforced exposure allowlist, and
68
+ * registering anything without it would bypass that allowlist. Absent
69
+ * manifest → meta tools only, with a clear diagnostic.
70
+ */
71
+ manifest?: AppMcpManifestPayload;
72
+ /** Client-scope credentials + client API base URL. */
73
+ clientAuth?: AppMcpClientAuth;
74
+ /**
75
+ * Tool-name namespace. Defaults to the manifest's slug when set,
76
+ * otherwise a sanitized project id.
33
77
  */
34
78
  namespace?: string;
35
79
  }
36
80
  /**
37
81
  * Register the auto-MCP tool surface for one project on `server`.
38
82
  *
39
- * Lists + introspects the project's collections (admin routes) and
40
- * registers a typed tool set per collection, plus the two meta tools.
41
83
  * Returns the names of the collections that were exposed plus `listOk`
42
- * (false when the collection listing was incomplete — a paginated page
43
- * failed — in which case typed tools are deliberately NOT registered so a
44
- * truncated set never masquerades as the whole project).
84
+ * (false when no manifest was available — in which case NO data tools
85
+ * register and the meta tools carry the diagnostic).
45
86
  */
46
87
  export declare function registerAutoMcpTools(server: McpServer, apiClient: ApiClient, options: RegisterAutoMcpOptions): Promise<{
47
88
  namespace: string;
@@ -49,8 +90,11 @@ export declare function registerAutoMcpTools(server: McpServer, apiClient: ApiCl
49
90
  listOk: boolean;
50
91
  }>;
51
92
  export { registerCollectionToolsFor, collectionToolName, sanitizeNameFragment, } from './collection-tools.js';
52
- export type { CollectionPolicy, RegisterCollectionToolsOptions } from './collection-tools.js';
93
+ export type { AppMcpClientAuth, CollectionPolicy, RegisterCollectionToolsOptions, } from './collection-tools.js';
94
+ export { registerFunctionToolsFor, functionToolName } from './function-tools.js';
95
+ export type { AppMcpManifestFunction, RegisterFunctionToolsOptions } from './function-tools.js';
96
+ export { jsonSchemaPropertyToZod, jsonSchemaToZodShape } from './json-schema-to-zod.js';
53
97
  export { mapCollectionSchema };
54
98
  export type { CollectionSchemaPayload };
55
99
  export { classifyColumn, SERVER_MANAGED_COLUMNS, type CollectionColumn, type ColumnKind, type MappedCollection, } from './schema-to-zod.js';
56
- export { describeCollectionTool, describeListCollections, describeWhoami, type CollectionVerb, type DescribeContext, type ToolScope, } from './describe.js';
100
+ export { describeCollectionTool, describeFunctionTool, describeListCollections, describeWhoami, type CollectionVerb, type DescribeContext, type DescribeFunctionContext, type ToolScope, } from './describe.js';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Declared-function-input-schema → zod shape mapper (auto-MCP Phase 2,
3
+ * slices C/I).
4
+ *
5
+ * A deployed function may DECLARE its input schema in the deploy
6
+ * annotation (`mcp.input_schema`). The API validates the annotation down
7
+ * to a SUPPORTED SUBSET of JSON Schema at deploy time (see
8
+ * `apps/api/src/lib/function-mcp-schema.ts`); this module converts that
9
+ * subset into the `ZodRawShape` the MCP tool registration consumes, so a
10
+ * declared schema becomes a genuinely typed tool — the agent sees the
11
+ * function's real parameters, not a `body: object` blob.
12
+ *
13
+ * Supported subset (deliberately mirrored with the deploy-time
14
+ * validator — change both together):
15
+ *
16
+ * - top level: { type: "object", properties, required? }
17
+ * - property types: string | number | integer | boolean | object | array
18
+ * - per property: description?, enum? (strings/numbers), items?
19
+ * - nesting: objects/arrays up to the validator's depth cap
20
+ *
21
+ * Fail-safe posture: this runs against schemas the API already validated,
22
+ * but a manifest could carry an annotation written by an older/newer API.
23
+ * Any construct we can't map cleanly degrades to `z.unknown()` for that
24
+ * property (the tool still works; the typing is just looser) — never a
25
+ * throw, because a registration-time throw would take down the whole
26
+ * tool surface for one bad annotation.
27
+ */
28
+ import { z } from 'zod';
29
+ /** Convert one property schema to a zod type. Never throws. */
30
+ export declare function jsonSchemaPropertyToZod(schema: unknown): z.ZodTypeAny;
31
+ /**
32
+ * Convert a declared top-level input schema to a `ZodRawShape` (the MCP
33
+ * tool registration input). Returns `null` when the schema is not the
34
+ * supported `type: "object"` shape — the caller falls back to the
35
+ * generic `{ body?, query? }` tool input.
36
+ */
37
+ export declare function jsonSchemaToZodShape(schema: unknown): z.ZodRawShape | null;
@@ -305,7 +305,7 @@ All SDKs expose the same surface: \`Amba.configure({ projectId, apiKey })\`, the
305
305
  - **analytics** — funnels + retention. Query via \`amba_analytics_get\`.
306
306
 
307
307
  ### Infrastructure
308
- - **collections** — your own typed key-value tables. Define with \`amba_collections_create\`; read/write from SDK \`Amba.client.*\`.
308
+ - **collections** — 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.*\`.
309
309
  - **functions** — serverless TypeScript handlers. Deploy with \`amba_functions_deploy\`; schedule with \`amba_functions_schedule\`.
310
310
  - **sites** — static site hosting at \`*.app.amba.host\`. Deploy with \`amba_sites_deploy\`.
311
311
  - **media** — file storage + CDN. Upload via \`amba_media_upload\`.
@@ -391,7 +391,7 @@ That's the entire setup. The CLI:
391
391
  detects on disk — Claude Code, Cursor, Windsurf.
392
392
  6. Verifies the PAT against the API and confirms it's good.
393
393
 
394
- The Amba MCP toolset (\`amba_*\` tools — ~130 of them) is available to
394
+ The Amba MCP toolset (\`amba_*\` tools — 500+ of them) is available to
395
395
  the agent immediately: pass the freshly-minted \`pat\` as an inline
396
396
  argument on every \`amba_*\` call in the current session. The next time
397
397
  your MCP client starts it picks the PAT up from the config as the
package/dist/index.d.ts CHANGED
@@ -41,5 +41,5 @@ export declare function createApiClient(options: {
41
41
  }): ApiClient;
42
42
  export { ApiClient } from './api-client.js';
43
43
  export type { ApiClientOptions } from './api-client.js';
44
- export { registerAutoMcpTools, registerCollectionToolsFor, collectionToolName, sanitizeNameFragment, mapCollectionSchema, classifyColumn, describeCollectionTool, describeListCollections, describeWhoami, SERVER_MANAGED_COLUMNS, } from './auto/index.js';
45
- export type { RegisterAutoMcpOptions, CollectionPolicy, RegisterCollectionToolsOptions, CollectionSchemaPayload, CollectionColumn, ColumnKind, MappedCollection, CollectionVerb, DescribeContext, ToolScope, } from './auto/index.js';
44
+ export { registerAutoMcpTools, registerCollectionToolsFor, registerFunctionToolsFor, collectionToolName, functionToolName, sanitizeNameFragment, mapCollectionSchema, classifyColumn, describeCollectionTool, describeFunctionTool, describeListCollections, describeWhoami, jsonSchemaToZodShape, SERVER_MANAGED_COLUMNS, } from './auto/index.js';
45
+ export type { RegisterAutoMcpOptions, AppMcpClientAuth, AppMcpManifestPayload, AppMcpManifestCollection, AppMcpManifestFunction, CollectionPolicy, RegisterCollectionToolsOptions, RegisterFunctionToolsOptions, CollectionSchemaPayload, CollectionColumn, ColumnKind, MappedCollection, CollectionVerb, DescribeContext, DescribeFunctionContext, ToolScope, } from './auto/index.js';