## Summary
- Add focused Configuring Sessions docs for ToolRouter `preload.tools`
and the direct-tools preset.
- Include examples for explicit preloaded tools, direct-tools preset,
and direct tools with selected meta tool groups enabled.
- Add a changelog entry for preloaded tools and direct tools sessions.
## Validation
- `git diff --check`
- `pnpm --dir docs lint:links` failed before validating links due to
local Bun 1.2.10 `fs.glob` API incompatibility: `TypeError: The
"options" argument must be of type object. Received undefined`.
- `pnpm --dir docs types:check` failed in existing generated Next route
types with missing `../../../app/(home)/reference/[[...slug]]/page.js`;
current app has `(home)/reference/(v31)/[[...slug]]/page.tsx` and
`(home)/reference/v3/[[...slug]]/page.tsx`.
## Why
We're submitting the **composio-mcp** plugin to Anthropic's official
Claude Code plugin marketplace via
[claude.ai/settings/plugins/submit](https://claude.ai/settings/plugins/submit).
The form requires a public **plugin homepage** URL before review. We
don't have one yet — this PR adds it.
The plugin lives at
[ComposioHQ/composio-plugin-cc](https://github.com/ComposioHQ/composio-plugin-cc/tree/master/plugins/composio-mcp)
and bundles:
- The Composio Connect MCP server (pre-configured, OAuth-managed — no
API key needed)
- 4 skills: \`composio-mcp\`, \`onboarding\`,
\`company-activity-summary\`, \`prefer-composio\`
Today users either install it from the GitHub-hosted marketplace
(\`/plugin marketplace add ComposioHQ/composio-plugin-cc\`) or — once
Anthropic accepts the submission — directly from the official
marketplace. Either way, they need a docs page that explains what's in
it and how to install.
## What this PR does
Adds \`docs/content/docs/claude-code-plugin.mdx\` covering:
- What's bundled (MCP server + 4 skills, with one-line descriptions of
each)
- 3-step install (\`/plugin marketplace add\` → \`/plugin install\` →
first-run OAuth)
- Team setup via \`.claude/settings.json\` for repo-scoped enable
- How it differs from the existing API-key MCP path (table comparing the
two)
- Source link + troubleshooting that defers to
\`/docs/composio-connect\` so we don't duplicate
Sidebar: adds \`claude-code-plugin\` under **Get Started**, between
\`cli\` and the Core Concepts section.
## Screenshots
<img width="766" height="679" alt="image"
src="https://github.com/user-attachments/assets/a5a1556f-3718-4193-bc38-71ecc62cd18f"
/>
<img width="603" height="763" alt="image"
src="https://github.com/user-attachments/assets/15b44d01-136f-4a32-a558-75cf172d8112"
/>
<img width="489" height="628" alt="image"
src="https://github.com/user-attachments/assets/d91a9b6e-b294-4520-8a04-76c16bb00c12"
/>
## Why a separate page (not extending composio-connect.mdx)
\`/docs/composio-connect\` is a multi-client landing page (Cursor,
Codex, Claude Desktop, ChatGPT, etc.) using the API-key + \`claude mcp
add\` setup. The plugin is a different distribution channel for the same
MCP server with different install steps (slash commands, OAuth,
marketplace updates) and different value-prop (bundled skills). Mixing
them into one page would muddy both. They cross-link.
## How this maps to the submission form
| Form field | Value |
|---|---|
| Link to plugin |
\`https://github.com/ComposioHQ/composio-plugin-cc/tree/master/plugins/composio-mcp\`
|
| **Plugin homepage** |
**\`https://docs.composio.dev/docs/claude-code-plugin\`** ← this PR |
| Plugin name | \`composio\` (slug \`composio-mcp\` internally) |
| Platforms | Claude Code + Claude Cowork (tested) |
| License | MIT |
| Privacy policy | https://composio.dev/privacy |
## Preview
Local dev: \`bun run dev\` →
http://localhost:3001/docs/claude-code-plugin
## Open questions for review
1. **Tone/positioning** — does the framing of "plugin path vs API-key
path" match how we want to talk about these two distribution channels
long-term? I've kept both as supported options.
2. **Sidebar placement** — currently under Get Started. Could also live
under Features or as a sub-page of \`composio-connect\`. Open to moving.
3. **Plugin name (\`composio\` vs \`composio-mcp\`)** — the
public-facing name in Anthropic's directory. Not blocking on this PR but
flagging since it affects the page's framing.
## Test plan
- [ ] Open \`/docs/claude-code-plugin\` locally, confirm it renders,
sidebar entry shows under Get Started
- [ ] Internal links resolve: \`/docs/composio-connect\` and
\`/docs/composio-connect#troubleshooting\`
- [ ] External links resolve: GitHub repo, Claude Code plugin reference
docs
- [ ] \`bun run scripts/validate-links.ts\` passes
- [ ] \`bun run build\` passes
cc @palash — flagged you here per Shawn; this is the homepage URL we
need before submitting the plugin to Anthropic.
Made with [Cursor](https://cursor.com)
Multiple corrections from review:
1. Frontmatter description reverted to original
"Create trigger instances via the dashboard or SDK" (was edited
to a longer string that wasn't part of this PR's scope).
2. SDK section's first paragraph reverted to original
("Before creating a trigger, inspect the trigger type to see
what configuration it requires. Then create the trigger with
the required config."). The previous edit added a "...whether
you need to set up a webhook endpoint first" tail that drifted
from the section's original framing.
3. Code-comment reverts in both Python and TypeScript samples:
- "# Inspect the trigger type" -> "# Check what configuration is required"
- "# {properties...}" -> "# Returns: {properties...}"
- same in TS with // comments
These were collateral edits during prior passes; the originals
were fine.
4. Dashboard step 4 reverted to original
("Choose a trigger type and fill in the required configuration").
The added sentence claimed the dashboard prompts for webhook
endpoint configuration, which it doesn't.
5. Section order: Configuring the webhook endpoint now comes
before Using the SDK. Anyone who needs to configure encounters
it before scrolling past SDK examples. Users who don't need
it skip naturally — the section's intro spells out the
conditions. Last sentence of step 4 changed from "head back
to" -> "continue to" since SDK is now below.
6. Per-project capabilities bullet reworded — "Its own signing
secret and app-level token" -> "Project-scoped credentials —
the signing secret and app-level token you provide are stored
against this project alone." Composio doesn't provide the
secrets; the customer does. The capability is project-scoping,
not credential issuance.
7. Step 3 consolidated into a single PATCH that sends both fields
at once (previously two separate PATCH requests, one per
field). One request is the right API pattern; the Slack-specific
guidance about where to find each credential is preserved as
a bullet list under the curl block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues flagged on review:
1. "Retry the trigger creation call" in step 4 implied the user had
already failed once. First-time setup users hadn't tried at all.
Reword to "head back to Using the SDK to create your trigger".
2. verified_at isn't universal — providers that don't run a URL
verification handshake never populate it. Telling readers to
check verified_at would mislead them on toolkits that don't
verify. Remove all verified_at references from the docs:
- creating-triggers.mdx Step 4 ending: drop the verified_at
framing; reword the verification challenge sentence to lead
with "for providers that issue a verification challenge on
save" so providers without a handshake aren't misframed.
- creating-triggers.mdx "Updating an endpoint": drop the
"(handy for checking verified_at after a provider re-save)"
parenthetical from the GET-by-id example.
- slack.md FAQ: simplify the "Why aren't my Slack triggers
working?" answer to just point at the troubleshooting page,
dropping the enumerated failure-mode list (which referenced
verified_at and is no longer on the troubleshooting page
anyway).
The changelog mention of verified_at (line 44 of the V2 announcement)
is left intact — historical reference, shouldn't be retroactively
edited.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step 5 ("Confirm the endpoint is verified" by GETting and checking
verified_at) wasn't in the V2 changelog walkthrough. The changelog
goes from "point provider dashboard at URL" straight to "create V2
trigger instances" — the trigger create call is itself the natural
confirmation, since it'll fail if the endpoint didn't verify.
Verified in the changelog: `verified_at` IS a real field returned by
GET /api/v3.1/webhook_endpoints/{id} (changelog line 44 lists the
endpoint as "Get a single endpoint, including verified_at"). So the
field exists; just the standalone confirmation step doesn't.
- Step 4's last sentence now ends with the natural next-action
("Once the provider saves the URL, retry the trigger creation
call from Using the SDK") instead of a separate Step 5.
- Add a GET-by-id example to "Updating an endpoint" so verified_at
remains discoverable as an inspection tool when needed, just not
promoted to a mandatory step.
Walkthrough collapses to 4 steps, matching the changelog structure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two prose paragraphs about per-tenant guarantees and ingress
signature checks were dense walls of text. Restructure as bullets
matching the V2 announcement changelog's format. Each item now
stands on its own line, scannable.
Word-level edits:
- "since providers accept" → "providers accept" (drop redundant
conjunction; colon does the work)
- "The upside:" → "In return," — acknowledges it's a trade
- "every project becomes its own webhook tenant with isolated..."
→ restructured as a lead-in followed by 4 bullets
- "Provider events are verified at ingress against the endpoint's
signing secret before any trigger fires —" → "Every inbound event
is signature-checked at ingress before any trigger fires:" —
active, shorter
- Replay protection bullet is no longer a "for providers..."
parenthetical; it's its own item
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The intro was cramming five things into one runaway sentence: where
you can create triggers, the Composio-managed flow, the
bring-your-own-OAuth flow, the requires_webhook_endpoint_setup flag,
and the 400 status code. Plus a meta "see Configuring below" pointer.
Reduced to two short sentences. Flag name and 400 status drop out —
the Configuring section's own intro already explains both, so they
don't need to be teased here. Reader gets oriented (SDK or dashboard)
with a soft anchor for the conditional case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
troubleshooting/triggers.mdx
- Remove the "Webhook endpoint issues" section. Bloated a generic
troubleshooting page with feature-specific content that's also
drift-prone — already-known failure modes (signing secret missing,
verified_at null, missing app_token, replay-window) are surfaced
during setup in the Configuring section's warn callouts.
creating-triggers.mdx
- Add one short sentence to the upsides paragraph noting that
repeat verification handshakes are rejected after the endpoint
is verified, so the signing secret can't be silently swapped by
a forged handshake. Subtle placement (no callout, no heading)
since this is a security guarantee customers should know about
but don't have to act on.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Once the Ingress signature verification section moved off this page,
the top callout's only job was to tell readers that ingress is covered
elsewhere — useful only when there was an in-page contrast to make.
Now that the page covers delivery exclusively (and the title +
opening sentence say so), the callout is just overhead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- Recreate the generated Changesets release PR from
`changeset-release/next` after #3372 was closed.
- Keep `@composio/core` on the generated minor bump to `0.9.0`.
- Manually correct provider package releases from the generated `1.0.0`
major bump down to `0.9.0` minor bumps.
- Add provider changelog minor notes explaining the versions are aligned
with `@composio/core@0.9.0` and do not represent provider API breaks.
## Context
- Addresses the Bugbot finding on #3372:
https://github.com/ComposioHQ/composio/pull/3372#discussion_r3202024169
- This follows the prior manual correction pattern used when Changesets
tried to promote provider packages to `1.0.0` because a `0.x` core peer
dependency received a minor bump.
## Validation
- `git diff --check`
- Verified no provider package `package.json` or changelog heading
remains at `1.0.0`.
- Spot-checked the PR diff shows provider packages moving from `0.8.1`
to `0.9.0` while their `@composio/core` peer dependency moves to
`0.9.0`.
Big cleanup pass on the trigger docs. Four threads, one commit.
1. Rewrite "Configuring the webhook endpoint" intro
- Drop "Skip this section unless all three are true:" robot speak
in favor of reassurance-first ("With Composio-managed OAuth,
this is already done for you").
- Drop the (toolkit_slug, project_id, client_id) tuple syntax
and the "endpoints are keyed by..." phrasing — internal
developer language, not customer-facing.
- Surface the V2 design rationale from the changelog: providers
accept only one callback URL per OAuth app + each ingress URL
routes to one project, so 1 OAuth app = 1 project. Frame the
constraint as a trade ("the upside") with the per-project
wins from the changelog: isolated ingress rate limits, own
signing secret/app-level token, clean fan-out, per-project
metering.
- Pull the ingress signature verification details into this
section as a single paragraph: HMAC-SHA256 / Ed25519 / shared
token, replay protection, 400 on tamper. They were on
webhook-verification.mdx but belong with the setup material.
- Warn callout reduced to action only ("Sharing one OAuth app
across projects? Consolidate or register separate apps").
2. Rename `requires_webhook_endpoint` → `requires_webhook_endpoint_setup`
The current name was ambiguous (every webhook trigger goes
through a webhook endpoint; what's variable is whether the user
sets one up). Adding "_setup" makes the flag's meaning clear.
- 4 prose mentions updated: glossary.mdx, creating-triggers.mdx
(×1, the second was removed in the rewrite), webhook-verification
was removed entirely, troubleshooting/triggers.mdx.
3. Slim webhook-verification.mdx
- Drop the "Ingress signature verification" section. The page is
about the *delivery* hop signature (you verify Composio's
signature on your endpoint) — ingress is automatic and the
setup details for it belong on creating-triggers.
- Slim the top callout: drop "see Ingress signature verification
below" cross-reference (no longer below).
4. Revert toolkit-specific FAQ walkthroughs
- slack.md: my five-step Slack walkthrough on "How do I set up
Slack event webhooks?" → short pointer to the shared docs.
"Why aren't my Slack triggers working?" → short pointer to
the troubleshooting page. The shared Configuring section in
creating-triggers already mentions Slack-specific dashboard
paths (Event Subscriptions → Request URL); duplication on the
toolkit page added drift risk.
- notion.md: drop the new "How do I set up Notion webhook
triggers?" entry I added in a previous pass. Same reasoning —
toolkit-specific webhook setup is covered once, on the shared
Configuring section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The page title was "Subscribing to triggers" but it's referenced as
"Subscribing to events" everywhere else (cards on triggers.mdx,
the new step 1 in Working-with-triggers, the description text).
Mismatch between the heading and how the page is named in nav.
- Frontmatter title: Subscribing to triggers → Subscribing to events
- common-faq.mdx link text updated to match (URL slug unchanged
since it was already /subscribing-to-events)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- Remove the Python package name from the TypeScript changeset
frontmatter.
- Keeps the `@composio/core` minor bump intact so pending patch/minor
changesets collapse into one TS minor release.
## Root Cause
The TypeScript Changesets release job runs against the pnpm workspace.
`.changeset/session-update-method.md` referenced `composio`, which is
the Python package name and not a pnpm workspace package, so `changeset
version` failed with `Found changeset session-update-method for package
composio which is not in the workspace`.
## Validation
- `git diff --check`
- Confirmed no remaining `.changeset` entry references `"composio"` as a
package name.
Note: a full local `pnpm changeset version` dry run was blocked in the
temp worktree by missing `node_modules`; the failure is static and this
removes the invalid package reference.
## Summary
- Bump the root Python SDK package from `0.12.0` to `0.13.0`.
- Bump all Python provider packages from `0.12.0` to `0.13.0`.
- Keep this PR release-only; no publish tag has been created.
## Notes
- Version bumps were generated with the repo bump script: `cd python &&
uv run python scripts/bump.py --minor`.
- Publishing still happens later by pushing the `py@0.13.0` tag, per
`.github/workflows/py.release.yml`.
- This mirrors the minor-release intent of TypeScript PR #3367, using
the Python release flow instead of changesets.
## Validation
- `git diff --check`
- Checked that the diff only updates version fields in
`python/pyproject.toml` and provider `pyproject.toml` / `setup.py`
files.
- Did not run tests because this PR only changes package versions.
Three iterations rolled up into the same commit since they all touch
triggers.mdx:
1. One-liner reworded to spell out reason → action → purpose
- Was: "If you bring your own OAuth app... you may need to
register the Composio-issued ingress URL with the provider
once per OAuth app so events can flow into Composio..."
- Now: "Composio handles ingress setup on most webhook triggers.
For some webhook triggers — typically when you bring your own
OAuth app — providers only deliver webhooks to URLs you've
registered on the OAuth app, so you'll need to register the
Composio-issued ingress URL there once for events to start
flowing into Composio."
- Reasoning: "for some webhook triggers" makes the conditional
framing explicit (it's not all triggers, not all apps); the
"providers only deliver to URLs you've registered" clause
explains why; "for events to start flowing into Composio"
keeps the user-facing purpose at the end.
2. Working with triggers section restored — original numbered list
shape (plain ordered list, action verb bold, single line each),
updated to the new vocabulary
- Step 1: "Configure your webhook endpoint" (which referred to
the subscription, confusingly named) → "Subscribe to events"
- Step 3: now references both Creating triggers AND the
Configuring the webhook endpoint section anchor, so readers
scanning the steps know that section exists when their trigger
needs it
- Steps 2, 4, 5: same shape as the original, reworded for the
subscription terminology
3. Next-steps cards reduced from 6 to 5 — drop the standalone
"Configuring the webhook endpoint" card. Still reachable from
the one-liner, the step 3 link, and the Creating triggers page.
The card duplicated those references and made a situational
step look like a primary one. Gmail labeler card kept.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The webhook subscription secret is no longer one-shot at creation.
Customers can fetch it later from the subscription endpoint or
rotate it. Update the three places that still made the old claim:
- subscribing-to-events.mdx: remove the middle sentence from the
warn callout. Result: "The response includes a `secret` for
verifying webhook signatures. Store it securely."
- webhook-verification.mdx (×2): SDK and manual sections both had
"Your webhook secret is returned only once..." callouts. Replace
with a short note pointing at GET /webhook_subscriptions/{id} for
fetching and the rotate endpoint for rotation, with the same
"store as COMPOSIO_WEBHOOK_SECRET" guidance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review:
- triggers.mdx feels duplicative when it both summarizes setup and
links to workflow pages that cover the same.
- subscribing-to-events.mdx introduces "webhook endpoints" in a
callout, which mixes two distinct concepts on a page that should
only own the subscription side.
triggers.mdx
- "Two delivery types" renamed to "Two trigger types".
- Drop the trailing "..." in webhook examples; remove GitHub.
- Add "Google Calendar" to polling examples.
- Add "processes the payload" to the Webhook row description.
- Drop the "End-to-end flow" section (arrow + two URL bullets +
signature bullets). The Figure at the top already conveys the
visual; signature behavior is documented on webhook-verification.mdx.
- Drop the "Working with triggers" 6-step list. The Next steps
cards orient readers to the workflow pages, which own the
step-by-step content.
- Add a single-sentence note between the trigger types table and
the Accordions: "If you bring your own OAuth app for a webhook
trigger, you may need to register the Composio-issued ingress URL
with the provider once per OAuth app — see Configuring the webhook
endpoint." Composio handles it for you in most cases.
subscribing-to-events.mdx
- Remove the top "two webhook URLs" callout. The page is about
subscriptions; bringing in webhook endpoints here added complexity
that belongs on the concept and workflow pages, not here.
Net: triggers.mdx goes from ~85 lines to ~42; concepts stay separated
per page (subscription on its own page, endpoint on creating-triggers).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Iteration based on review of the rendered preview.
triggers.mdx
- Webhook row: add "processes the payload" to the description so the
table reflects what Composio does between signature verification
and fan-out.
- Drop the "Setup at a glance" 4-column table and the second
flag-vs-OAuth-source table — both restated content already covered
by the bullets and the steps below.
- End-to-end flow: keep the arrow + the two URL bullets as a slim
description; webhook-endpoint bullet links to the section in
creating-triggers (not a standalone page).
- Drop the "Two webhook URLs" duplicate table inside End-to-end flow.
- "Working with triggers" steps already lead with subscription
before create — no change.
- Next-steps cards reordered: Subscribing first (one-time per
project), then Creating, then the situational Configuring the
webhook endpoint card linking to the section anchor inside
Creating triggers.
creating-triggers.mdx
- Restore the "Configuring the webhook endpoint" section (5 steps +
Updating subsection) as a section, not a separate page. Earlier
iteration tried a standalone page; reverted per direction
(customers should hit a short note in triggers.mdx and follow it
to a section in creating-triggers).
- Remove the in-page configuring page link from the next-steps cards;
reuse the slot for "Subscribing to events".
- Prereq callout adds: webhook subscription must exist on the project
so events have somewhere to land.
Cross-references in subscribing-to-events.mdx, webhook-verification.mdx,
troubleshooting/triggers.mdx, glossary.mdx, slack/notion FAQs all
already point at creating-triggers#configuring-the-webhook-endpoint
— no further change needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The rightmost box in the triggers-flow figure (the receiver inside
"Your Application") was labelled "Webhook Endpoint", which conflicts
with our docs vocabulary: webhook_endpoint is the Composio-side
resource that owns the ingress URL we register with the provider, not
the URL the customer's app exposes. The customer-side URL is a
webhook_subscription.
Update both the light and dark SVGs to label that box "Webhook
Subscription". Also reword the alt text on the Figure in triggers.mdx
("your webhook endpoint" → "your webhook subscription URL") so the
non-visual experience matches.
The leftmost box "Webhook Receiver" is unchanged — it's a generic
descriptive label for Composio's intake side, not a vocabulary term.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The TypeScript code block in creating-triggers.mdx accessed
triggerType.requiresWebhookEndpoint, which doesn't exist on the
SDK's TriggerType today (see ts/packages/core/src/types/triggers.types.ts:152).
Twoslash type-checks all TS code blocks at build time per docs/CLAUDE.md
rule 1, so the build failed on Vercel.
Drop the property reads (Python and TypeScript) so the samples are
valid against today's SDK. Conceptual prose still references the
requires_webhook_endpoint flag — the discovery story is unchanged,
just the code samples no longer claim the field exists yet. When the
SDK ships the field, add the reads back.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rethought the structure: whether endpoint configuration is required is
a property of the trigger type, not of (toolkit + OAuth source). So:
- The trigger type exposes a `requires_webhook_endpoint` flag (forthcoming
on the SDK / API per product direction).
- The reader inspects the trigger type. If the flag is true, configure
the endpoint; otherwise just create.
- The toolkit-level schema endpoint is no longer a primary upfront check
— it's used inside the configuration walkthrough as the source of
truth for which fields to PATCH.
triggers.mdx
- Drop the "Webhook endpoints" subsection with the two-row Composio-
configures vs you-configure table.
- Drop the "Checking which case applies to your toolkit" subsection
with the schema-endpoint upfront check.
- Add a "Setup at a glance" table — webhook subscription always (per
project), webhook endpoint only when required (per OAuth app),
determined at the trigger level.
- Working-with-triggers steps now lead with "Pick a trigger type and
inspect it" before the create step.
creating-triggers.mdx
- Reorder so the SDK and dashboard sections come first (most readers'
path) and the 5-step "Configuring the webhook endpoint" walkthrough
is last, gated behind "skip unless your trigger needs it."
- Code samples now print `requires_webhook_endpoint` /
`requiresWebhookEndpoint` alongside `config`, so readers see the
discovery moment in the same snippet.
- Walkthrough body unchanged — still discovers fields via the schema
endpoint, creates, PATCHes credentials, points provider at URL,
confirms verified_at.
subscribing-to-events.mdx
- Top callout reframed around the flag instead of toolkit names.
webhook-verification.mdx
- Ingress section's "your own OAuth app on a toolkit (today: Slack,
Notion)" bullet reframed around the flag.
troubleshooting/triggers.mdx
- Section header drops the toolkit-name list.
- Lead-in note now references the flag, not "if you've configured the
webhook endpoint yourself."
glossary.mdx
- Webhook Endpoint entry rephrased around the flag.
Toolkit FAQs (slack.md, notion.md) and meta.json unchanged — toolkit-
specific FAQs naturally talk per-toolkit, and the flag-vs-toolkit
framing doesn't change the steps users follow there.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Description
Adds five FAQs to the Slack toolkit FAQ snippet
(`docs/content/toolkits/faq/slack.md`) covering the most common Slack
OAuth install/approval friction points:
1. Why users see "This app isn't listed in the Slack Marketplace…"
during install
2. Whether workspace owner is required to install the app
3. Why Slack asks the user to submit a request during auth
4. How a workspace member can complete the connection without
permissions/approvals
5. The recommended solution (custom OAuth app)
These FAQs are placed right after the existing "How do I set up custom
OAuth credentials for Slack?" entry, since they're all about the OAuth
install flow and the resolution path consistently points back to using a
custom OAuth app.
Format follows the existing snippet style: plain markdown, `##
Question?` headers, paragraph or short bullet-list answers, `**bold**`
for UI/setting names, relative/external links matching what's already in
the file. No frontmatter (matches the rest of `content/toolkits/faq/`).
# How did I test this PR
- Read existing FAQ snippets (`slack.md`, `gmail.md`, `notion.md`) to
match style — short headers, `**bold**` for Slack setting names, no
Fumadocs components, ends with `---`
- Verified the file structure is unchanged: 5 new `## Question?`
sections inserted between the existing custom-OAuth question (line 9)
and the Slack-vs-Slackbot question; closing `---` separator still
present at EOF
- All links in the new content point to
`https://composio.dev/auth/slack`, which already exists in the same file
— no new link surface introduced
- Confirmed `bun run scripts/validate-links.ts` failure is pre-existing
on `origin/next` (sandbox dependency mismatch on
`fumadocs-core/content/md/frontmatter`), not caused by this change
- No code blocks added, so Twoslash type-check is not affected
Triggered by: uday@composio.dev | Source: slack
Session:
https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-7f4c8629aad8
# Description
Adds a one-line callout to the trigger-subscription docs page clarifying
that user webhook endpoints must be publicly reachable. Composio's
outbound webhook delivery runs on Cloudflare Workers, which use dynamic
egress IPs — so IP allowlisting and private/VPN-only endpoints will
silently drop webhook payloads (both `composio.trigger.message` and
`composio.connected_account.expired`).
The callout points readers to signature verification as the intended
authentication mechanism instead.
Placed on `subscribing-to-events.mdx` directly after the `POST
/webhook_subscriptions` example, where users are actually setting their
webhook URL.
# How did I test this PR
- Verified the claim by tracing webhook egress in `hermes`: cloud
delivery flows through `defaultDeliveryService` →
`sendComposioProxyRequest` → Cloudflare Workers external-proxy
(`/workspace/hermes/wrangler/external-proxy/`); self-hosted goes through
`directHttpDeliveryService`. Both `TRIGGER_MESSAGE_EVENT_TYPE` and
`CONNECTION_EXPIRED_EVENT_TYPE` share this path
(`apps/apollo/src/lib/events/handlers/webhook/handler.ts:86-90,
241-255`). No static-IP infrastructure exists for the Workers egress.
- Confirmed the linked `/docs/webhook-verification` route already exists
in the same file (line 30), so no new links were introduced.
- Content-only MDX change (no TypeScript code blocks added), so twoslash
type-checking is unaffected.
# Description
Bumps the `packageManager` pin from `pnpm@10.28.0` to `pnpm@10.28.2`,
the smallest release that fixes
[**CVE-2026-24056**](https://nvd.nist.gov/vuln/detail/CVE-2026-24056) —
a symlink
attack in pnpm where installing a malicious `file:` (directory) or
`git:`
dependency that contains a symlink to an absolute path causes pnpm to
copy that target file's contents (e.g. `~/.ssh/id_rsa`, `/etc/passwd`)
into `node_modules`, enabling local data exfiltration on developer
machines and CI runners.
Practical risk for this repo is **LOW** — we only install
registry-pinned dependencies with `minimumReleaseAge: 4320` (72-hour
cooldown) configured in `pnpm-workspace.yaml`, so the attacker would
need a malicious package to (a) be added as a dependency, and (b) sit
unnoticed for 72h. The fix is nevertheless a one-line defensive bump
that aligns this repo with the rest of the monorepo:
| repo | pnpm version | status |
|--------------------|-------------|--------|
| hermes | `10.33.0` | safe |
| composio_dashboard | `10.28.2` | safe |
| frontend | `10.28.2` | safe |
| **composio (this PR)** | `10.28.0` -> `10.28.2` | **fix** |
| metrics.composio.io | `10.18.2` | flagged separately (no CI) |
Discovered during the daily Zen security audit cron.
# How did I test this PR
- Diff is a single character bump (`10.28.0` -> `10.28.2`) in
`package.json` `packageManager`. No code, lockfile, or workflow
changes — `pnpm install` will simply use the newer pnpm via Corepack.
- Verified `composio_dashboard` and `frontend` already pin
`pnpm@10.28.2`
successfully across their CI workflows.
- No GHA file modified, so the pnpm-version reference in
`ts/docs/internal/release.md` (per `CLAUDE.md` maintenance task) does
not need to be updated by this PR.
---
Triggered by: dhawal@composio.dev | Source: cron-48e51eab745f
Session:
https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-cron-16acec0fd729
Origin: cron-48e51eab745f /
[zen-cron-16acec0fd729](https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-cron-16acec0fd729)
## Summary
- Fixes SDK custom-tool mapping for custom toolkits that reuse the same
child tool slug, e.g. `APP_A.VERSION` and `APP_B.VERSION`.
- Adds toolkit-qualified lookup (`toolkit + original slug`) while
keeping bare original-slug lookup only when it is unambiguous.
- Throws a client-side ambiguity error for manual
`session.execute('VERSION')` when multiple custom toolkit tools share
`VERSION`, instead of falling through to backend execution.
- Keeps `session.customToolkits()` / `session.customTools()` mapped to
the backend-assigned final slugs for duplicate child names.
## Repro / validation
Validated locally with a temporary Tool Router script (not committed)
using two dummy custom toolkits that both define `VERSION`:
- Current `next` SDK fails before high-level use with `Custom tool slug
collision: original slug "VERSION" maps to multiple final slugs...`.
- Tool Router backend accepts the same payload and returns both
`LOCAL_DUMMY_APP_A_REPRO_VERSION` and `LOCAL_DUMMY_APP_B_REPRO_VERSION`.
- This branch builds the SDK map successfully and high-level SDK
execution routes each final slug to its own internal handler:
- `LOCAL_DUMMY_APP_A_REPRO_VERSION` -> `{ app: "A", version: "1.0.0" }`
- `LOCAL_DUMMY_APP_B_REPRO_VERSION` -> `{ app: "B", version: "2.0.0" }`
## Tests
- `pnpm --filter @composio/core typecheck`
- `pnpm --filter @composio/core exec vitest run
test/models/customTool.test.ts test/models/toolRouter.test.ts
test/models/customToolRouting.test.ts`
Targeted English fixes on triggers.mdx:
- Webhook endpoints table — drop the duplicated "for on your behalf"
("register webhooks for on your behalf" → "register webhooks on
your behalf"), reflow both rows to read as full sentences instead
of fragmented clauses.
- "There are two ways an endpoint gets configured" → "An endpoint
is configured in one of two ways" (less awkward).
- "more toolkits move onto this flow" → "more toolkits adopt this
flow over time" (idiomatic).
- Two webhook URLs table — "you for your-own-OAuth on toolkits"
→ "you when you bring your own OAuth app on a toolkit".
- Ingress signature paragraph — "the signing secret is sourced
from" → "the signing secret comes from"; tighten clauses.
- Working with triggers / "Configure ingress" step — split the
long compound sentence into two; replace parenthetical
"(only when needed)" with a clearer lead-in.
- Next steps card — "(when needed)" → "if your toolkit needs it".
No structural changes; the table and section structure are
unchanged, just the copy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Toolkit pages (e.g. /toolkits/slack) get triggers/tools server-side
from Apollo and pull a per-toolkit FAQ from
content/toolkits/faq/{slug}.md. The Slack FAQ already had a
"How do I set up Slack event webhooks?" entry but it pointed at the
legacy ingress URL; Notion had no webhook entry at all.
- slack.md: rewrite the webhook setup answer to use the
webhook_endpoints flow (POST /webhook_endpoints, PATCH signing
secret, optional app_token, paste URL into Event Subscriptions).
Lead with "Composio-managed credentials = nothing to do."
Update the "Why aren't my Slack triggers working?" answer to
reference the same flow.
- notion.md: add a "How do I set up Notion webhook triggers?" entry
with the same Composio-managed-vs-your-own split. Step 1 calls
the schema endpoint as the source of truth for which credentials
Notion needs, since I don't want to invent field names.
- Both link to /docs/setting-up-triggers/creating-triggers#configuring-the-webhook-endpoint
for the canonical reference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review: the conceptual docs should describe the current product —
one webhook-endpoint concept whose only axis is who configures it.
V1/V2 split was an implementation detail that didn't belong in user-
facing prose. Per-OAuth-app endpoint setup also doesn't apply when
you use Composio-managed credentials, which the previous draft failed
to call out.
Concrete changes vs the previous commit:
- Drop "V1", "V2", "user-level webhook", "app-level webhook endpoint",
and "delivery models" from all conceptual docs (triggers.mdx,
creating-triggers.mdx, subscribing-to-events.mdx,
webhook-verification.mdx, troubleshooting/triggers.mdx, glossary.mdx).
- Remove the standalone configuring-webhook-endpoints.mdx page; fold
the walkthrough into creating-triggers.mdx as a "Configuring the
webhook endpoint" section. Revert meta.json accordingly.
- triggers.mdx now frames a single webhook-endpoint concept with two
configurations: Composio-managed (default for everything; required
with Composio-managed OAuth apps) vs you-managed (your own OAuth
app on toolkits like Slack and Notion today).
- Make the Composio-managed-OAuth case explicit: if you use
Composio-managed credentials, no manual webhook-endpoint setup
applies. Surfaced as a callout in triggers.mdx and
creating-triggers.mdx.
- The schema endpoint
(GET /api/v3.1/webhook_endpoints/schema?toolkit_slug=...) is
documented as the source of truth for whether your toolkit needs
manual configuration: empty setup_fields = Composio handles it
(Asana, etc.); non-empty = you handle it (Slack, Notion).
- creating-triggers.mdx: walkthrough now uses 5 numbered steps
(discover → create → store credentials → point provider at URL →
confirm verified_at), plus an "Updating an endpoint" subsection
covering PATCH vs POST semantics and how to list endpoints.
- troubleshooting/triggers.mdx: section header drops "V2", lead with
a one-line note that issues only apply to user-managed endpoints.
- glossary.mdx: Trigger entry simplified to two delivery types;
Webhook Endpoint entry rewritten without V2 vocabulary.
- webhook-verification.mdx: ingress section drops "V2" framing and
explains the two cases for where the signing secret comes from
(Composio-managed credentials vs PATCHed by the user).
Note: the schema endpoint is referenced in the docs but is not in
Apollo's exported OpenAPI spec, so no auto-generated reference page
exists for it. CRUD on /webhook_endpoints is in the spec and will
surface via auto-update PR #3238.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
Follow-up to #3358. The `.transform()` added on the `connectedAccounts`
Zod schema made the inferred TypeScript type resolve to the
**post-transform output** (`Record<string, string[]>`), so TS users
still hit `error TS2322: Type 'string' is not assignable to type
'string[]'` even though the runtime accepted strings. The runtime fix
landed; the public TS surface didn't follow.
This PR moves the coercion out of the schema and into
`ToolRouter.create`, mirroring the Python implementation. The public
type is now `Record<string, string | string[]>` and runtime behavior is
unchanged.
## Why CI didn't catch this in #3358
The PR's own test file (`toolRouter.test.ts`) already assigns a `string`
to `ToolRouterCreateSessionConfig`, but `ts/packages/core/tsconfig.json`
has `"include": ["src/**/*.ts"]` — `test/` is not typechecked. So `tsc
--noEmit clean` was technically true while masking the issue. Verified
empirically by dropping a typecheck file into `src/` on `next`:
```
src/__type_check.ts(8,7): error TS2322: Type 'string' is not assignable to type 'string[]'.
```
After this PR, the same file compiles cleanly.
## Changes
- **`ts/packages/core/src/types/toolRouter.types.ts`**: drop
`.transform()` from the `connectedAccounts` schema; `z.infer` now
exposes `Record<string, string | string[]>`.
- **`ts/packages/core/src/models/ToolRouter.ts`**: coerce `string →
[string]` inside `create` before sending to the backend (which expects
arrays). Preserves the original `connected_accounts: undefined` behavior
when the field is omitted (the parent schema's `.partial()` strips the
`default({})`).
- **`ts/packages/core/src/types/toolRouter.types.ts`**: fix stale
`@param {Record<string, string>}` JSDoc on the same field.
- **`.changeset/v31-connected-accounts-array.md`**: drop the inaccurate
*"Bumps `@composio/client` to `0.1.0-alpha.70`"* line — that bump landed
in a separate commit on `next` (`7c1443838`), not in #3358's diff (`git
diff 2bbd791de^1 2bbd791de` shows zero `pnpm-lock.yaml`/`package.json`
changes).
- **`.changeset/fix-connected-accounts-string-type.md`**: new `patch`
changeset for `@composio/core`.
## Test plan
- [x] `pnpm exec tsc --noEmit -p tsconfig.json` clean on
`@composio/core`
- [x] `pnpm exec vitest run` — 883/883 tests pass (incl. 110 in
`toolRouter.test.ts`)
- [x] `pnpm prettier --check` clean on touched files
- [x] Spot-checked: assigning `{ connectedAccounts: { gmail: 'ca_xxx' }
}` to `ToolRouterCreateSessionConfig` now typechecks; assigning the
array form still typechecks.