> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/kortix-ai/suna/llms.txt
> Use this file to discover all available pages before exploring further.

# Composio Integration

> Integrate with Composio platform for seamless third-party service connections

## Overview

Kortix provides deep integration with [Composio](https://composio.dev), enabling agents to connect to 150+ third-party services through managed OAuth, MCP servers, and credential profiles. The integration handles authentication, MCP server provisioning, and credential management automatically.

## Architecture

The Composio integration consists of several service layers:

```
┌─────────────────────────────────────────────┐
│     ComposioIntegrationService              │
│  (Orchestrates complete integration flow)   │
└─────────────────────────────────────────────┘
              │
              ├─── ToolkitService
              ├─── AuthConfigService
              ├─── ConnectedAccountService
              ├─── MCPServerService
              └─── ComposioProfileService
```

### Core Services

#### 1. ToolkitService

**Module:** `core/composio_integration/toolkit_service.py`

Manages toolkit discovery and information:

* List available toolkits (Gmail, Slack, GitHub, etc.)
* Search toolkits by name or category
* Get toolkit details and required scopes

#### 2. AuthConfigService

**Module:** `core/composio_integration/auth_config_service.py`

Handles authentication configuration:

* Create OAuth configs for toolkits
* Manage custom OAuth apps
* Configure scopes and permissions

#### 3. ConnectedAccountService

**Module:** `core/composio_integration/connected_account_service.py`

Manages user connections:

* Create connected accounts
* Handle OAuth flow
* Check connection status
* Refresh tokens

#### 4. MCPServerService

**Module:** `core/composio_integration/mcp_server_service.py`

Provisions MCP servers:

* Create MCP servers for toolkits
* Generate user-specific MCP URLs
* Configure server permissions

#### 5. ComposioProfileService

**Module:** `core/composio_integration/composio_profile_service.py`

Stores credential profiles:

* Save integration configurations
* Retrieve MCP URLs for runtime
* Manage multiple profiles per toolkit

## Complete Integration Flow

The `ComposioIntegrationService` orchestrates the entire integration process:

```python theme={null}
from core.composio_integration.composio_service import ComposioIntegrationService
from core.services.supabase import DBConnection

# Initialize service
db = DBConnection()
service = ComposioIntegrationService(
    api_key="your_composio_api_key",
    db_connection=db
)

# Complete integration in one call
result = await service.integrate_toolkit(
    toolkit_slug="gmail",
    account_id="user_account_id",
    user_id="user_unique_id",
    profile_name="Gmail for Sales",
    display_name="Gmail Integration",
    save_as_profile=True,
    initiation_fields={"subdomain": "company"}  # If required
)

print(f"MCP URL: {result.final_mcp_url}")
print(f"Profile ID: {result.profile_id}")
print(f"Connected Account: {result.connected_account.id}")
```

### What Happens Behind the Scenes

The integration performs these steps automatically:

```python theme={null}
async def integrate_toolkit(
    self,
    toolkit_slug: str,
    account_id: str,
    user_id: str,
    profile_name: Optional[str] = None,
    save_as_profile: bool = True,
    initiation_fields: Optional[Dict[str, str]] = None,
    custom_auth_config: Optional[Dict[str, str]] = None,
    use_custom_auth: bool = False
) -> ComposioIntegrationResult:
    # Step 1: Verify toolkit exists
    toolkit = await self.toolkit_service.get_toolkit_by_slug(toolkit_slug)
    
    # Step 2: Create auth config (OAuth)
    auth_config = await self.auth_config_service.create_auth_config(
        toolkit_slug,
        initiation_fields=initiation_fields,
        custom_auth_config=custom_auth_config,
        use_custom_auth=use_custom_auth
    )
    
    # Step 3: Create connected account (user's OAuth connection)
    connected_account = await self.connected_account_service.create_connected_account(
        auth_config_id=auth_config.id,
        user_id=user_id,
        initiation_fields=initiation_fields
    )
    
    # Step 4: Create MCP server
    mcp_server = await self.mcp_server_service.create_mcp_server(
        auth_config_ids=[auth_config.id],
        name=f"{toolkit.name} MCP Server",
        toolkit_name=toolkit.name
    )
    
    # Step 5: Generate user-specific MCP URL
    mcp_url_response = await self.mcp_server_service.generate_mcp_url(
        mcp_server_id=mcp_server.id,
        connected_account_ids=[connected_account.id],
        user_ids=[user_id]
    )
    
    # Prefer account-specific URL (more secure)
    final_mcp_url = mcp_url_response.connected_account_urls[0]
    
    # Step 6: Save as credential profile (optional)
    if save_as_profile:
        profile = await self.profile_service.create_profile(
            account_id=account_id,
            profile_name=profile_name or f"{toolkit.name} Integration",
            toolkit_slug=toolkit_slug,
            mcp_url=final_mcp_url,
            user_id=user_id,
            connected_account_id=connected_account.id
        )
        profile_id = profile.profile_id
    
    return ComposioIntegrationResult(
        toolkit=toolkit,
        auth_config=auth_config,
        connected_account=connected_account,
        mcp_server=mcp_server,
        mcp_url_response=mcp_url_response,
        final_mcp_url=final_mcp_url,
        profile_id=profile_id
    )
```

## Using Composio Tools in Agents

### Method 1: Via MCP Configuration

Once integrated, use the MCP URL in your agent configuration:

```python theme={null}
from core.tools.mcp_tool_wrapper import MCPToolWrapper

# Using the MCP URL from integration
mcp_configs = [
    {
        "name": "gmail_integration",
        "isCustom": True,
        "customType": "composio",
        "config": {
            "profile_id": result.profile_id  # From integration result
        },
        "enabledTools": [  # Optional: filter tools
            "GMAIL_SEND_EMAIL",
            "GMAIL_READ_EMAIL",
            "GMAIL_SEARCH_EMAIL"
        ]
    }
]

mcp_wrapper = MCPToolWrapper(
    mcp_configs=mcp_configs,
    use_cache=True,
    account_id=account_id
)

await mcp_wrapper.initialize_and_register_tools()
```

### Method 2: Direct MCP URL Usage

```python theme={null}
mcp_configs = [
    {
        "name": "gmail",
        "isCustom": True,
        "customType": "http",
        "config": {
            "url": result.final_mcp_url  # Direct URL from Composio
        }
    }
]
```

### Executing Composio Tools

```python theme={null}
# Tools are available as methods on the MCP wrapper
result = await mcp_wrapper.GMAIL_SEND_EMAIL(
    to="recipient@example.com",
    subject="Hello from Kortix",
    body="This email was sent via Composio integration!"
)

# Or use execute method
result = await mcp_wrapper._execute_mcp_tool(
    tool_name="GMAIL_SEND_EMAIL",
    arguments={
        "to": "recipient@example.com",
        "subject": "Hello",
        "body": "Message content"
    }
)
```

## Composio Upload Tool

For Gmail attachments and file operations, use the `ComposioUploadTool`:

```python theme={null}
from core.tools.composio_upload_tool import ComposioUploadTool

upload_tool = ComposioUploadTool()

# Upload file to Composio storage
result = await upload_tool.upload_file(
    file_path="/workspace/presentation.pptx",
    file_name="presentation.pptx"
)

# Result contains attachment data
attachment_data = json.loads(result.output)
print(attachment_data)  # {"s3key": "...", "mimetype": "...", "name": "..."}

# Use with Gmail
await mcp_wrapper.GMAIL_SEND_EMAIL(
    to="recipient@example.com",
    subject="Presentation",
    body="Please find attached",
    attachment=attachment_data  # Pass attachment data directly
)
```

**Important:** When attaching presentations to emails, ALWAYS export and attach `.pptx` format (not PDF) unless explicitly requested otherwise.

## Custom OAuth Apps

For white-label deployments, use custom OAuth credentials:

```python theme={null}
result = await service.integrate_toolkit(
    toolkit_slug="gmail",
    account_id=account_id,
    user_id=user_id,
    use_custom_auth=True,
    custom_auth_config={
        "client_id": "your_oauth_client_id",
        "client_secret": "your_oauth_client_secret",
        "scopes": ["https://www.googleapis.com/auth/gmail.send"],
        "redirect_uri": "https://your-app.com/oauth/callback"
    }
)
```

## Credential Profiles

Profiles allow users to have multiple integrations for the same toolkit:

```python theme={null}
from core.composio_integration.composio_profile_service import ComposioProfileService

profile_service = ComposioProfileService(db)

# Create profile
profile = await profile_service.create_profile(
    account_id=account_id,
    profile_name="Work Gmail",
    toolkit_slug="gmail",
    toolkit_name="Gmail",
    mcp_url=mcp_url,
    user_id=user_id,
    is_default=True
)

# List profiles for toolkit
profiles = await profile_service.get_profiles(
    account_id=account_id,
    toolkit_slug="gmail"
)

for profile in profiles:
    print(f"Profile: {profile.profile_name}")
    print(f"Status: {profile.status}")
    print(f"Default: {profile.is_default}")

# Get MCP URL for runtime
mcp_url = await profile_service.get_mcp_url_for_runtime(
    profile_id=profile.profile_id,
    account_id=account_id
)

# Delete profile
await profile_service.delete_profile(
    profile_id=profile.profile_id,
    account_id=account_id
)
```

## Checking Integration Status

```python theme={null}
# Check if OAuth connection is still valid
status = await service.get_integration_status(
    connected_account_id=result.connected_account.id
)

print(f"Status: {status['status']}")  # "ACTIVE", "EXPIRED", etc.
print(f"Expires at: {status['expires_at']}")

# Refresh if needed
if status['status'] == 'EXPIRED':
    refreshed = await connected_account_service.refresh_account(
        connected_account_id=result.connected_account.id
    )
```

## Available Toolkits

### List All Toolkits

```python theme={null}
toolkits = await service.list_available_toolkits(limit=100)

for toolkit in toolkits['items']:
    print(f"{toolkit['name']} ({toolkit['slug']})")
    print(f"  Category: {toolkit['category']}")
    print(f"  Tools: {toolkit['tool_count']}")
```

### Search Toolkits

```python theme={null}
results = await service.search_toolkits(
    query="email",
    category="communication",
    limit=20
)

for toolkit in results['items']:
    print(f"Found: {toolkit['name']}")
```

### Popular Toolkits

**Communication:**

* Gmail - Email operations
* Slack - Team messaging
* Discord - Community chat
* Microsoft Teams - Enterprise messaging

**Productivity:**

* Google Drive - File storage
* Notion - Knowledge management
* Asana - Project management
* Trello - Task boards

**Development:**

* GitHub - Code repositories
* GitLab - DevOps platform
* Jira - Issue tracking
* Linear - Project management

**CRM & Sales:**

* Salesforce - CRM platform
* HubSpot - Marketing & sales
* Zendesk - Customer support
* Intercom - Customer messaging

**Calendar & Scheduling:**

* Google Calendar - Event management
* Outlook Calendar - Microsoft calendar
* Calendly - Scheduling tool

## Environment Variables

Required environment variables:

```bash theme={null}
# Composio API key
COMPOSIO_API_KEY=your_composio_api_key

# Optional: Custom OAuth apps
GMAIL_CLIENT_ID=your_gmail_client_id
GMAIL_CLIENT_SECRET=your_gmail_client_secret

SLACK_CLIENT_ID=your_slack_client_id
SLACK_CLIENT_SECRET=your_slack_client_secret
```

## Error Handling

```python theme={null}
try:
    result = await service.integrate_toolkit(
        toolkit_slug="gmail",
        account_id=account_id,
        user_id=user_id
    )
except ValueError as e:
    # Toolkit not found or invalid configuration
    logger.error(f"Configuration error: {e}")
except httpx.HTTPError as e:
    # Composio API error
    logger.error(f"API error: {e}")
except Exception as e:
    # Unexpected error
    logger.error(f"Integration failed: {e}", exc_info=True)
```

## Special Toolkit Considerations

### Gmail Attachments

Gmail tools have special attachment handling:

```python theme={null}
# The MCP registry enriches Gmail tool descriptions automatically
def _enrich_description(tool_name: str, description: str) -> str:
    _GMAIL_ATTACHMENT_TOOLS = {
        "GMAIL_SEND_EMAIL", 
        "GMAIL_CREATE_EMAIL_DRAFT", 
        "GMAIL_REPLY_TO_THREAD"
    }
    
    if tool_name.upper() in _GMAIL_ATTACHMENT_TOOLS:
        return description + """
        To attach files: first use composio_upload to upload the file to Composio storage.
        The response includes attachment data (s3key, mimetype, name).
        Pass these to the attachment parameter.
        IMPORTANT: When attaching presentations, always export .pptx (not .pdf) unless requested.
        """
    return description
```

### Zendesk Configuration

Zendesk requires subdomain in initiation\_fields:

```python theme={null}
result = await service.integrate_toolkit(
    toolkit_slug="zendesk",
    account_id=account_id,
    user_id=user_id,
    initiation_fields={
        "subdomain": "yourcompany"  # yourcompany.zendesk.com
    }
)
```

## Best Practices

1. **Use Profile Management**: Store credentials in profiles for reusability
2. **Enable Caching**: Use `use_cache=True` for faster MCP tool loading
3. **Filter Tools**: Use `enabledTools` to load only needed tools
4. **Handle OAuth Expiry**: Check integration status periodically
5. **Custom OAuth**: Use custom OAuth apps for white-label deployments
6. **Error Recovery**: Implement retry logic for transient API failures
7. **Account-Specific URLs**: Prefer connected\_account URLs over user\_id URLs

## Advanced Usage

### Multiple Profiles for Same Toolkit

```python theme={null}
# Work Gmail
work_result = await service.integrate_toolkit(
    toolkit_slug="gmail",
    account_id=account_id,
    user_id="work_user_id",
    profile_name="Work Gmail",
    is_default=True
)

# Personal Gmail
personal_result = await service.integrate_toolkit(
    toolkit_slug="gmail",
    account_id=account_id,
    user_id="personal_user_id",
    profile_name="Personal Gmail",
    is_default=False
)

# Use specific profile
work_mcp_url = await profile_service.get_mcp_url_for_runtime(
    profile_id=work_result.profile_id,
    account_id=account_id
)
```

### Trigger-Based Automations

Composio supports triggers for event-driven workflows:

```python theme={null}
from core.composio_integration.composio_trigger_service import ComposioTriggerService

trigger_service = ComposioTriggerService()

# Set up Gmail trigger
trigger = await trigger_service.create_trigger(
    toolkit_slug="gmail",
    trigger_name="GMAIL_NEW_EMAIL_RECEIVED",
    connected_account_id=result.connected_account.id,
    webhook_url="https://your-app.com/webhooks/gmail",
    filters={
        "from": "important@example.com"
    }
)
```

## Next Steps

* [MCP Integration](/tools/mcp-integration) - General MCP integration guide
* [Custom Tools](/tools/custom-tools) - Create custom tools
* [Built-in Tools](/tools/built-in-tools) - Explore native tools
