diff --git a/products/messaging/backend/presentation/views/supabase_auth_emails.py b/products/messaging/backend/presentation/views/supabase_auth_emails.py index 86870cc2bd39..d2e8caa42663 100644 --- a/products/messaging/backend/presentation/views/supabase_auth_emails.py +++ b/products/messaging/backend/presentation/views/supabase_auth_emails.py @@ -110,20 +110,24 @@ class SupabaseAuthEmailSettingsUpdateSerializer(serializers.Serializer): required=False, allow_blank=True, max_length=200, - help_text="The Supabase project URL, such as https://abcdefgh.supabase.co.", + help_text="The Supabase project URL, such as https://abcdefgh.supabase.co, from the project's API settings in " + "the Supabase dashboard. It must use https.", ) hook_secret = serializers.CharField( required=False, allow_blank=True, write_only=True, max_length=500, - help_text="The Send Email Hook secret from Supabase, starting with v1,whsec_. Leave it out to keep the " - "stored secret.", + help_text="The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, " + "Hooks, Send Email hook. Leave it out to keep the stored secret.", ) templates = serializers.DictField( child=serializers.UUIDField(), required=False, - help_text="Supabase email action type to transactional message template id. Replaces the whole mapping. " + help_text="Supabase email action type to the id of the email template that sends it. Each template must be " + "transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a " + "type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no " + "template is skipped. " f"Valid action types: {', '.join(SupabaseEmailActionType.values)}.", ) diff --git a/products/messaging/frontend/generated/api.schemas.ts b/products/messaging/frontend/generated/api.schemas.ts index 2aa414b86e9b..125a6803e445 100644 --- a/products/messaging/frontend/generated/api.schemas.ts +++ b/products/messaging/frontend/generated/api.schemas.ts @@ -444,22 +444,22 @@ export interface SupabaseAuthEmailSettingsApi { } /** - * Supabase email action type to transactional message template id. Replaces the whole mapping. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. + * Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ export type PatchedSupabaseAuthEmailSettingsUpdateApiTemplates = { [key: string]: string } export interface PatchedSupabaseAuthEmailSettingsUpdateApi { /** - * The Supabase project URL, such as https://abcdefgh.supabase.co. + * The Supabase project URL, such as https://abcdefgh.supabase.co, from the project's API settings in the Supabase dashboard. It must use https. * @maxLength 200 */ supabase_url?: string /** - * The Send Email Hook secret from Supabase, starting with v1,whsec_. Leave it out to keep the stored secret. + * The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, Hooks, Send Email hook. Leave it out to keep the stored secret. * @maxLength 500 */ hook_secret?: string - /** Supabase email action type to transactional message template id. Replaces the whole mapping. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ + /** Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ templates?: PatchedSupabaseAuthEmailSettingsUpdateApiTemplates } diff --git a/products/messaging/frontend/generated/api.zod.ts b/products/messaging/frontend/generated/api.zod.ts index 79bd590cd7fc..c877138543ae 100644 --- a/products/messaging/frontend/generated/api.zod.ts +++ b/products/messaging/frontend/generated/api.zod.ts @@ -438,19 +438,21 @@ export const MessagingSupabaseAuthEmailsSettingsPartialUpdateBody = /* @__PURE__ .string() .max(messagingSupabaseAuthEmailsSettingsPartialUpdateBodySupabaseUrlMax) .optional() - .describe('The Supabase project URL, such as https:\/\/abcdefgh.supabase.co.'), + .describe( + "The Supabase project URL, such as https:\/\/abcdefgh.supabase.co, from the project's API settings in the Supabase dashboard. It must use https." + ), hook_secret: zod .string() .max(messagingSupabaseAuthEmailsSettingsPartialUpdateBodyHookSecretMax) .optional() .describe( - 'The Send Email Hook secret from Supabase, starting with v1,whsec_. Leave it out to keep the stored secret.' + 'The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, Hooks, Send Email hook. Leave it out to keep the stored secret.' ), templates: zod .record(zod.string(), zod.uuid()) .optional() .describe( - 'Supabase email action type to transactional message template id. Replaces the whole mapping. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification.' + 'Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification.' ), }) diff --git a/products/messaging/mcp/tools.yaml b/products/messaging/mcp/tools.yaml index cf44c7a2922c..e6af4c43aa39 100644 --- a/products/messaging/mcp/tools.yaml +++ b/products/messaging/mcp/tools.yaml @@ -113,3 +113,53 @@ tools: description: > Opt a recipient back in to the message category named by category_key, or to all marketing messages if omitted. Use to honor a resubscribe recorded in your own app. Repeating a call is safe. + supabase-auth-emails-settings-get: + operation: messaging_supabase_auth_emails_settings_retrieve + enabled: true + scopes: + - hog_flow:read + title: Get the Supabase auth email settings + description: > + Get how the project sends a Supabase project's auth emails through PostHog email templates, including the + hook URL to paste into Supabase and every email type it can map. Call this before + supabase-auth-emails-settings-update, because that tool replaces the whole template mapping. + feature_flag: workflows-supabase-auth-emails + supabase-auth-emails-settings-update: + operation: messaging_supabase_auth_emails_settings_partial_update + enabled: true + scopes: + - hog_flow:write + annotations: + readOnly: false + destructive: true + idempotent: true + title: Update the Supabase auth email settings + description: > + Update how the project sends a Supabase project's auth emails. Send only the fields to change. To get + templates to map, call supabase-auth-emails-starter-templates-create or use the email template tools. Ask + the user for the hook secret. Never invent one. Sending starts when the user turns on the Send Email hook in + Supabase, so map the core emails before telling them to. + feature_flag: workflows-supabase-auth-emails + response: + exclude: + - email_types + - hook_url + supabase-auth-emails-starter-templates-create: + operation: messaging_supabase_auth_emails_starter_templates_create + enabled: true + scopes: + - hog_flow:write + annotations: + readOnly: false + destructive: false + idempotent: false + title: Create starter templates for the Supabase auth emails + description: > + Create and map an email template for each core Supabase auth email that has no usable template yet. A repeat + call skips types that still have one. Needs a verified email sender on the project. Edit the templates + afterwards with the email template tools. + feature_flag: workflows-supabase-auth-emails + response: + exclude: + - email_types + - hook_url diff --git a/services/mcp/schema/generated-tool-definitions.json b/services/mcp/schema/generated-tool-definitions.json index 94d0efe8e4cf..aead31676637 100644 --- a/services/mcp/schema/generated-tool-definitions.json +++ b/services/mcp/schema/generated-tool-definitions.json @@ -14254,6 +14254,54 @@ "readOnlyHint": false } }, + "supabase-auth-emails-settings-get": { + "description": "Get how the project sends a Supabase project's auth emails through PostHog email templates, including the hook URL to paste into Supabase and every email type it can map. Call this before supabase-auth-emails-settings-update, because that tool replaces the whole template mapping.", + "category": "Messaging", + "feature": "messaging", + "summary": "Get the Supabase auth email settings", + "title": "Get the Supabase auth email settings", + "required_scopes": ["hog_flow:read"], + "api_operations": ["GET /api/projects/{project_id}/messaging_supabase_auth_emails/settings/"], + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true + }, + "feature_flag": "workflows-supabase-auth-emails" + }, + "supabase-auth-emails-settings-update": { + "description": "Update how the project sends a Supabase project's auth emails. Send only the fields to change. To get templates to map, call supabase-auth-emails-starter-templates-create or use the email template tools. Ask the user for the hook secret. Never invent one. Sending starts when the user turns on the Send Email hook in Supabase, so map the core emails before telling them to.", + "category": "Messaging", + "feature": "messaging", + "summary": "Update the Supabase auth email settings", + "title": "Update the Supabase auth email settings", + "required_scopes": ["hog_flow:write"], + "api_operations": ["PATCH /api/projects/{project_id}/messaging_supabase_auth_emails/settings/"], + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false + }, + "feature_flag": "workflows-supabase-auth-emails" + }, + "supabase-auth-emails-starter-templates-create": { + "description": "Create and map an email template for each core Supabase auth email that has no usable template yet. A repeat call skips types that still have one. Needs a verified email sender on the project. Edit the templates afterwards with the email template tools.", + "category": "Messaging", + "feature": "messaging", + "summary": "Create starter templates for the Supabase auth emails", + "title": "Create starter templates for the Supabase auth emails", + "required_scopes": ["hog_flow:write"], + "api_operations": ["POST /api/projects/{project_id}/messaging_supabase_auth_emails/starter_templates/"], + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false + }, + "feature_flag": "workflows-supabase-auth-emails" + }, "survey-create": { "description": "Creates a new survey in the project. For the draft, targeting, preview, and launch workflow, load the creating-surveys skill when available. Use this for both in-app surveys and hosted forms. Prefer draft creation by default and do not set start_date unless the user explicitly asks to launch immediately. For in-app surveys, popover is the default unless the user asks for widget or api. For hosted forms, use external_survey. Keep surveys short unless the user asks for a longer flow. Survey content is public: anyone can read the name, questions, and appearance text. In-app surveys send them to every visitor's browser, and a hosted survey shows them on its public page. Tell the user before putting a customer name or other private detail in a survey. For substantial visual changes, preview the final draft once before launch if browser access is already available. Skip browser checks for small edits.", "category": "Surveys", diff --git a/services/mcp/schema/tool-definitions-all.json b/services/mcp/schema/tool-definitions-all.json index 0abd96fab2a8..125c98e21268 100644 --- a/services/mcp/schema/tool-definitions-all.json +++ b/services/mcp/schema/tool-definitions-all.json @@ -14943,6 +14943,54 @@ "readOnlyHint": false } }, + "supabase-auth-emails-settings-get": { + "description": "Get how the project sends a Supabase project's auth emails through PostHog email templates, including the hook URL to paste into Supabase and every email type it can map. Call this before supabase-auth-emails-settings-update, because that tool replaces the whole template mapping.", + "category": "Messaging", + "feature": "messaging", + "summary": "Get the Supabase auth email settings", + "title": "Get the Supabase auth email settings", + "required_scopes": ["hog_flow:read"], + "api_operations": ["GET /api/projects/{project_id}/messaging_supabase_auth_emails/settings/"], + "annotations": { + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": true + }, + "feature_flag": "workflows-supabase-auth-emails" + }, + "supabase-auth-emails-settings-update": { + "description": "Update how the project sends a Supabase project's auth emails. Send only the fields to change. To get templates to map, call supabase-auth-emails-starter-templates-create or use the email template tools. Ask the user for the hook secret. Never invent one. Sending starts when the user turns on the Send Email hook in Supabase, so map the core emails before telling them to.", + "category": "Messaging", + "feature": "messaging", + "summary": "Update the Supabase auth email settings", + "title": "Update the Supabase auth email settings", + "required_scopes": ["hog_flow:write"], + "api_operations": ["PATCH /api/projects/{project_id}/messaging_supabase_auth_emails/settings/"], + "annotations": { + "destructiveHint": true, + "idempotentHint": true, + "openWorldHint": true, + "readOnlyHint": false + }, + "feature_flag": "workflows-supabase-auth-emails" + }, + "supabase-auth-emails-starter-templates-create": { + "description": "Create and map an email template for each core Supabase auth email that has no usable template yet. A repeat call skips types that still have one. Needs a verified email sender on the project. Edit the templates afterwards with the email template tools.", + "category": "Messaging", + "feature": "messaging", + "summary": "Create starter templates for the Supabase auth emails", + "title": "Create starter templates for the Supabase auth emails", + "required_scopes": ["hog_flow:write"], + "api_operations": ["POST /api/projects/{project_id}/messaging_supabase_auth_emails/starter_templates/"], + "annotations": { + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true, + "readOnlyHint": false + }, + "feature_flag": "workflows-supabase-auth-emails" + }, "survey-create": { "description": "Creates a new survey in the project. For the draft, targeting, preview, and launch workflow, load the creating-surveys skill when available. Use this for both in-app surveys and hosted forms. Prefer draft creation by default and do not set start_date unless the user explicitly asks to launch immediately. For in-app surveys, popover is the default unless the user asks for widget or api. For hosted forms, use external_survey. Keep surveys short unless the user asks for a longer flow. Survey content is public: anyone can read the name, questions, and appearance text. In-app surveys send them to every visitor's browser, and a hosted survey shows them on its public page. Tell the user before putting a customer name or other private detail in a survey. For substantial visual changes, preview the final draft once before launch if browser access is already available. Skip browser checks for small edits.", "category": "Surveys", diff --git a/services/mcp/src/api/generated.ts b/services/mcp/src/api/generated.ts index e959a2be3b46..62e36f5fd50a 100644 --- a/services/mcp/src/api/generated.ts +++ b/services/mcp/src/api/generated.ts @@ -92151,22 +92151,22 @@ export namespace Schemas { } /** - * Supabase email action type to transactional message template id. Replaces the whole mapping. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. + * Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ export type PatchedSupabaseAuthEmailSettingsUpdateTemplates = {[key: string]: string}; export interface PatchedSupabaseAuthEmailSettingsUpdate { /** - * The Supabase project URL, such as https://abcdefgh.supabase.co. + * The Supabase project URL, such as https://abcdefgh.supabase.co, from the project's API settings in the Supabase dashboard. It must use https. * @maxLength 200 */ supabase_url?: string; /** - * The Send Email Hook secret from Supabase, starting with v1,whsec_. Leave it out to keep the stored secret. + * The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, Hooks, Send Email hook. Leave it out to keep the stored secret. * @maxLength 500 */ hook_secret?: string; - /** Supabase email action type to transactional message template id. Replaces the whole mapping. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ + /** Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification. */ templates?: PatchedSupabaseAuthEmailSettingsUpdateTemplates; } diff --git a/services/mcp/src/generated/messaging/api.ts b/services/mcp/src/generated/messaging/api.ts index a4fca0f98805..78578e13771e 100644 --- a/services/mcp/src/generated/messaging/api.ts +++ b/services/mcp/src/generated/messaging/api.ts @@ -3,7 +3,7 @@ * MCP service uses these Zod schemas for generated tool handlers. * To regenerate: hogli build:openapi * - * PostHog API - MCP 7 enabled ops + * PostHog API - MCP 10 enabled ops * OpenAPI spec version: 1.0.0 */ import * as zod from 'zod' @@ -197,3 +197,66 @@ export const MessagingPreferencesRemoveOptOutCreateBody = () => zod.object({ 'Optional message category key. If omitted, the recipient is opted back in to all marketing messages.' ), }) + +/** + * Send a Supabase project's auth emails through transactional email templates. + * @summary Get the Supabase auth email settings + */ +export const MessagingSupabaseAuthEmailsSettingsRetrieveParams = () => zod.object({ + project_id: zod + .string() + .describe( + "Project ID of the project you're trying to access. To find the ID of the project, make a call to \/api\/projects\/." + ), +}) + +/** + * Send a Supabase project's auth emails through transactional email templates. + * @summary Update the Supabase auth email settings + */ +export const MessagingSupabaseAuthEmailsSettingsPartialUpdateParams = () => zod.object({ + project_id: zod + .string() + .describe( + "Project ID of the project you're trying to access. To find the ID of the project, make a call to \/api\/projects\/." + ), +}) + +export const messagingSupabaseAuthEmailsSettingsPartialUpdateBodySupabaseUrlMax = 200 + +export const messagingSupabaseAuthEmailsSettingsPartialUpdateBodyHookSecretMax = 500 + +export const MessagingSupabaseAuthEmailsSettingsPartialUpdateBody = () => zod.object({ + supabase_url: zod + .string() + .max(messagingSupabaseAuthEmailsSettingsPartialUpdateBodySupabaseUrlMax) + .optional() + .describe( + "The Supabase project URL, such as https:\/\/abcdefgh.supabase.co, from the project's API settings in the Supabase dashboard. It must use https." + ), + hook_secret: zod + .string() + .max(messagingSupabaseAuthEmailsSettingsPartialUpdateBodyHookSecretMax) + .optional() + .describe( + 'The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, Hooks, Send Email hook. Leave it out to keep the stored secret.' + ), + templates: zod + .record(zod.string(), zod.string()) + .optional() + .describe( + 'Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification.' + ), +}) + +/** + * Create a transactional template for each core Supabase auth email that has no template yet, and map it. Needs a verified email sender. + * @summary Create starter templates for the Supabase auth emails + */ +export const MessagingSupabaseAuthEmailsStarterTemplatesCreateParams = () => zod.object({ + project_id: zod + .string() + .describe( + "Project ID of the project you're trying to access. To find the ID of the project, make a call to \/api\/projects\/." + ), +}) diff --git a/services/mcp/src/tools/generated/messaging.ts b/services/mcp/src/tools/generated/messaging.ts index 668db51e625c..5f53d3aa0faf 100644 --- a/services/mcp/src/tools/generated/messaging.ts +++ b/services/mcp/src/tools/generated/messaging.ts @@ -3,7 +3,7 @@ import { z } from 'zod' import type { Schemas } from '@/api/generated' import * as orvalSchemas from '@/generated/messaging/api' -import { withPostHogUrl, type WithPostHogUrl } from '@/tools/tool-utils' +import { withPostHogUrl, omitResponseFields, type WithPostHogUrl } from '@/tools/tool-utils' import type { Context, ToolBase, ZodObjectAny } from '@/tools/types' const MessageCategoriesCreateSchema = () => { @@ -201,6 +201,80 @@ const optOutsRemove = (): ToolBase, Schem }, }) +const SupabaseAuthEmailsSettingsGetSchema = () => z.object({}) + +const supabaseAuthEmailsSettingsGet = (): ToolBase< + ReturnType, + Schemas.SupabaseAuthEmailSettings +> => ({ + name: 'supabase-auth-emails-settings-get', + schema: SupabaseAuthEmailsSettingsGetSchema(), + handler: async (context: Context, _params: z.infer>) => { + const projectId = await context.stateManager.getProjectId() + const result = await context.api.request({ + method: 'GET', + path: `/api/projects/${encodeURIComponent(String(projectId))}/messaging_supabase_auth_emails/settings/`, + }) + return result + }, +}) + +const SupabaseAuthEmailsSettingsUpdateSchema = () => { + const MessagingSupabaseAuthEmailsSettingsPartialUpdateBody = + orvalSchemas.MessagingSupabaseAuthEmailsSettingsPartialUpdateBody() + return MessagingSupabaseAuthEmailsSettingsPartialUpdateBody +} + +const supabaseAuthEmailsSettingsUpdate = (): ToolBase< + ReturnType, + Schemas.SupabaseAuthEmailSettings +> => ({ + name: 'supabase-auth-emails-settings-update', + schema: SupabaseAuthEmailsSettingsUpdateSchema(), + handler: async (context: Context, params: z.infer>) => { + const projectId = await context.stateManager.getProjectId() + const body: Record = {} + if (params.supabase_url !== undefined) { + body['supabase_url'] = params.supabase_url + } + if (params.hook_secret !== undefined) { + body['hook_secret'] = params.hook_secret + } + if (params.templates !== undefined) { + body['templates'] = params.templates + } + const result = await context.api.request({ + method: 'PATCH', + path: `/api/projects/${encodeURIComponent(String(projectId))}/messaging_supabase_auth_emails/settings/`, + body, + }) + const filtered = omitResponseFields(result, ['email_types', 'hook_url']) as typeof result + return filtered + }, +}) + +const SupabaseAuthEmailsStarterTemplatesCreateSchema = () => z.object({}) + +const supabaseAuthEmailsStarterTemplatesCreate = (): ToolBase< + ReturnType, + Schemas.SupabaseAuthEmailSettings +> => ({ + name: 'supabase-auth-emails-starter-templates-create', + schema: SupabaseAuthEmailsStarterTemplatesCreateSchema(), + handler: async ( + context: Context, + _params: z.infer> + ) => { + const projectId = await context.stateManager.getProjectId() + const result = await context.api.request({ + method: 'POST', + path: `/api/projects/${encodeURIComponent(String(projectId))}/messaging_supabase_auth_emails/starter_templates/`, + }) + const filtered = omitResponseFields(result, ['email_types', 'hook_url']) as typeof result + return filtered + }, +}) + export const GENERATED_TOOLS: Record ToolBase> = { 'message-categories-create': messageCategoriesCreate, 'message-categories-get': messageCategoriesGet, @@ -209,4 +283,7 @@ export const GENERATED_TOOLS: Record ToolBase> = { 'opt-outs-add': optOutsAdd, 'opt-outs-list': optOutsList, 'opt-outs-remove': optOutsRemove, + 'supabase-auth-emails-settings-get': supabaseAuthEmailsSettingsGet, + 'supabase-auth-emails-settings-update': supabaseAuthEmailsSettingsUpdate, + 'supabase-auth-emails-starter-templates-create': supabaseAuthEmailsStarterTemplatesCreate, } diff --git a/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-get.json b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-get.json new file mode 100644 index 000000000000..7b7ea9186078 --- /dev/null +++ b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-get.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": {}, + "type": "object" +} diff --git a/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-update.json b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-update.json new file mode 100644 index 000000000000..0896e00489af --- /dev/null +++ b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-settings-update.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "hook_secret": { + "description": "The Send Email Hook secret, starting with v1,whsec_. Supabase generates it under Authentication, Hooks, Send Email hook. Leave it out to keep the stored secret.", + "maxLength": 500, + "type": "string" + }, + "supabase_url": { + "description": "The Supabase project URL, such as https://abcdefgh.supabase.co, from the project's API settings in the Supabase dashboard. It must use https.", + "maxLength": 200, + "type": "string" + }, + "templates": { + "additionalProperties": { + "type": "string" + }, + "description": "Supabase email action type to the id of the email template that sends it. Each template must be transactional and marked sensitive. This replaces the whole mapping: include every type to keep, and leave a type out to unmap it. A core auth email with no template fails in Supabase, and a notification with no template is skipped. Valid action types: signup, invite, magiclink, email, recovery, email_change, reauthentication, password_changed_notification, email_changed_notification, phone_changed_notification, identity_linked_notification, identity_unlinked_notification, mfa_factor_enrolled_notification, mfa_factor_unenrolled_notification.", + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" +} diff --git a/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-starter-templates-create.json b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-starter-templates-create.json new file mode 100644 index 000000000000..7b7ea9186078 --- /dev/null +++ b/services/mcp/tests/unit/__snapshots__/tool-schemas/supabase-auth-emails-starter-templates-create.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": {}, + "type": "object" +} diff --git a/services/mcp/tests/unit/tool-filtering.test.ts b/services/mcp/tests/unit/tool-filtering.test.ts index 0d4c976dc00f..627ac57363b4 100644 --- a/services/mcp/tests/unit/tool-filtering.test.ts +++ b/services/mcp/tests/unit/tool-filtering.test.ts @@ -1095,6 +1095,7 @@ describe('Tool Filtering - Feature Flags', () => { it('getRequiredFeatureFlags should return flags used by current definitions', () => { const allFlags = getRequiredFeatureFlags() const branchFlags = [ + 'workflows-supabase-auth-emails', 'scout-trials', 'business-knowledge-github-repos', 'signals-report-checks-replace', diff --git a/services/mcp/tests/unit/tool-schema-snapshots.test.ts b/services/mcp/tests/unit/tool-schema-snapshots.test.ts index e320bd38f4da..2e9201c84a7d 100644 --- a/services/mcp/tests/unit/tool-schema-snapshots.test.ts +++ b/services/mcp/tests/unit/tool-schema-snapshots.test.ts @@ -102,6 +102,7 @@ async function loadSnapshotTools(): Promise[]> { 'inbox-report-actions-mcp': true, 'signals-reviewer-exclusions-mcp': true, 'ai-observability-offline-evaluations': true, + 'workflows-supabase-auth-emails': true, 'warehouse-suggestions': true, 'scouts-tool-access': true, 'subscription-source-summaries': true,