diff --git a/.changeset/fix-member-directory-tools-count.md b/.changeset/fix-member-directory-tools-count.md new file mode 100644 index 0000000000..76e05f9cfc --- /dev/null +++ b/.changeset/fix-member-directory-tools-count.md @@ -0,0 +1,4 @@ +--- +--- + +Fix member directory agent detail modal showing "Tools: 0" by including tools_count and tools in the /api/public/discover-agent response. Tools are stripped to {name, description} before serialization; inputSchema is not exposed. diff --git a/dist/schemas/member-agents-openapi.js b/dist/schemas/member-agents-openapi.js index ade3e163f1..ca72c44652 100644 --- a/dist/schemas/member-agents-openapi.js +++ b/dist/schemas/member-agents-openapi.js @@ -31,37 +31,53 @@ const MemberAgentTypeSchema = z 'unknown', ]) .openapi('MemberAgentType', { - description: "Agent type. Resolved server-side from the agent's capability snapshot when one exists; the value submitted by the client is used only as a fallback when no snapshot is available, and is never trusted to override an inferred classification.", + description: "Agent type as stored on the registry. Server-side smuggle protection compares the caller's declaration against the capability snapshot (when one exists) and may stamp `unknown` if the snapshot contradicts the declaration without classifying it. `unknown` is reserved for that server-side outcome; clients cannot submit it.", +}); +const MemberAgentTypeInputSchema = z + .enum([ + 'brand', + 'rights', + 'measurement', + 'governance', + 'creative', + 'sales', + 'buying', + 'signals', +]) + .openapi('MemberAgentTypeInput', { + description: "Agent type the caller declares. Required on register; smuggle-protection still cross-checks against the capability snapshot when one exists. The server never infers `type` — the owner declares what kind of agent this is.", }); const MemberAgentSchema = z .object({ url: z.string().url().openapi({ example: 'https://agent.example.com/mcp' }), visibility: MemberAgentVisibilitySchema, + type: MemberAgentTypeSchema, name: z.string().optional(), - type: MemberAgentTypeSchema.optional(), health_check_url: z.string().url().optional().openapi({ description: 'Optional fallback liveness URL used by the health probe when the protocol handshake fails.', }), }) - .openapi('MemberAgent', { description: 'Agent entry stored on a member profile.' }); + .openapi('MemberAgent', { + description: "Agent entry stored on a member profile. `type` is required on read because every write surface declares it and the operator endpoint always emits it; a stored value of `unknown` is the smuggle-protection outcome (snapshot contradicted the declaration without classifying it) and is the only path that surfaces an agent without a real type.", +}); const MemberAgentInputSchema = z .object({ url: z.string().url().openapi({ example: 'https://agent.example.com/mcp' }), + type: MemberAgentTypeInputSchema, name: z.string().optional(), visibility: MemberAgentVisibilitySchema.optional(), - type: MemberAgentTypeSchema.optional(), health_check_url: z.string().url().optional(), }) - .openapi('MemberAgentInput', { description: 'Request body for `POST /api/me/agents`.' }); + .openapi('MemberAgentInput', { description: 'Request body for `POST /api/me/agents`. `type` is required — the owner declares it; the server never infers.' }); const MemberAgentPatchSchema = z .object({ name: z.string().optional(), visibility: MemberAgentVisibilitySchema.optional(), - type: MemberAgentTypeSchema.optional(), + type: MemberAgentTypeInputSchema.optional(), health_check_url: z.string().url().optional(), }) .openapi('MemberAgentPatch', { - description: 'Request body for `PATCH /api/me/agents/{url}`. The `url` field cannot be changed via PATCH; re-register at the new URL and DELETE the old entry instead.', + description: 'Request body for `PATCH /api/me/agents/{url}`. The `url` field cannot be changed via PATCH; re-register at the new URL and DELETE the old entry instead. If `type` is omitted, the existing value is preserved.', }); const MemberAgentVisibilityWarningSchema = z .object({ @@ -79,6 +95,12 @@ const MemberAgentResponseSchema = z .object({ agent: MemberAgentSchema, warnings: z.array(MemberAgentVisibilityWarningSchema).optional(), + org_auto_created: z.boolean().optional().openapi({ + description: "Set to `true` when this `POST` was the caller's first interaction with the registry and the server auto-created the organization (display name derived from the user's email domain for corporate emails, or `'s Workspace` for free-email providers). Combined with `profile_auto_created`, this is the one-call storefront experience: a third-party app holding only an OAuth token gets the org, profile, and registered agent in a single request.", + }), + profile_auto_created: z.boolean().optional().openapi({ + description: 'Set to `true` when this `POST` was the first agent registration on the caller\'s organization and the server auto-created a private member profile (display name = organization name, `is_public: false`). Absent on subsequent calls and on update-in-place. Surfaced so storefront-style integrations can show a "we set up your profile" hint without needing to detect the prior 404 → bootstrap → retry shape.', + }), }) .openapi('MemberAgentResponse'); const MemberAgentListResponseSchema = z @@ -126,7 +148,11 @@ registry.registerPath({ description: [ "Register an agent on the caller's organization member profile.", 'Idempotent on `url`: re-posting the same `url` updates the entry in place rather than creating a duplicate. New entries return `201`; updates return `200`.', - "The `type` field is resolved server-side from the agent's capability snapshot — a client cannot pin a misclassification (e.g. registering a sales agent as `buying`).", + "**True one-call storefront experience.** A third-party app holding only a user's OAuth token can `POST /api/me/agents` once and have the entire bootstrap chain materialize:", + "- If the caller has zero org memberships, the server auto-creates an organization (corporate or personal workspace based on the user's email domain) and the response includes `org_auto_created: true`.", + "- If the caller's org has no member profile, the server auto-creates a private profile (display name = organization name, `is_public: false`) and the response includes `profile_auto_created: true`.", + "Both auto-bootstraps are best-effort fallbacks. To customize org name / company_type / revenue_tier, or to control profile slug / brand identity / tagline, call `POST /api/organizations` and `POST /api/me/member-profile` explicitly before registering the agent. Tier transitions never happen via this path — go through the billing flow.", + "`type` is required and declared by the caller — the server does not infer it. Server-side smuggle protection still cross-checks the declared type against the agent's capability snapshot when one exists; if the snapshot contradicts the declaration without classifying it, the stored value is `unknown` and the dashboard surfaces the conflict for the owner to resolve.", '`visibility: "public"` requires Professional tier or higher and a `primary_brand_domain` set on the profile. Non-API-tier callers who request `public` will have the entry stored as `members_only` instead, and the response will include a `visibility_downgraded` warning describing the coercion.', ].join('\n\n'), tags: ['Member Agents'], @@ -141,11 +167,11 @@ registry.registerPath({ content: { 'application/json': { schema: MemberAgentResponseSchema } }, }, 201: { - description: 'Agent registered.', + description: 'Agent registered. When this is the first agent on a freshly created organization, the response includes `profile_auto_created: true`.', content: { 'application/json': { schema: MemberAgentResponseSchema } }, }, 400: { - description: 'Missing or invalid `url`, or no organization associated with this account.', + description: 'Missing or invalid `url`, missing/invalid `type`, or the caller has memberships in other orgs but no primary org set — pass `?org=` to target one explicitly. (Fresh users with no memberships at all hit the org auto-bootstrap path and do not see this error.)', content: { 'application/json': { schema: ErrorSchema } }, }, 401: { @@ -157,7 +183,7 @@ registry.registerPath({ content: { 'application/json': { schema: ErrorSchema } }, }, 404: { - description: 'No member profile exists yet — create one via `POST /api/me/member-profile`.', + description: 'Auto-bootstrap could not run (e.g. the organization has no name yet). Call `POST /api/me/member-profile` to create a profile explicitly, then retry.', content: { 'application/json': { schema: ErrorSchema } }, }, 429: { diff --git a/dist/schemas/member-agents-openapi.js.map b/dist/schemas/member-agents-openapi.js.map index 4ef71556e9..a5bc854299 100644 --- a/dist/schemas/member-agents-openapi.js.map +++ b/dist/schemas/member-agents-openapi.js.map @@ -1 +1 @@ -{"version":3,"file":"member-agents-openapi.js","sourceRoot":"","sources":["../../server/src/schemas/member-agents-openapi.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"member-agents-openapi.js","sourceRoot":"","sources":["../../server/src/schemas/member-agents-openapi.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/schemas/onboarding-openapi.d.ts b/dist/schemas/onboarding-openapi.d.ts new file mode 100644 index 0000000000..ed29eaf6de --- /dev/null +++ b/dist/schemas/onboarding-openapi.d.ts @@ -0,0 +1,27 @@ +/** + * OpenAPI registrations for the onboarding REST surface. + * + * `POST /api/organizations` has existed in production for a long time but + * has only ever been documented as a private endpoint exercised by the AAO + * dashboard's `/onboarding` form. Surfacing it in the public spec is the + * minimum-surface answer to the storefront-bootstrap question: a + * third-party app holding only a user's OAuth token needs *one* documented + * call to materialize the org, then `POST /api/me/agents` to land an agent + * (which auto-creates the member profile on first call). + * + * Two fields the handler accepts but the public schema deliberately omits: + * + * - `membership_tier` — owned exclusively by the Stripe webhook. Accepting + * it from the caller would let any user stamp tier intent on their org + * row, leaking tier-gated UI state until/unless a real subscription + * overwrites the column. + * - `corporate_domain` — server derives the value from the authenticated + * user's email. Accepting it as a field invited 400s when a caller's + * value disagreed with their email and gave nothing back when it agreed. + * + * Kept in its own module so the spec generator's import graph stays free + * of route handlers (each route file's transitive imports pull in WorkOS + * init, which fails at module load without env vars). + */ +export {}; +//# sourceMappingURL=onboarding-openapi.d.ts.map \ No newline at end of file diff --git a/dist/schemas/onboarding-openapi.d.ts.map b/dist/schemas/onboarding-openapi.d.ts.map new file mode 100644 index 0000000000..9e449fbf0f --- /dev/null +++ b/dist/schemas/onboarding-openapi.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"onboarding-openapi.d.ts","sourceRoot":"","sources":["../../server/src/schemas/onboarding-openapi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"} \ No newline at end of file diff --git a/dist/schemas/onboarding-openapi.js b/dist/schemas/onboarding-openapi.js new file mode 100644 index 0000000000..d3e3074486 --- /dev/null +++ b/dist/schemas/onboarding-openapi.js @@ -0,0 +1,135 @@ +/** + * OpenAPI registrations for the onboarding REST surface. + * + * `POST /api/organizations` has existed in production for a long time but + * has only ever been documented as a private endpoint exercised by the AAO + * dashboard's `/onboarding` form. Surfacing it in the public spec is the + * minimum-surface answer to the storefront-bootstrap question: a + * third-party app holding only a user's OAuth token needs *one* documented + * call to materialize the org, then `POST /api/me/agents` to land an agent + * (which auto-creates the member profile on first call). + * + * Two fields the handler accepts but the public schema deliberately omits: + * + * - `membership_tier` — owned exclusively by the Stripe webhook. Accepting + * it from the caller would let any user stamp tier intent on their org + * row, leaking tier-gated UI state until/unless a real subscription + * overwrites the column. + * - `corporate_domain` — server derives the value from the authenticated + * user's email. Accepting it as a field invited 400s when a caller's + * value disagreed with their email and gave nothing back when it agreed. + * + * Kept in its own module so the spec generator's import graph stays free + * of route handlers (each route file's transitive imports pull in WorkOS + * init, which fails at module load without env vars). + */ +import { z } from 'zod'; +import { registry, ErrorSchema } from './registry.js'; +const OrganizationCompanyTypeSchema = z + .enum(['adtech', 'agency', 'brand', 'publisher', 'data', 'ai', 'other']) + .openapi('OrganizationCompanyType', { + description: "Coarse classification of the organization's role in the open ad ecosystem. Drives default verification badges and the member profile's display category.", +}); +const OrganizationRevenueTierSchema = z + .enum(['under_1m', '1m_5m', '5m_50m', '50m_250m', '250m_1b', '1b_plus']) + .openapi('OrganizationRevenueTier', { + description: 'Annual revenue band, USD. Drives membership-tier eligibility for company-tier seats.', +}); +const CreateOrganizationInputSchema = z + .object({ + organization_name: z.string().min(1).max(200).openapi({ + description: "Display name for the organization. Used both as the org row name and (when auto-bootstrapping a member profile via the first agent registration) as the profile's `display_name`.", + example: 'Acme Media', + }), + is_personal: z.boolean().optional().openapi({ + description: 'Set to `true` to create a personal workspace instead of a corporate organization. Personal workspaces skip corporate-domain verification, are limited to one per user, and cannot host the `company_*` membership tiers.', + default: false, + }), + company_type: OrganizationCompanyTypeSchema.optional(), + revenue_tier: OrganizationRevenueTierSchema.optional(), + marketing_opt_in: z.boolean().optional().openapi({ + description: 'Whether the caller opted in to AAO marketing communications. Recorded once per user (not overwritten on subsequent calls). Independent of Terms-of-Service consent, which is recorded server-side from the request context.', + default: false, + }), +}) + .openapi('CreateOrganizationInput', { + description: [ + 'Request body for `POST /api/organizations`.', + "Bootstraps a WorkOS organization, mirrors the caller as `owner`, records the caller's ToS / privacy-policy acceptance, and (for non-personal orgs) inserts an email-verified record into `organization_domains` so subsequent registry calls can skip explicit domain-verification.", + "Membership tier and corporate domain are *not* caller-supplied: the tier is set by the Stripe webhook on subscription events, and the corporate domain is derived from the authenticated user's email.", + ].join('\n\n'), +}); +const CreateOrganizationResponseSchema = z + .object({ + success: z.boolean().optional(), + organization: z + .object({ + id: z.string().openapi({ example: 'org_01HXZAB123' }), + name: z.string().openapi({ example: 'Acme Media' }), + }) + .optional(), + id: z.string().optional().openapi({ + description: "Set on the **prospect-adoption** path: when an org with the user's email domain already exists in a `prospect` state (i.e. the registry pre-recorded it from a brand crawl but no human had claimed it yet), this call adopts that org for the caller instead of creating a new one.", + }), + name: z.string().optional(), + adopted: z.boolean().optional().openapi({ + description: '`true` when the response is the prospect-adoption path. When `true`, no new WorkOS organization was created — the caller is now the owner of an existing prospect record.', + }), +}) + .openapi('CreateOrganizationResponse', { + description: 'Response from `POST /api/organizations`. The body shape varies by path: a fresh creation returns `{ success: true, organization: { id, name } }`; a prospect adoption returns `{ id, name, adopted: true }` directly. Both paths are 2xx; downstream callers should treat any `2xx` as "the org now exists and you are an owner of it" and read whichever id is present.', +}); +registry.registerPath({ + method: 'post', + path: '/api/organizations', + operationId: 'createOrganization', + summary: 'Create or adopt my organization', + description: [ + "Bootstrap the caller's organization explicitly. Use this when the caller wants to control the organization name, `company_type`, `revenue_tier`, or `is_personal` flag before any agents are registered.", + "**Most storefront-style integrations don't need this call** — `POST /api/me/agents` will auto-create an org for a fresh OAuth user (corporate or personal workspace based on the email domain) and surface `org_auto_created: true` in the response. Reach for `POST /api/organizations` only when the auto-derived defaults aren't acceptable.", + 'Three outcomes depending on the caller\'s state:', + "- **Fresh create** (most common): a new WorkOS organization is created, the caller is added as `owner`, the corporate domain is recorded as email-verified, and ToS / privacy-policy acceptance is logged from the request context. Returns `{ success: true, organization: { id, name } }`.", + "- **Prospect adoption**: an organization with the caller's email domain already exists as a `prospect` (the registry pre-recorded it from a brand crawl but no human had claimed it yet). The caller is promoted to `owner` of the existing record instead of forking a duplicate. Returns `{ id, name, adopted: true }`.", + '- **Already-active conflict**: the org exists and is already claimed by another paying member or a previously joined user. Returns `409` with the existing org id so the caller can switch to a join-request flow (`POST /api/organizations/:orgId/join-requests`) instead of trying to register a duplicate.', + 'Tier transitions happen via the billing flow only — there is no `membership_tier` field on this endpoint. After org creation, send the user to `POST /api/checkout-session` (or the dashboard `/membership` page) to start a subscription; the Stripe webhook is the sole writer of `organizations.membership_tier`.', + 'Rate-limited per user: `15` failed attempts per hour; successful calls do not count against the limit so a legitimate registration is never penalized by earlier validation errors.', + ].join('\n\n'), + tags: ['Onboarding'], + security: [{ bearerAuth: [] }, { oauth2: [] }], + request: { + body: { content: { 'application/json': { schema: CreateOrganizationInputSchema } } }, + }, + responses: { + 200: { + description: 'Prospect adoption — an existing prospect organization for this domain was claimed by the caller. Body is `{ id, name, adopted: true }`.', + content: { 'application/json': { schema: CreateOrganizationResponseSchema } }, + }, + 201: { + description: 'New organization created. Body is `{ success: true, organization: { id, name } }`. The caller is the `owner`; the corporate domain is recorded as email-verified for downstream registry calls.', + content: { 'application/json': { schema: CreateOrganizationResponseSchema } }, + }, + 400: { + description: [ + 'One of:', + '- `organization_name` missing or invalid', + '- `company_type` / `revenue_tier` value not in the documented enum', + "- caller is on a personal-email domain (gmail.com, yahoo.com, …) and is trying to register a corporate org — register `is_personal: true` instead", + '- per-user organization cap reached (10 orgs per user)', + ].join('\n'), + content: { 'application/json': { schema: ErrorSchema } }, + }, + 401: { + description: 'Authentication required', + content: { 'application/json': { schema: ErrorSchema } }, + }, + 409: { + description: "An active organization already exists for this caller's email domain. The body includes `existing_org_id` and `existing_org_name`; the caller should switch to the join-request flow rather than retrying.", + content: { 'application/json': { schema: ErrorSchema } }, + }, + 429: { + description: 'Rate limit exceeded — 15 failed attempts per hour per user. Successful calls do not count against the limit.', + content: { 'application/json': { schema: ErrorSchema } }, + }, + }, +}); +//# sourceMappingURL=onboarding-openapi.js.map \ No newline at end of file diff --git a/dist/schemas/onboarding-openapi.js.map b/dist/schemas/onboarding-openapi.js.map new file mode 100644 index 0000000000..9fb894c315 --- /dev/null +++ b/dist/schemas/onboarding-openapi.js.map @@ -0,0 +1 @@ +{"version":3,"file":"onboarding-openapi.js","sourceRoot":"","sources":["../../server/src/schemas/onboarding-openapi.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/server/public/members.html b/server/public/members.html index f8f9e09cc7..e72afaf252 100644 --- a/server/public/members.html +++ b/server/public/members.html @@ -2407,7 +2407,7 @@

Overview

Tools
-
${data.tools_count || tools.length}
+
${data.tools_count ?? tools.length}
${data.description ? `
diff --git a/server/src/routes/registry-api.ts b/server/src/routes/registry-api.ts index 8763172379..03a7df8139 100644 --- a/server/src/routes/registry-api.ts +++ b/server/src/routes/registry-api.ts @@ -997,7 +997,7 @@ registry.registerPath({ tags: ["Agent Probing"], request: { query: z.object({ url: z.string() }) }, responses: { - 200: { description: "Discovered agent info", content: { "application/json": { schema: z.object({ name: z.string(), description: z.string().optional(), protocols: z.array(z.string()), type: z.string(), stats: z.object({ format_count: z.number().int().optional(), product_count: z.number().int().optional(), publisher_count: z.number().int().optional() }) }) } } }, + 200: { description: "Discovered agent info", content: { "application/json": { schema: z.object({ name: z.string(), description: z.string().optional(), protocols: z.array(z.string()), type: z.string(), tools_count: z.number().int(), tools: z.array(z.object({ name: z.string(), description: z.string().optional() })), stats: z.object({ format_count: z.number().int().optional(), product_count: z.number().int().optional(), publisher_count: z.number().int().optional() }) }) } } }, 504: { description: "Connection timeout", content: { "application/json": { schema: z.object({ error: z.string(), message: z.string() }) } } }, }, }); @@ -6711,7 +6711,8 @@ export function createRegistryApiRouter(config: RegistryApiConfig): Router { } } - return res.json({ name: agentName, description: agentInfo.description, protocols, type: agentType, stats }); + const publicTools = tools.map(({ name, description }: { name: string; description?: string }) => ({ name, description })); + return res.json({ name: agentName, description: agentInfo.description, protocols, type: agentType, tools_count: publicTools.length, tools: publicTools, stats }); } catch (error) { logger.warn({ err: error, url }, "Public agent discovery error");