MCP Client

Consent screen React components for the Zooly MCP OAuth flow

Overview

@zooly/mcp-client holds the React pieces of the Zooly MCP connector's consent step: the screen that asks a signed-in person to let an AI client call Zooly tools on their behalf, and its Authorize / Deny controls. It also holds the two other React surfaces the MCP flow renders outside the chat — the demo creator-agreement sheet the campaign's agreement card opens, and the admin scenario-catalog screen. Refusing is a first-class decision — Deny sends the client a clean OAuth error instead of leaving a popup stranded.

Like the other client packages it is pure, framework-agnostic React with Tailwind classes, and every state is driven by props.

Package Details

  • Package Name: @zooly/mcp-client
  • Location: packages/mcp/client
  • Type: Client-side React components
  • Used by: apps/zooly-app/app/authorize/page.tsx, the mcp-demo/agreement/[creatorId] page, and /admin/scenarios

Exports

ExportPurpose
McpConsentScreenThe consent screen. Props: params (the OAuth query params, passed through verbatim), sessionEmail, clientName, and error (renders the error instead of the form).
McpAuthorizeButtonThe approve/deny controls. Props: params, disabledReason.
McpCreatorAgreementThe demo agreement/checkout sheet behind the campaign agreement card. Props: creatorId (from the path) and query (the page's search params, verbatim — the tool wrote them into the link). A demo prop, not a product surface: nothing is charged and no signature is stored.
ScenarioCatalogThe admin scenario-catalog screen (/admin/scenarios): list versions, edit drafts, publish, disable, create empty or copy.
McpConsentScreenProps, McpAuthorizeButtonProps, McpCreatorAgreementPropsProp types.

Behaviour

  • The page — not this package — does the work: it validates the OAuth params, resolves the Zooly session and redirects a logged-out visitor to auth.zooly.ai with returnTo. The screen only renders what it is given.
  • Both buttons POST the full parameter set to /api/oauth/authorize with action: "approve" | "deny", then follow the redirectUrl the route returns (the client's callback, with ?code=… or ?error=access_denied).
  • The screen names the client asking for access, so the person authorizing can see who is asking. It says nothing about the callback destination.
  • Stable hooks for tests: mcp-consent-screen, mcp-consent-error, mcp-authorize, mcp-authorize-button, mcp-deny-button, mcp-authorize-disabled, mcp-authorize-error.

Further Reading

  • The server side (OAuth shim, tools, the upload card): @zooly/mcp-srv
  • Plan and verification status: docs/mcp/zly-1963-chatgpt-mcp-demo.md