Files
composio-skills-reference/composio-sdk/rules/tr-framework-integration.md
sohamganatra b8b711dff6 Add Composio SDK skill with rules and agent config
Adds composio-sdk/ with SKILL.md, AGENTS.md, and 18 rule files
covering Tool Router, direct execution, triggers, and auth patterns.

Source: composiohq/skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 22:54:21 -08:00

21 KiB

title, impact, description, tags
title impact description tags
Integrate Tool Router with AI Frameworks HIGH Connect Tool Router sessions with popular AI frameworks using MCP or native tools
tool-router
frameworks
integration
vercel
openai
langchain
claude
crewai

Integrate Tool Router with AI Frameworks

Tool Router works with any AI framework through two methods: Native Tools (recommended for speed) or MCP (for framework flexibility). Choose native tools when available for better performance and control.

Integration Methods

Method Pros Cons When to Use
Native Tools Faster execution
Full control with modifiers
No MCP overhead
Framework lock-in Single framework, production apps
MCP Framework independent
Works with any MCP client
Easy framework switching
⚠️ Slower (extra API roundtrip)
⚠️ Less control
Multi-framework, prototyping

MCP Headers Configuration

When using MCP, the session.mcp.headers object contains the authentication headers required to connect to the Composio MCP server:

{
  "x-api-key": "your_composio_api_key"
}

Using with MCP Clients

When configuring MCP clients (like Claude Desktop), you need to provide the Composio API key in the headers:

{
  "mcpServers": {
    "composio": {
      "type": "http",
      "url": "https://mcp.composio.dev/session/your_session_id",
      "headers": {
        "x-api-key": "your_composio_api_key"
      }
    }
  }
}

Where to find your Composio API key:

  • Login to Composio Platform
  • Select your project
  • Navigate to Settings to find your API keys
  • Or set it via environment variable: COMPOSIO_API_KEY

When using Tool Router sessions programmatically, the headers are automatically included in session.mcp.headers.

Incorrect - Using Tools Without Tool Router

// DON'T: Use tools directly without session isolation
import { Composio } from '@composio/core';
import { VercelProvider } from '@composio/vercel';

const composio = new Composio({ provider: new VercelProvider() });

// ❌ No user isolation
// ❌ Tools not scoped per user
// ❌ All users share same tools
const tools = await composio.tools.get('default', {
  toolkits: ['gmail']
});
# DON'T: Use tools directly without session isolation
from composio import Composio
from composio_openai_agents import OpenAIAgentsProvider

composio = Composio(provider=OpenAIAgentsProvider())

# ❌ No user isolation
# ❌ Tools not scoped per user
# ❌ All users share same tools
tools = composio.tools.get(
    user_id="default",
    toolkits=["gmail"]
)

Correct - Vercel AI SDK (Native Tools)

// DO: Use Tool Router with native tools for best performance
import { openai } from '@ai-sdk/openai';
import { Composio } from '@composio/core';
import { VercelProvider } from '@composio/vercel';
import { streamText } from 'ai';

// Initialize Composio with Vercel provider
const composio = new Composio({
  provider: new VercelProvider()
});

async function runAgent(userId: string, prompt: string) {
  // Create isolated session for user
  const session = await composio.create(userId, {
    toolkits: ['gmail'],
    manageConnections: true
  });

  // Get native Vercel-formatted tools
  const tools = await session.tools();

  // Stream response with tools
  const stream = await streamText({
    model: openai('gpt-4o'),
    prompt,
    tools,
    maxSteps: 10
  });

  // ✅ Fast execution (no MCP overhead)
  // ✅ User-isolated tools
  // ✅ Native Vercel format

  for await (const textPart of stream.textStream) {
    process.stdout.write(textPart);
  }
}

await runAgent('user_123', 'Fetch my last email from Gmail');
# DO: Use Tool Router with native tools for best performance
from composio import Composio
from composio_vercel import VercelProvider
from ai import streamText, openai

# Initialize Composio with Vercel provider
composio = Composio(provider=VercelProvider())

async def run_agent(user_id: str, prompt: str):
    # Create isolated session for user
    session = composio.create(
        user_id=user_id,
        toolkits=["gmail"],
        manage_connections=True
    )

    # Get native Vercel-formatted tools
    tools = session.tools()

    # Stream response with tools
    stream = streamText(
        model=openai("gpt-4o"),
        prompt=prompt,
        tools=tools,
        max_steps=10
    )

    # ✅ Fast execution (no MCP overhead)
    # ✅ User-isolated tools
    # ✅ Native Vercel format

    async for text_part in stream.text_stream:
        print(text_part, end="")

await run_agent("user_123", "Fetch my last email from Gmail")

Correct - Vercel AI SDK (MCP)

// DO: Use MCP when framework flexibility is needed
import { openai } from '@ai-sdk/openai';
import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp';
import { Composio } from '@composio/core';
import { streamText } from 'ai';

const composio = new Composio();

async function runAgentMCP(userId: string, prompt: string) {
  // Create session (MCP URL only, no provider needed)
  const session = await composio.create(userId, {
    toolkits: ['gmail'],
    manageConnections: true
  });

  // Create MCP client
  const client = await createMCPClient({
    transport: {
      type: 'http',
      url: session.mcp.url,
      headers: session.mcp.headers
    }
  });

  // Get tools from MCP server
  const tools = await client.tools();

  // Stream response
  const stream = await streamText({
    model: openai('gpt-4o'),
    prompt,
    tools,
    maxSteps: 10
  });

  // ✅ Framework independent
  // ✅ User-isolated tools
  // ⚠️ Slower (MCP overhead)

  for await (const textPart of stream.textStream) {
    process.stdout.write(textPart);
  }
}

await runAgentMCP('user_123', 'Fetch my last email');

Correct - OpenAI Agents SDK (Native Tools)

// DO: Use native tools with 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()
});

async function createAssistant(userId: string) {
  // Create session with native tools
  const session = await composio.create(userId, {
    toolkits: ['gmail', 'slack']
  });

  // Get native OpenAI Agents formatted tools
  const tools = await session.tools();

  // Create agent with tools
  const agent = new Agent({
    name: 'Personal Assistant',
    model: 'gpt-4o',
    instructions: 'You are a helpful assistant. Use tools to help users.',
    tools
  });

  // ✅ Fast execution
  // ✅ Native OpenAI Agents format
  // ✅ Full control

  return agent;
}

const agent = await createAssistant('user_123');
const result = await run(agent, 'Check my emails and send a summary to Slack');
console.log(result.finalOutput);
# DO: Use native tools with OpenAI Agents
from composio import Composio
from composio_openai_agents import OpenAIAgentsProvider
from agents import Agent, Runner

composio = Composio(provider=OpenAIAgentsProvider())

async def create_assistant(user_id: str):
    # Create session with native tools
    session = composio.create(
        user_id=user_id,
        toolkits=["gmail", "slack"]
    )

    # Get native OpenAI Agents formatted tools
    tools = session.tools()

    # Create agent with tools
    agent = Agent(
        name="Personal Assistant",
        model="gpt-4o",
        instructions="You are a helpful assistant. Use tools to help users.",
        tools=tools
    )

    # ✅ Fast execution
    # ✅ Native OpenAI Agents format
    # ✅ Full control

    return agent

agent = await create_assistant("user_123")
result = await Runner.run(
    starting_agent=agent,
    input="Check my emails and send a summary to Slack"
)
print(result.final_output)

Correct - OpenAI Agents SDK (MCP)

// DO: Use MCP with OpenAI Agents for flexibility
import { Composio } from '@composio/core';
import { Agent, run, hostedMcpTool } from '@openai/agents';

const composio = new Composio();

async function createAssistantMCP(userId: string) {
  // Create session
  const { mcp } = await composio.create(userId, {
    toolkits: ['gmail']
  });

  // Create agent with MCP tool
  const agent = new Agent({
    name: 'Gmail Assistant',
    model: 'gpt-4o',
    instructions: 'Help users manage their Gmail.',
    tools: [
      hostedMcpTool({
        serverLabel: 'composio',
        serverUrl: mcp.url,
        headers: mcp.headers
      })
    ]
  });

  // ✅ Framework independent
  // ⚠️ Slower execution

  return agent;
}

const agent = await createAssistantMCP('user_123');
const result = await run(agent, 'Fetch my last email');
# DO: Use MCP with OpenAI Agents for flexibility
from composio import Composio
from agents import Agent, Runner, HostedMCPTool

composio = Composio()

def create_assistant_mcp(user_id: str):
    # Create session
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Create agent with MCP tool
    composio_mcp = HostedMCPTool(
        tool_config={
            "type": "mcp",
            "server_label": "composio",
            "server_url": session.mcp.url,
            "require_approval": "never",
            "headers": session.mcp.headers
        }
    )

    agent = Agent(
        name="Gmail Assistant",
        instructions="Help users manage their Gmail.",
        tools=[composio_mcp]
    )

    # ✅ Framework independent
    # ⚠️ Slower execution

    return agent

agent = create_assistant_mcp("user_123")
result = Runner.run_sync(starting_agent=agent, input="Fetch my last email")
print(result.final_output)

Correct - LangChain (MCP)

// DO: Use LangChain with MCP
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import { createAgent } from 'langchain';
import { Composio } from '@composio/core';

const composio = new Composio();

async function createLangChainAgent(userId: string) {
  // Create session
  const session = await composio.create(userId, {
    toolkits: ['gmail']
  });

  // Create MCP client
  const client = new MultiServerMCPClient({
    composio: {
      transport: 'http',
      url: session.mcp.url,
      headers: session.mcp.headers
    }
  });

  // Get tools
  const tools = await client.getTools();

  // Create agent
  const llm = new ChatOpenAI({ model: 'gpt-4o' });

  const agent = createAgent({
    name: 'Gmail Assistant',
    systemPrompt: 'You help users manage their Gmail.',
    model: llm,
    tools
  });

  return agent;
}

const agent = await createLangChainAgent('user_123');
const result = await agent.invoke({
  messages: [{ role: 'user', content: 'Fetch my last email' }]
});
console.log(result);
# DO: Use LangChain with MCP
from composio import Composio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain_openai.chat_models import ChatOpenAI

composio = Composio()

async def create_langchain_agent(user_id: str):
    # Create session
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Create MCP client
    mcp_client = MultiServerMCPClient({
        "composio": {
            "transport": "streamable_http",
            "url": session.mcp.url,
            "headers": session.mcp.headers
        }
    })

    # Get tools
    tools = await mcp_client.get_tools()

    # Create agent
    agent = create_agent(
        tools=tools,
        model=ChatOpenAI(model="gpt-4o")
    )

    return agent

agent = await create_langchain_agent("user_123")
result = await agent.ainvoke({
    "messages": [
        {"role": "user", "content": "Fetch my last email"}
    ]
})
print(result)

Correct - Claude Agent SDK (Native Tools)

// DO: Use Claude Agent SDK with native tools
import { query } from '@anthropic-ai/claude-agent-sdk';
import { Composio } from '@composio/core';
import { ClaudeAgentSDKProvider } from '@composio/claude-agent-sdk';

const composio = new Composio({
  provider: new ClaudeAgentSDKProvider()
});

async function runClaudeAgent(userId: string, prompt: string) {
  // Create session with native tools
  const session = await composio.create(userId, {
    toolkits: ['gmail']
  });

  // Get native Claude tools format
  const tools = await session.tools();

  // Query with tools
  const stream = await query({
    prompt,
    options: {
      model: 'claude-sonnet-4-5-20250929',
      permissionMode: 'bypassPermissions',
      tools
    }
  });

  for await (const event of stream) {
    if (event.type === 'result' && event.subtype === 'success') {
      process.stdout.write(event.result);
    }
  }
}

await runClaudeAgent('user_123', 'Fetch my last email');
# DO: Use Claude Agent SDK with native tools
from composio import Composio
from composio_claude_agent_sdk import ClaudeAgentSDKProvider
from claude_agent_sdk import query, ClaudeAgentOptions

composio = Composio(provider=ClaudeAgentSDKProvider())

async def run_claude_agent(user_id: str, prompt: str):
    # Create session with native tools
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Get native Claude tools format
    tools = session.tools()

    # Query with tools
    options = ClaudeAgentOptions(
        model="claude-sonnet-4-5-20250929",
        permission_mode="bypassPermissions",
        tools=tools
    )

    async for message in query(prompt=prompt, options=options):
        print(message, end="")

await run_claude_agent("user_123", "Fetch my last email")

Correct - Claude Agent SDK (MCP)

// DO: Use Claude Agent SDK with MCP
import { query } from '@anthropic-ai/claude-agent-sdk';
import { Composio } from '@composio/core';

const composio = new Composio();

async function runClaudeAgentMCP(userId: string, prompt: string) {
  // Create session
  const session = await composio.create(userId, {
    toolkits: ['gmail']
  });

  // Query with MCP server
  const stream = await query({
    prompt,
    options: {
      model: 'claude-sonnet-4-5-20250929',
      permissionMode: 'bypassPermissions',
      mcpServers: {
        composio: {
          type: 'http',
          url: session.mcp.url,
          headers: session.mcp.headers
        }
      }
    }
  });

  for await (const event of stream) {
    if (event.type === 'result' && event.subtype === 'success') {
      process.stdout.write(event.result);
    }
  }
}

await runClaudeAgentMCP('user_123', 'Fetch my last email');
# DO: Use Claude Agent SDK with MCP
from composio import Composio
from claude_agent_sdk import query, ClaudeAgentOptions

composio = Composio()

async def run_claude_agent_mcp(user_id: str, prompt: str):
    # Create session
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Query with MCP server
    options = ClaudeAgentOptions(
        model="claude-sonnet-4-5-20250929",
        permission_mode="bypassPermissions",
        mcp_servers={
            "composio": {
                "type": session.mcp.type,
                "url": session.mcp.url,
                "headers": session.mcp.headers
            }
        }
    )

    async for message in query(prompt=prompt, options=options):
        print(message, end="")

await run_claude_agent_mcp("user_123", "Fetch my last email")

Correct - CrewAI (MCP)

# DO: Use CrewAI with MCP
from crewai import Agent, Task, Crew
from crewai.mcp import MCPServerHTTP
from composio import Composio

composio = Composio()

def create_crewai_agent(user_id: str):
    # Create session
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Create agent with MCP server
    agent = Agent(
        role="Gmail Assistant",
        goal="Help with Gmail related queries",
        backstory="You are a helpful assistant.",
        mcps=[
            MCPServerHTTP(
                url=session.mcp.url,
                headers=session.mcp.headers
            )
        ]
    )

    return agent

# Create agent
agent = create_crewai_agent("user_123")

# Define task
task = Task(
    description="Find the last email and summarize it.",
    expected_output="A summary including sender, subject, and key points.",
    agent=agent
)

# Execute
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
print(result)

Using Modifiers with Native Tools

// Add logging and telemetry with modifiers
import { Composio } from '@composio/core';
import { VercelProvider } from '@composio/vercel';
import { SessionExecuteMetaModifiers } from '@composio/core';

const composio = new Composio({
  provider: new VercelProvider()
});

async function getToolsWithLogging(userId: string) {
  const session = await composio.create(userId, {
    toolkits: ['gmail']
  });

  // Add modifiers for logging
  const modifiers: SessionExecuteMetaModifiers = {
    beforeExecute: ({ toolSlug, sessionId, params }) => {
      console.log(`[${sessionId}] Executing ${toolSlug}`);
      console.log('Parameters:', JSON.stringify(params, null, 2));
      return params;
    },
    afterExecute: ({ toolSlug, sessionId, result }) => {
      console.log(`[${sessionId}] Completed ${toolSlug}`);
      console.log('Success:', result.successful);
      return result;
    }
  };

  // Get tools with modifiers
  const tools = await session.tools(modifiers);

  return tools;
}
# Add logging and telemetry with modifiers
from composio import Composio, before_execute, after_execute
from composio_openai_agents import OpenAIAgentsProvider
from composio.types import ToolExecuteParams, ToolExecutionResponse

composio = Composio(provider=OpenAIAgentsProvider())

async def get_tools_with_logging(user_id: str):
    session = composio.create(user_id=user_id, toolkits=["gmail"])

    # Define logging modifiers
    @before_execute(tools=[])
    def log_before(
        tool: str,
        toolkit: str,
        params: ToolExecuteParams
    ) -> ToolExecuteParams:
        print(f"🔧 Executing {toolkit}.{tool}")
        print(f"   Arguments: {params.get('arguments', {})}")
        return params

    @after_execute(tools=[])
    def log_after(
        tool: str,
        toolkit: str,
        response: ToolExecutionResponse
    ) -> ToolExecutionResponse:
        print(f"✅ Completed {toolkit}.{tool}")
        if "data" in response:
            print(f"   Response: {response['data']}")
        return response

    # Get tools with modifiers
    tools = session.tools(modifiers=[log_before, log_after])

    return tools

Framework Comparison

Framework Native Tools MCP Provider Package Best For
Vercel AI SDK @composio/vercel Modern web apps, streaming
OpenAI Agents SDK @composio/openai-agents Production agents
LangChain N/A (MCP only) Complex chains, memory
Claude Agent SDK @composio/claude-agent-sdk Claude-specific features
CrewAI N/A (MCP only) Multi-agent teams

Pattern: Framework Switching

// Same session, different frameworks
const composio = new Composio();
const session = await composio.create('user_123', { toolkits: ['gmail'] });

// Use with Vercel AI SDK
const client1 = await createMCPClient({
  transport: { type: 'http', url: session.mcp.url, headers: session.mcp.headers }
});

// Use with LangChain
const client2 = new MultiServerMCPClient({
  composio: { transport: 'http', url: session.mcp.url, headers: session.mcp.headers }
});

// Use with OpenAI Agents
const client3 = hostedMcpTool({
  serverUrl: session.mcp.url,
  headers: session.mcp.headers
});

// ✅ Same tools, different frameworks
// ✅ Framework flexibility with MCP

Best Practices

1. Choose Native Tools When Available

  • Faster execution (no MCP overhead)
  • Better performance for production
  • Full control with modifiers

2. Use MCP for Flexibility

  • When using multiple frameworks
  • During prototyping phase
  • When native tools unavailable

3. Always Create User Sessions

  • Never share sessions across users
  • Use proper user IDs (not 'default')
  • Isolate tools per user

4. Enable Connection Management

  • Set manageConnections: true
  • Let agent handle authentication
  • Better user experience

5. Add Logging with Modifiers

  • Use beforeExecute/afterExecute
  • Track tool execution
  • Debug agent behavior

6. Handle Streaming Properly

  • Use framework's streaming APIs
  • Process events as they arrive
  • Better UX for long operations

Key Principles

  1. Native tools recommended - Faster and more control
  2. MCP for flexibility - Framework independent
  3. User isolation - Create sessions per user
  4. Connection management - Enable auto-authentication
  5. Logging and monitoring - Use modifiers for observability
  6. Framework agnostic - Same session works with any framework

Reference