Skip to main content

ToolProvider

The ToolProvider interface defines how the editor discovers and resolves integration tools from external platforms. Mastra includes two built-in implementations: ComposioToolProvider and ArcadeToolProvider.

See Editor tools for provider setup and the Studio workflow. See tool configuration for stored selections and resolution behavior.

ToolProvider interface
Direct link to ToolProvider interface

Providers expose metadata and the legacy discovery and resolution methods. Agent Builder integrations can also implement the optional VNext catalog, connection, authorization, and health methods.

info:

ToolProviderInfo
Provider ID, name, and description.

displayName?:

string
Optional name shown in the tool picker. Defaults to info.name.

capabilities?:

ToolProviderCapabilities
Static connection and revocation capabilities. Required for VNext providers.

defaultScope?:

'per-author' | 'caller-supplied'
Default connection identity scope. Defaults to 'per-author' when omitted.

listToolkits()?:

() => Promise<ToolProviderListResult<ToolProviderToolkit>>
Lists available toolkits through the legacy interface.

listTools(params?):

(params?: ListToolProviderToolsOptions) => Promise<ToolProviderListResult<ToolProviderToolInfo>>
Lists tools with optional toolkit, search, and pagination filters.

getToolSchema(slug)?:

(slug: string) => Promise<Record<string, unknown> | null>
Returns a tool input schema through the legacy interface.

resolveTools(slugs, configs?, options?):

(slugs: string[], configs?: Record<string, StorageToolConfig>, options?: ResolveToolProviderToolsOptions) => Promise<Record<string, ToolAction>>
Resolves legacy tool selections into executable Mastra tools.

listToolkitsVNext()?:

() => Promise<ListToolkitsResult>
Lists allowed toolkits for Agent Builder and Editor.

listToolsVNext(options?)?:

(options?: ListToolsOpts) => Promise<ListToolsResult>
Lists allowed tools with toolkit, search, and pagination options.

resolveToolsVNext(options)?:

(options: ResolveToolsOpts) => Promise<Record<string, ToolAction>>
Resolves tools for one set of slugs and one authorized connection.

authorize(options)?:

(options: AuthorizeOpts) => Promise<{ url: string; authId: string }>
Starts an authorization flow.

listConnectionFields(options)?:

(options: { toolkit: string }) => Promise<ConnectionField[]>
Lists provider-specific values required to authorize a toolkit.

getAuthStatus(authId)?:

(authId: string) => Promise<AuthFlowStatus>
Returns the state of an authorization flow.

getConnectionStatus(options)?:

(options: { items: Array<{ connectionId: string; toolkit: string }> }) => Promise<Record<string, { connected: boolean }>>
Checks whether a batch of connections is still active.

listConnections(options)?:

(options: ListConnectionsOpts) => Promise<ListConnectionsResult>
Lists existing provider connections for a user and toolkit.

getHealth()?:

() => Promise<ToolProviderHealth>
Returns provider configuration and reachability health.

revokeConnection(connectionId)?:

(connectionId: string) => Promise<void>
Revokes a provider connection.

ComposioToolProvider
Direct link to ComposioToolProvider

Connects to Composio for access to hundreds of integration tools.

Usage example
Direct link to Usage example

src/mastra/index.ts
import { MastraEditor } from '@mastra/editor'
import { ComposioToolProvider } from '@mastra/editor/composio'

const editor = new MastraEditor({
toolProviders: {
composio: new ComposioToolProvider({
apiKey: process.env.COMPOSIO_API_KEY!,
}),
},
})

Constructor parameters
Direct link to Constructor parameters

apiKey:

string
Your Composio API key.

allowedToolkits?:

readonly string[]
Toolkit slug allowlist. Supports exact matches and suffix wildcards.

allowedTools?:

Readonly<Record<string, readonly string[]>>
Per-toolkit tool slug allowlists. Supports exact matches and prefix wildcards.

defaultScope?:

'per-author' | 'caller-supplied'
= 'per-author'
Connection identity scope. Defaults to per-author.

userIdResolver?:

ComposioUserIdResolver
Server-side resolver that derives the effective Composio userId from authenticated context fields. Used for invoker and caller-supplied execution. The exact connected account always comes from the stored connection pin.

Tool slugs
Direct link to Tool slugs

Composio tools use uppercase slug format: GITHUB_CREATE_ISSUE, SLACK_SEND_MESSAGE.

Authentication
Direct link to Authentication

Connections use per-author scope by default. Set defaultScope: 'caller-supplied' to bucket authorization by the caller identity resolved from MASTRA_RESOURCE_ID_KEY in request context. Ensure each authenticated request provides a stable, unique resource ID. When using MastraAuthWorkos, configure mapUserToResourceId to set this value from the authenticated user.

How the provider resolves the Composio user for a tool call depends on the connection:

  • Author-bound connections (kind: 'author') execute as the agent author's user against the pinned connected account.
  • Invoker-bound connections (kind: 'invoker') execute as the authenticated invoker against the exact pinned account, which may be an account another user shared with the invoker through Composio's access control list (ACL). The user ID comes from userIdResolver when configured, then the authenticated user, and never from the Memory resourceId. Invoker resolution fails when no authenticated user or resolver result exists.
  • Caller-supplied scope (scope: 'caller-supplied') uses userIdResolver when configured. Otherwise, it falls back to the legacy resourceId from request context for backward compatibility. When a specific connected account is pinned, execution routes to that exact account. Otherwise, Composio auto-resolves within the user's bucket.

Execute with a shared account
Direct link to Execute with a shared account

Bob needs to run a Salesforce tool with an account that Alice shared through Composio. Keep each identity separate:

IdentityValue
Memory resourceproject_123
Composio user IDbob
Connected accountca_alice_salesforce

Register the provider normally. Mastra server authentication writes the authenticated user to request context, so most applications don't need a userIdResolver:

src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { MastraEditor } from '@mastra/editor'
import { ComposioToolProvider } from '@mastra/editor/composio'

const editor = new MastraEditor({
toolProviders: {
composio: new ComposioToolProvider({
apiKey: process.env.COMPOSIO_API_KEY!,
}),
},
})

export const mastra = new Mastra({ editor })

Configure the agent with an invoker connection pinned to ca_alice_salesforce. When Bob invokes the agent, Mastra sends bob as the Composio user and the pinned account ID as the exact connected account. The Memory resource stays project_123. Composio then checks whether the account's ACL permits Bob to execute it.

Map application users to Composio users
Direct link to Map application users to Composio users

Use userIdResolver when your Composio user IDs differ from the IDs returned by Mastra authentication, or when your application must authorize the stored account pin before execution.

type ComposioUserIdResolver = (
input: ComposioUserIdResolverInput,
) => Promise<string | undefined> | string | undefined

requestContext?:

RequestContext
Live per-request context. Client-provided non-reserved entries are untrusted. Derive identity and authorize connectedAccountId only from validated, server-populated fields such as MASTRA_USER_KEY, read with getRaw().

toolkit?:

string
Toolkit slug the identity is being resolved for, when known.

connectedAccountId?:

string
Stored connection pin being resolved, when one exists. Use it to validate that the invoker may use this exact account.

The resolver returns the Composio user ID, or undefined to use the provider's default resolution. Returning an empty string throws instead of silently falling back. The resolver can't replace the connected account.

This example namespaces the Composio user by organization and asks the application's authorization layer to approve the exact account pin:

src/mastra/index.ts
import { MASTRA_USER_KEY } from '@mastra/server/auth'
import { ComposioToolProvider } from '@mastra/editor/composio'
import { canUseConnectedAccount } from './integration-authorization'

type AuthenticatedUser = {
id: string
organizationId: string
}

function isAuthenticatedUser(value: unknown): value is AuthenticatedUser {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
typeof value.id === 'string' &&
'organizationId' in value &&
typeof value.organizationId === 'string'
)
}

const composio = new ComposioToolProvider({
apiKey: process.env.COMPOSIO_API_KEY!,
userIdResolver: async ({ requestContext, toolkit, connectedAccountId }) => {
const user = requestContext?.getRaw(MASTRA_USER_KEY)
if (!isAuthenticatedUser(user)) return undefined

if (connectedAccountId) {
const allowed = await canUseConnectedAccount({
actorId: user.id,
organizationId: user.organizationId,
provider: 'composio',
toolkit,
connectedAccountId,
})
if (!allowed) {
throw new Error('User cannot access this connected account')
}
}

return `${user.organizationId}:${user.id}`
},
})

Use the same namespaced ID when creating Composio connections and shared-account ACL entries. For example, Bob's Composio user ID in this setup is acme:bob.

Throw from userIdResolver to deny the request. During stored-agent resolution, Mastra logs the failure and omits tools associated with that connection, so no tool call reaches Composio. Other connections continue to resolve. When calling resolveToolsVNext() directly, the error is returned to the caller instead.

Connection management tools
Direct link to Connection management tools

Composio provides tools for starting and monitoring authorization from an agent chat. When allowedToolkits is set, include composio to make these tools available:

src/mastra/index.ts
const editor = new MastraEditor({
toolProviders: {
composio: new ComposioToolProvider({
apiKey: process.env.COMPOSIO_API_KEY!,
allowedToolkits: ['composio', 'gmail'],
defaultScope: 'caller-supplied',
}),
},
})

Add only the connection management tools that the agent needs:

ToolBehavior
COMPOSIO_MANAGE_CONNECTIONSCreates an authorization link in chat through a session owned by the caller.
COMPOSIO_WAIT_FOR_CONNECTIONSWaits for the caller to finish authorization before the agent continues.

COMPOSIO_WAIT_FOR_CONNECTIONS is optional. Without it, complete authorization and return to the chat. Then ask the agent to continue. The connected account remains associated with the caller resource ID for later requests.


ArcadeToolProvider
Direct link to ArcadeToolProvider

Connects to Arcade for a curated tool catalog with built-in authentication.

Usage example
Direct link to Usage example

src/mastra/index.ts
import { MastraEditor } from '@mastra/editor'
import { ArcadeToolProvider } from '@mastra/editor/arcade'

const editor = new MastraEditor({
toolProviders: {
arcade: new ArcadeToolProvider({
apiKey: process.env.ARCADE_API_KEY!,
}),
},
})

Constructor parameters
Direct link to Constructor parameters

apiKey:

string
Your Arcade API key.

baseURL?:

string
Custom base URL for the Arcade API.

Tool slugs
Direct link to Tool slugs

Arcade tools use Toolkit.ToolName format: Github.GetRepository, Slack.SendMessage.

Authentication
Direct link to Authentication

The legacy Arcade resolver uses resourceId from request context when available. It otherwise falls back to the supplied userId, then to a shared default identity. Use default only for intentionally shared integrations. In tenant-isolated deployments, provide a trusted, stable resourceId or explicit userId. Omitting both doesn't isolate callers.