Files
PaperClipAI/ui/storybook/stories/ZapierConnection.stories.tsx
T
DottaandPaperclip b41ccf097f fix(apps): configure MCP aggregators from inline task cards (#13879)
## Thinking Path

> - Paperclip lets people manage AI agents and their work.
> - Agents request connections through cards in task threads.
> - MCP aggregators need provider-specific URLs and authentication.
> - The task dialog used the generic setup form and omitted these
fields.
> - This pull request uses the same provider setup controller in tasks
and Apps.
> - Users can configure a connection without leaving the task.

## Linked Issues or Issue Description

Related: #13755, #13855.

**What happened?**

An inline Executor request opened a very wide dialog with an empty
credential step. Connect failed because the MCP URL was missing. The
other aggregator cards also bypassed their provider setup.

**Expected behavior**

Each card shows its provider instructions, URL field, and authentication
options in a bounded dialog. Completing setup grants access only to the
requesting agent.

**Steps to reproduce**

1. Enable experimental MCP aggregators.
2. Have an agent request Zapier, Arcade, Composio, or Executor from a
task.
3. Open the card and continue past Access.

## What Changed

- Route page and task setup through the same provider controller.
- Bound the task dialog width and preserve the requesting agent's access
scope.
- Support existing accounts, saved drafts, URL/token setup, and
task-bound OAuth.
- Keep a sign-in link available when the browser cannot open a popup.
Verify completion through the existing durable callback path.
- Add inline Access, configuration, and narrow Storybooks for all four
providers.
- Document the shared setup requirement and correct Executor's URL
instructions.

## Verification

- Focused Vitest selection: 24 passed. Covers all four inline forms,
requester access, existing accounts, saved drafts, OAuth retry, callback
validation, popup cleanup, and generic reconnect endpoint preservation.
- UI typecheck, UI build, design-token gates, and Storybook build
passed.
- Live local browser: new Executor, Arcade, and Composio connections
completed provider consent from task cards. Each appeared Connected with
the requester selected.
- Real Test calls returned Executor output `4`, an Arcade public GitHub
star count, and Composio tool-discovery results. An ungranted agent was
denied access. Real Paperclip process-agent runs discovered each
provider catalog with only the requester’s connection installed.
- Deployed implementation commit `5d722e89c` to the isolated staging
tenant. The original failing Executor card now completes, discovers
seven actions, limits access to its requesting agent, and resumes that
agent. Its continuation completed real Executor calls and the provider
resume flow, then returned an upstream Airtable authorization link. A
real staging Test call returned `4` in 1.5 seconds. Later PR commits add
regression coverage and popup-unmount cleanup.
- Zapier fresh-token browser test remains pending a provider clipboard
handoff. Its URL and token flow passes focused tests.
- Latest-head CI (`d14f4c73c`): 53 checks passed; optional Storybook
deployment and visual regression jobs skipped. Greptile 5/5, both review
threads resolved. Canceled runners and unrelated chat timeouts passed
the single retry on unchanged code.
- The full local test suite was not run, as requested by the maintainer.
CI runs the repository gates.

## Risks

- OAuth popup behavior differs by browser. The explicit sign-in link and
durable server completion checks provide recovery.
- Saved task drafts store only a connection ID in browser storage.
Credentials remain in the existing server vault.
- No database or server protocol changes.

## Model Used

OpenAI GPT-6 (`gpt-6-astra`) through Codex, with reasoning, code
execution, and browser tools. The exact context-window size is not
exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` OR (b) described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-23 09:19:18 -05:00

37 lines
2.6 KiB
TypeScript

import type { Meta, StoryObj } from "@storybook/react-vite";
import { RemoteMcpConnectionReview } from "../prototypes/RemoteMcpConnectionReview";
const meta = {
title: "Apps/Connections/Zapier",
component: RemoteMcpConnectionReview,
args: { provider: "zapier", scenario: "journey" },
parameters: { layout: "fullscreen", docs: { description: { component: "Interactive design review using application views with in-memory provider responses. No real authentication, tool calls, or credential persistence. Representative catalogs are examples; production discovery supplies the actual tools." } } },
argTypes: { provider: { control: false } },
} satisfies Meta<typeof RemoteMcpConnectionReview>;
export default meta;
type Story = StoryObj<typeof meta>;
export const CompleteSetupJourney: Story = { args: { scenario: "journey" } };
export const InitialSetup: Story = { args: { scenario: "initial" } };
export const SelectedAgents: Story = { args: { scenario: "selected_agents" } };
export const ConnectionDetails: Story = { args: { scenario: "connect" } };
export const AdvancedAuthentication: Story = { args: { scenario: "advanced" } };
export const Connecting: Story = { args: { scenario: "connecting" } };
export const InvalidUrl: Story = { args: { scenario: "invalid_url" } };
export const RejectedCredentials: Story = { args: { scenario: "rejected" } };
export const UnreachableEndpoint: Story = { args: { scenario: "unreachable" } };
export const ManageToolPermissions: Story = { args: { scenario: "permissions" } };
export const CompletedConnection: Story = { args: { scenario: "completed" } };
export const Reconnect: Story = { args: { scenario: "reconnect" } };
export const SavedDraftResume: Story = { args: { scenario: "draft" } };
export const NewToolsAllowed: Story = { args: { scenario: "new_tools" } };
export const BroadExecutionTools: Story = { args: { scenario: "broad" } };
export const NarrowSetup: Story = { args: { scenario: "initial" }, globals: { viewport: { value: "mobile", isRotated: false } } };
export const NarrowToolManagement: Story = { args: { scenario: "permissions" }, globals: { viewport: { value: "mobile", isRotated: false } } };
export const NarrowConnectionDetails: Story = { args: { scenario: "connect" }, globals: { viewport: { value: "mobile", isRotated: false } } };
export const InlineCardAccess: Story = { args: { scenario: "initial", inline: true } };
export const InlineCardConfiguration: Story = { args: { scenario: "connect", inline: true } };
export const NarrowInlineCard: Story = { args: { scenario: "connect", inline: true }, globals: { viewport: { value: "mobile", isRotated: false } } };