> [!WARNING] > ## ⚠️ Breaking change — `@composio/core@0.11.0` (minor bump, pre-1.0) > > The legacy in-memory custom-tools registry **`composio.tools.createCustomTool(...)` has been removed** (changeset `44e5458`). Because `@composio/core` is pre-1.0, this ships as a **minor** bump per semver convention — but it **is breaking**: any code calling `composio.tools.createCustomTool(...)` will fail to compile/run after upgrading. Consumers pinned to `^0.10.0` will **not** auto-upgrade to `0.11.0` and must opt in explicitly. ### Migration: use Tool Router custom tools Custom tools are now standalone factories bound to a **Tool Router session**, instead of being registered into an in-memory registry on the `composio.tools` namespace. **Before (removed):** ```ts // ❌ No longer available in 0.11.0 const tool = composio.tools.createCustomTool({ /* ... */ }); ``` **After — a standalone tool (no auth):** ```ts import { Composio, experimental_createTool } from '@composio/core'; import { z } from 'zod'; const composio = new Composio(); const grep = experimental_createTool('GREP', { name: 'Grep Search', description: 'Search for patterns in files', inputParams: z.object({ pattern: z.string(), path: z.string() }), execute: async (input) => ({ matches: [] }), }); // Bind the custom tool(s) to a Tool Router session const session = await composio.create(userId, { experimental: { customTools: [grep] }, }); ``` **After — a tool that extends a Composio toolkit (inherits that toolkit's auth):** ```ts const getImportantEmails = experimental_createTool('GET_IMPORTANT_EMAILS', { name: 'Get Important Emails', description: 'Fetch high-priority emails', extendsToolkit: 'gmail', inputParams: z.object({ limit: z.number().default(10) }), execute: async (input, ctx) => { // ctx.execute() returns the standard { data, error, logId } shape const result = await ctx.execute('GMAIL_SEARCH', { query: 'is:important' }); return { emails: result.data }; }, }); const session = await composio.create(userId, { experimental: { customTools: [getImportantEmails] }, }); ``` **After — grouping related tools into a custom toolkit:** ```ts import { experimental_createToolkit } from '@composio/core'; const devTools = experimental_createToolkit('DEV_TOOLS', { name: 'Dev Tools', description: 'Local developer utilities', tools: [grep], // tools here must NOT set `extendsToolkit` }); const session = await composio.create(userId, { experimental: { customToolkits: [devTools] }, }); ``` > Notes: > - `experimental_createTool` / `experimental_createToolkit` are also available from the dedicated `@composio/core/experimental` entry point. > - Tool slugs are auto-prefixed with `LOCAL_` when exposed to the agent (e.g. `GREP` → `LOCAL_GREP`; inside a toolkit, `DEV_TOOLS` + `GREP` → `LOCAL_DEV_TOOLS_GREP`). > - These APIs are intentionally namespaced `experimental_*` — they are not yet stable and may change. --- This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated. # Releases ## @composio/core@0.11.0 ### Minor Changes -a94715f: Forward `userId` when creating trigger instances so trigger 2FA flows can verify connected account ownership. -44e5458: Remove the legacy `composio.tools.createCustomTool(...)` in-memory registry API. Use Tool Router custom tools via `experimental_createTool`, `experimental_createToolkit`, and `composio.create(..., { experimental: { customTools, customToolkits } })` instead. ### Patch Changes -22a9171: Defer telemetry batch and error sends so instrumentation does not wait for telemetry network requests before returning SDK results or rethrowing SDK errors. -93b67e8: Fix automatic file upload/download substitution for file schemas that accept either a single file or a list of files. The file modifier now selects composed-schema branches by runtime value shape, so `anyOf(file, array<file>)` uploads or downloads each file when the tool receives a list while preserving existing single-file behavior. -b69cef1: Tolerate dangling `$ref` pointers in tool schemas the Composio API ships without a matching `$defs` entry. Some toolkits (e.g. `GMAIL_FETCH_EMAILS`) emit `outputParameters` with `"$ref": "#/$defs/FetchEmailsResponse"` while never declaring a top-level `$defs` block. After the strict resolver shipped with the previous Mastra fix, this caused `composio.tools.get(...)` to throw `JsonSchemaRefResolutionError` upfront, making every Gmail / Slack / Google-Calendar tool unusable through `MastraProvider`. The SDK now degrades the unresolvable branch to a permissive object schema and surfaces a single observability warning per `(toolSlug, ref)` pair instead of crashing. - `dereferenceJsonSchema` accepts a new optional second argument `{ onUnresolved?: 'throw' | 'sentinel'; onReplace?: (ref, reason) => void }`. Default behavior is unchanged (`'throw'`) — first-party / custom-tool schemas with a typo'd `$ref` still surface as a hard error. Pass `'sentinel'` to replace unresolved branches with the cycle-break sentinel (`{ type: 'object', additionalProperties: true }`) that the resolver already uses for `$ref` cycles. The replaced sentinel carries a default `description` hint so LLMs consuming the wrapped tool's schema get an in-band signal that the branch is opaque; a caller-provided `description` sibling overrides the default (Draft 2020-12 sibling-keyword merge). Safety caps (`MAX_REF_CHAIN_DEPTH`, `MAX_NODE_DEPTH`) keep throwing in both modes. New `UnresolvedRefStrategy`, `UnresolvedRefReason`, and `DereferenceJsonSchemaOptions` type exports. - `MastraProvider.wrapTool` opts both `inputParameters` and `outputParameters` into `'sentinel'` mode and emits one `logger.warn` per `(toolSlug, ref)` pair via the provider-scoped dedup `Set`. User-controlled segments in the warning (`tool.slug`, `toolkit.slug`, `ref`) are `JSON.stringify`d to neutralize embedded newlines / ANSI escapes / control bytes that could otherwise forge log lines (CWE-117). A matching one-shot telemetry event (`composio.mastra.wrapTool.danglingRef`) fires next to the warn so the Composio team has aggregate visibility into which toolkits are affected; the event respects `COMPOSIO_DISABLE_TELEMETRY=true`. - The `telemetry` instance from `@composio/core` is now publicly re-exported alongside `logger`, so providers can emit aggregate signals without reaching into the package's internals. - Resolvable `$defs` / `definitions` continue to be inlined exactly as before — no regression in the type-info preservation contract introduced by the previous Mastra fix. -1ba66ca: Fix `tools.execute` (and `tools.get` / `tools.list`) failing with a `ZodError` for every tool from an MCP-backed toolkit (e.g. `granola_mcp`, `apify_mcp`, `tavily_mcp`). MCP toolkits don't declare an output schema, and the Composio API serializes that as `output_parameters: {}`. The SDK's `ParametersSchema` required `{ type: 'object', properties: {...} }`, so `transformToolCases` rejected the response and `getRawComposioToolBySlug` — called by `execute` and the list path — threw. The SDK now normalizes empty (`{}`), `null`, and missing `input_parameters` / `output_parameters` payloads to `undefined` before validation. `outputParameters` was already declared `.optional()` in the public `Tool` type, so this preserves the contract: "undefined means no declared schema." Tools that _do_ declare a schema continue to be validated strictly. No public API change; no toolkit allow-list. -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/cli-local-tools@0.0.5 ### Patch Changes - Updated dependencies [22a9171] - Updated dependencies [93b67e8] - Updated dependencies [b69cef1] - Updated dependencies [1ba66ca] - Updated dependencies [a94715f] - Updated dependencies [ce4b213] - Updated dependencies [44e5458] - @composio/core@0.11.0 ## @composio/anthropic@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/claude-agent-sdk@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/cloudflare@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/google@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/langchain@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/llamaindex@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/mastra@0.9.3 ### Patch Changes -b69cef1: Tolerate dangling `$ref` pointers in tool schemas the Composio API ships without a matching `$defs` entry. Some toolkits (e.g. `GMAIL_FETCH_EMAILS`) emit `outputParameters` with `"$ref": "#/$defs/FetchEmailsResponse"` while never declaring a top-level `$defs` block. After the strict resolver shipped with the previous Mastra fix, this caused `composio.tools.get(...)` to throw `JsonSchemaRefResolutionError` upfront, making every Gmail / Slack / Google-Calendar tool unusable through `MastraProvider`. The SDK now degrades the unresolvable branch to a permissive object schema and surfaces a single observability warning per `(toolSlug, ref)` pair instead of crashing. - `dereferenceJsonSchema` accepts a new optional second argument `{ onUnresolved?: 'throw' | 'sentinel'; onReplace?: (ref, reason) => void }`. Default behavior is unchanged (`'throw'`) — first-party / custom-tool schemas with a typo'd `$ref` still surface as a hard error. Pass `'sentinel'` to replace unresolved branches with the cycle-break sentinel (`{ type: 'object', additionalProperties: true }`) that the resolver already uses for `$ref` cycles. The replaced sentinel carries a default `description` hint so LLMs consuming the wrapped tool's schema get an in-band signal that the branch is opaque; a caller-provided `description` sibling overrides the default (Draft 2020-12 sibling-keyword merge). Safety caps (`MAX_REF_CHAIN_DEPTH`, `MAX_NODE_DEPTH`) keep throwing in both modes. New `UnresolvedRefStrategy`, `UnresolvedRefReason`, and `DereferenceJsonSchemaOptions` type exports. - `MastraProvider.wrapTool` opts both `inputParameters` and `outputParameters` into `'sentinel'` mode and emits one `logger.warn` per `(toolSlug, ref)` pair via the provider-scoped dedup `Set`. User-controlled segments in the warning (`tool.slug`, `toolkit.slug`, `ref`) are `JSON.stringify`d to neutralize embedded newlines / ANSI escapes / control bytes that could otherwise forge log lines (CWE-117). A matching one-shot telemetry event (`composio.mastra.wrapTool.danglingRef`) fires next to the warn so the Composio team has aggregate visibility into which toolkits are affected; the event respects `COMPOSIO_DISABLE_TELEMETRY=true`. - The `telemetry` instance from `@composio/core` is now publicly re-exported alongside `logger`, so providers can emit aggregate signals without reaching into the package's internals. - Resolvable `$defs` / `definitions` continue to be inlined exactly as before — no regression in the type-info preservation contract introduced by the previous Mastra fix. -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/openai@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/openai-agents@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/vercel@0.9.3 ### Patch Changes -ce4b213: fix(providers): normalize string tool-call arguments across all providers Models occasionally emit tool-call arguments as a JSON string instead of an object (most visibly with `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK), which broke downstream validation with errors like `tool_use.input: Input should be a valid dictionary`. `@composio/core` now exposes a single `normalizeToolArguments` helper, and every provider routes model-supplied arguments through it. Object payloads pass through unchanged, JSON strings are parsed, empty/`null` payloads become `{}`, and anything that cannot resolve to an object throws a typed `ComposioInvalidToolArgumentsError` instead of a raw `SyntaxError` or a silently forwarded malformed string. This replaces the inconsistent per-provider guards that previously existed only in vercel, cloudflare and openai-agents. ## @composio/cli@0.2.32 ### Patch Changes - Updated dependencies [22a9171] - Updated dependencies [93b67e8] - Updated dependencies [b69cef1] - Updated dependencies [1ba66ca] - Updated dependencies [a94715f] - Updated dependencies [ce4b213] - Updated dependencies [44e5458] - @composio/core@0.11.0 - @composio/cli-local-tools@0.0.5 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This repository contains the official Software Development Kits (SDKs) for Composio, providing seamless integration capabilities for Python and Typescript Agentic Frameworks and Libraries.
Getting Started
TypeScript SDK Installation
# Using npm
npm install @composio/core
# Using yarn
yarn add @composio/core
# Using pnpm
pnpm add @composio/core
Quick start:
import { Composio } from '@composio/core';
// Initialize the SDK
const composio = new Composio({
// apiKey: 'your-api-key',
});
Simple Agent with OpenAI Agents
npm install @composio/openai-agents @openai/agents
import { Composio } from '@composio/core';
import { OpenAIAgentsProvider } from '@composio/openai-agents';
import { Agent, run } from '@openai/agents';
const composio = new Composio({
provider: new OpenAIAgentsProvider(),
});
const userId = 'user@acme.org';
const tools = await composio.tools.get(userId, {
toolkits: ['HACKERNEWS'],
});
const agent = new Agent({
name: 'Hackernews assistant',
tools: tools,
});
const result = await run(agent, 'What is the latest hackernews post about?');
console.log(JSON.stringify(result.finalOutput, null, 2));
// will return the response from the agent with data from HACKERNEWS API.
Python SDK Installation
# Using pip
pip install composio
# Using poetry
poetry add composio
Quick start:
from composio import Composio
composio = Composio(
# api_key="your-api-key",
)
Simple Agent with OpenAI Agents
pip install composio_openai_agents openai-agents
import asyncio
from agents import Agent, Runner
from composio import Composio
from composio_openai_agents import OpenAIAgentsProvider
# Initialize Composio client with OpenAI Agents Provider
composio = Composio(provider=OpenAIAgentsProvider())
user_id = "user@acme.org"
tools = composio.tools.get(user_id=user_id, toolkits=["HACKERNEWS"])
# Create an agent with the tools
agent = Agent(
name="Hackernews Agent",
instructions="You are a helpful assistant.",
tools=tools,
)
# Run the agent
async def main():
result = await Runner.run(
starting_agent=agent,
input="What's the latest Hackernews post about?",
)
print(result.final_output)
asyncio.run(main())
# will return the response from the agent with data from HACKERNEWS API.
For more detailed usage instructions and examples, please refer to each SDK's specific documentation.
Open API Specification
To update the OpenAPI specifications used for generating SDK documentation:
# Pull the latest API specifications from the backend
pnpm api:pull
This command pulls the OpenAPI specification from https://backend.composio.dev/api/v3/openapi.json and updates the local API documentation files.
This is pulled automatically with build step.
Available SDKs
TypeScript SDK (/ts)
The TypeScript SDK provides a modern, type-safe way to interact with Composio's services. It's designed for both Node.js and browser environments, offering full TypeScript support with comprehensive type definitions.
For detailed information about the TypeScript SDK, please refer to the TypeScript SDK Documentation.
Python SDK (/python)
The Python SDK offers a Pythonic interface to Composio's services, making it easy to integrate Composio into your Python applications. It supports Python 3.10+ and follows modern Python development practices.
For detailed information about the Python SDK, please refer to the Python SDK Documentation.
Provider Support
The following table shows which AI frameworks and platforms are supported in each SDK:
| Provider | TypeScript | Python |
|---|---|---|
| OpenAI | ✅ | ✅ |
| OpenAI Agents | ✅ | ✅ |
| Anthropic | ✅ | ✅ |
| LangChain | ✅ | ✅ |
| LangGraph | ✅* | ✅ |
| LlamaIndex | ✅ | ✅ |
| Vercel AI SDK | ✅ | ❌ |
| Google Gemini | ✅ | ✅ |
| Google ADK | ❌ | ✅ |
| Mastra | ✅ | ❌ |
| Cloudflare Workers AI | ✅ | ❌ |
| CrewAI | ❌ | ✅ |
| AutoGen | ❌ | ✅ |
* LangGraph in TypeScript is supported via the @composio/langchain package.
Don't see your provider? Learn how to build a custom provider to integrate with any AI framework.
Packages
Core Packages
| Package | Version |
|---|---|
| TypeScript | |
| @composio/core | |
| Python | |
| composio |
Provider Packages
Utility Packages
| Package | Version |
|---|---|
| @composio/json-schema-to-zod | |
| @composio/ts-builders |
if you are looking for the older sdk, you can find them here
Rube
Rube is a Model Context Protocol (MCP) server built with Composio. It connects your AI tools to 500+ apps like Gmail, Slack, GitHub, and Notion. Simply install it in your AI client, authenticate once with your apps, and start asking your AI to perform real actions like "Send an email" or "Create a task."
It integrates with major AI clients like Cursor, Claude Desktop, VS Code, Claude Code and any custom MCP‑compatible client. You can switch between these clients and your integrations follow you.
Contributing
We welcome contributions to both SDKs! Please read our contribution guidelines before submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you encounter any issues or have questions about the SDKs:
- Open an issue in this repository
- Contact our support team
- Check our documentation
