Skip to content

composio #653

@ngoiyaeric

Description

@ngoiyaeric

Improve Composio Integration

The current Composio integration has a hybrid implementation where lib/agents/tools/geospatial.tsx uses a direct MCP client approach instead of the proper Composio SDK methods defined in mapbox_mcp/composio-mapbox.ts. 1

Current Issues

Mixed Implementation Approaches

The codebase uses two different methods to connect to Composio:

  • Proper SDK approach: mapbox_mcp/composio-mapbox.ts uses authenticateToolkit() and initializeComposioMapbox() with the Composio SDK 2
  • Manual MCP approach: lib/agents/tools/geospatial.tsx manually constructs URLs and uses MCP client transport 3

Security and Maintainability Concerns

The manual URL construction in geospatial.tsx bypasses the proper Composio SDK authentication flow, which is acknowledged as needing migration 1 .

Recommended Improvements

1. Migrate geospatial.tsx to Use Composio SDK

Replace the getConnectedMcpClient() function in lib/agents/tools/geospatial.tsx with calls to the proper Composio SDK methods:

// Replace getConnectedMcpClient() with:
import { initializeComposioMapbox, getComposioClient } from '@/mapbox_mcp/composio-mapbox';

async function getComposioConnection() {
  const { connectionId, composio } = await initializeComposioMapbox();
  return { connectionId, composio };
}

2. Update Tool Execution Logic

Replace the MCP client tool calls with Composio SDK executeAction calls:

// Current approach (lines 361-377):
const result = await client.callTool(toolName, args);

// New approach:
const result = await composio.executeAction({
  action: toolName, // e.g., 'mapbox_geocode_location'
  params: args,
  connectedAccountId: connectionId,
});

3. Standardize Environment Variable Usage

Ensure consistent environment variable validation by using the validateEnvironmentVariables() function from composio-mapbox.ts 4 instead of the manual checks in geospatial.tsx 5 .

4. Remove Redundant Configuration

The mapbox_mcp_config.json file is loaded but not fully utilized in the current implementation 6 . After migrating to the SDK, this file can be removed or simplified since the SDK handles configuration internally.

5. Improve Error Handling

Implement consistent error handling using the patterns from composio-mapbox.ts 7 and the hooks file 8 .

Implementation Priority

  1. High Priority: Migrate getConnectedMcpClient() to use initializeComposioMapbox()
  2. High Priority: Replace MCP client calls with Composio SDK executeAction()
  3. Medium Priority: Standardize environment variable validation
  4. Low Priority: Clean up redundant configuration files

Notes

The migration guide in COMPOSIO_MIGRATION.md 9 provides additional context for the migration from Smithery to Composio, but the current issue is about completing the migration within the Composio implementation itself. The security warnings in mapbox_mcp/README.md 10 highlight the importance of proper server-side authentication, which the SDK approach provides.

Wiki pages you might want to explore:

Citations

File: lib/agents/tools/geospatial.tsx (L40-53)

  const composioApiKey = process.env.COMPOSIO_API_KEY;
  const mapboxAccessToken = process.env.MAPBOX_ACCESS_TOKEN;
  const composioUserId = process.env.COMPOSIO_USER_ID;

  console.log('[GeospatialTool] Environment check:', {
    composioApiKey: composioApiKey ? `${composioApiKey.substring(0, 8)}...` : 'MISSING',
    mapboxAccessToken: mapboxAccessToken ? `${mapboxAccessToken.substring(0, 8)}...` : 'MISSING',
    composioUserId: composioUserId ? `${composioUserId.substring(0, 8)}...` : 'MISSING',
  });

  if (!composioApiKey || !mapboxAccessToken || !composioUserId || !composioApiKey.trim() || !mapboxAccessToken.trim() || !composioUserId.trim()) {
    console.error('[GeospatialTool] Missing or empty required environment variables');
    return null;
  }

File: lib/agents/tools/geospatial.tsx (L55-71)

  // Load config from file or fallback
  let config;
  try {
    // Use static import for config
    let mapboxMcpConfig;
    try {
      mapboxMcpConfig = require('../../../mapbox_mcp_config.json');
      config = { ...mapboxMcpConfig, mapboxAccessToken };
      console.log('[GeospatialTool] Config loaded successfully');
    } catch (configError: any) {
      throw configError;
    }
  } catch (configError: any) {
    console.error('[GeospatialTool] Failed to load mapbox config:', configError.message);
    config = { mapboxAccessToken, version: '1.0.0', name: 'mapbox-mcp-server' };
    console.log('[GeospatialTool] Using fallback config');
  }

File: lib/agents/tools/geospatial.tsx (L73-103)

  // Build Composio MCP server URL
  // Note: This should be migrated to use Composio SDK directly instead of MCP client
  // For now, constructing URL directly without Smithery SDK
  let serverUrlToUse: URL;
  try {
    // Construct URL with Composio credentials
    const baseUrl = 'https://api.composio.dev/v1/mcp/mapbox';
    serverUrlToUse = new URL(baseUrl);
    serverUrlToUse.searchParams.set('api_key', composioApiKey);
    serverUrlToUse.searchParams.set('user_id', composioUserId);
    
    const urlDisplay = serverUrlToUse.toString().split('?')[0];
    console.log('[GeospatialTool] Composio MCP Server URL created:', urlDisplay);

    if (!serverUrlToUse.href || !serverUrlToUse.href.startsWith('https://')) {
      throw new Error('Invalid server URL generated');
    }
  } catch (urlError: any) {
    console.error('[GeospatialTool] Error creating Composio URL:', urlError.message);
    return null;
  }

  // Create transport
  let transport;
  try {
    transport = new StreamableHTTPClientTransport(serverUrlToUse);
    console.log('[GeospatialTool] Transport created successfully');
  } catch (transportError: any) {
    console.error('[GeospatialTool] Failed to create transport:', transportError.message);
    return null;
  }

File: mapbox_mcp/composio-mapbox.ts (L8-48)

function validateEnvironmentVariables(): {
  authConfigId: string;
  userId: string;
  mapboxToken: string;
  apiKey: string;
} {
  const authConfigId = process.env.COMPOSIO_MAPBOX_AUTH_CONFIG_ID;
  const userId = process.env.COMPOSIO_USER_ID;
  const mapboxToken = process.env.MAPBOX_ACCESS_TOKEN;
  const apiKey = process.env.COMPOSIO_API_KEY;

  if (!authConfigId) {
    throw new Error(
      'COMPOSIO_MAPBOX_AUTH_CONFIG_ID environment variable is required. ' +
      'Please set it in your .env.local file.'
    );
  }

  if (!userId) {
    throw new Error(
      'COMPOSIO_USER_ID environment variable is required. ' +
      'Please set it in your .env.local file.'
    );
  }

  if (!mapboxToken) {
    throw new Error(
      'MAPBOX_ACCESS_TOKEN environment variable is required. ' +
      'Please set it in your .env.local file.'
    );
  }

  if (!apiKey) {
    throw new Error(
      'COMPOSIO_API_KEY environment variable is required. ' +
      'Please set it in your .env.local file.'
    );
  }

  return { authConfigId, userId, mapboxToken, apiKey };
}

File: mapbox_mcp/composio-mapbox.ts (L59-115)

export async function authenticateToolkit(
  userId: string,
  authConfigId: string,
  mapboxApiKey: string,
  composioApiKey: string
): Promise<string> {
  if (!userId || !authConfigId || !mapboxApiKey || !composioApiKey) {
    throw new Error(
      'userId, authConfigId, mapboxApiKey, and composioApiKey are required for authentication'
    );
  }

  // Initialize Composio with API key
  const composio = new Composio({ apiKey: composioApiKey });

  const connectionRequest = await composio.connectedAccounts.initiate(
    userId,
    authConfigId,
    {
      config: AuthScheme.APIKey({
        api_key: mapboxApiKey
      })
    }
  );
  
  // API Key authentication is immediate - no redirect needed
  console.log(`Successfully connected Mapbox for user ${userId}`);
  console.log(`Connection status: ${connectionRequest.status}`);
  
  return connectionRequest.id;
}

/**
 * Initialize Composio connection for Mapbox
 * This should only be called server-side to avoid exposing API keys
 * @throws Error if environment variables are missing or connection fails
 */
export async function initializeComposioMapbox() {
  const { authConfigId, userId, mapboxToken, apiKey } = validateEnvironmentVariables();

  try {
    // Authenticate the toolkit
    const connectionId = await authenticateToolkit(userId, authConfigId, mapboxToken, apiKey);
    
    // Initialize Composio client with API key for subsequent operations
    const composio = new Composio({ apiKey });
    
    // Verify the connection
    const connectedAccount = await composio.connectedAccounts.get(connectionId);
    console.log("Connected account:", connectedAccount);
    
    return { connectionId, connectedAccount, composio };
  } catch (error) {
    console.error("Failed to initialize Composio Mapbox connection:", error);
    throw error;
  }
}

File: mapbox_mcp/hooks.ts (L96-100)

    } catch (err) {
      const errorMessage = `Failed to connect to Composio Mapbox: ${err}`;
      setError(errorMessage);
      console.error('❌ Composio connection error:', err);
      throw new Error(errorMessage);

File: COMPOSIO_MIGRATION.md (L1-253)

# Migration Guide: Smithery to Composio

This document outlines the migration from Smithery to Composio for the Mapbox integration in QCX.

## Overview

The QCX project has migrated from using Smithery's MCP server hosting to Composio's integration platform for Mapbox functionality. This change provides better scalability, more robust authentication, and improved tool management.

## What Changed

### 1. Dependencies

**Removed:**
- `@smithery/cli` (^1.2.5)
- `@smithery/sdk` (^1.0.4)
- `smithery` (^0.5.2)

**Added:**
- `@composio/core` (^0.5.0)

### 2. Environment Variables

**Old (Smithery):**
```bash
SMITHERY_PROFILE_ID="your_smithery_profile_id_here"
SMITHERY_API_KEY="your_smithery_api_key_here"
NEXT_PUBLIC_SMITHERY_PROFILE_ID="your_smithery_profile_id_here"
NEXT_PUBLIC_SMITHERY_API_KEY="your_smithery_api_key_here"

New (Composio):

COMPOSIO_MAPBOX_AUTH_CONFIG_ID="ac_YOUR_MAPBOX_CONFIG_ID"
COMPOSIO_USER_ID="user@example.com"
MAPBOX_ACCESS_TOKEN="your_mapbox_api_key"
NEXT_PUBLIC_COMPOSIO_MAPBOX_AUTH_CONFIG_ID="ac_YOUR_MAPBOX_CONFIG_ID"
NEXT_PUBLIC_COMPOSIO_USER_ID="user@example.com"

3. Configuration Files

mapbox_mcp_config.json

Old:

{
  "mcpServers": {
    "mapbox-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@smithery/cli@latest",
        "run",
        "@ngoiyaeric/mapbox-mcp-server",
        "--key",
        "705b0222-a657-4cd2-b180-80c406cf6179",
        "--profile",
        "smooth-lemur-vfUbUE"
      ]
    }
  }
}

New:

{
  "composio": {
    "mapbox": {
      "authConfigId": "ac_YOUR_MAPBOX_CONFIG_ID",
      "userId": "user@example.com",
      "description": "Composio configuration for Mapbox integration"
    }
  }
}

4. Code Changes

mapbox_mcp/hooks.ts

Old Connection Method:

const mcp = useMcp({
  url: `https://server.smithery.ai/@Waldzell-Agentics/mcp-server/mcp?profile=${process.env.NEXT_PUBLIC_SMITHERY_PROFILE_ID}&api_key=${process.env.NEXT_PUBLIC_SMITHERY_API_KEY}`,
  debug: process.env.NODE_ENV === 'development',
  autoReconnect: true,
  autoRetry: 5000,
});

New Connection Method:

const composioClient = getComposioClient();
const { connectionId, connectedAccount } = await initializeComposioMapbox();

Tool Execution

Old:

const result = await mcp.callTool('geocode_location', {
  query: address,
  includeMapPreview: true,
});

New:

const result = await composioClient.executeAction({
  action: 'mapbox_geocode_location',
  params: {
    query: address,
    includeMapPreview: true,
  },
  connectedAccountId: connectionId,
});

Migration Steps

Step 1: Install Composio

bun install @composio/core

Step 2: Remove Smithery Dependencies

bun remove @smithery/cli @smithery/sdk smithery

Step 3: Set Up Composio Account

  1. Sign up at https://composio.dev
  2. Create a new auth config for Mapbox
  3. Select "API Key" as the authentication method
  4. Note your auth config ID (starts with ac_)

Step 4: Update Environment Variables

  1. Copy .env.local.example to .env.local (if not already done)
  2. Replace Smithery variables with Composio variables:
    COMPOSIO_MAPBOX_AUTH_CONFIG_ID="ac_YOUR_ACTUAL_CONFIG_ID"
    COMPOSIO_USER_ID="your_email@example.com"
    MAPBOX_ACCESS_TOKEN="your_mapbox_token"

Step 5: Update Code References

The following files have been updated automatically:

  • mapbox_mcp/composio-mapbox.ts (new file)
  • mapbox_mcp/hooks.ts (updated)
  • mapbox_mcp/index.ts (updated)
  • mapbox_mcp_config.json (updated)
  • package.json (updated)
  • .env.local.example (updated)

Step 6: Test the Integration

# Test the connection
bun run mapbox_mcp/index.ts

# Run the development server
bun run dev

API Compatibility

The useMCPMapClient hook maintains the same interface, so existing components using it should continue to work without changes:

const {
  isConnected,
  isLoading,
  error,
  connect,
  disconnect,
  processLocationQuery,
  geocodeLocation,
  calculateDistance,
  searchNearbyPlaces,
} = useMCPMapClient();

Troubleshooting

Issue: "Composio client not connected"

Solution: Ensure you've called connect() before using any tool functions:

useEffect(() => {
  connect();
}, [connect]);

Issue: "Invalid auth config ID"

Solution: Verify your COMPOSIO_MAPBOX_AUTH_CONFIG_ID starts with ac_ and is copied correctly from the Composio dashboard.

Issue: "Mapbox API key invalid"

Solution: Check that your MAPBOX_ACCESS_TOKEN is valid and has the necessary scopes enabled in your Mapbox account.

Issue: Tool execution fails

Solution: Verify the action names match Composio's Mapbox integration. Common actions:

  • mapbox_geocode_location
  • mapbox_calculate_distance
  • mapbox_search_nearby_places
  • mapbox_generate_map_link

Benefits of Composio

  1. Better Authentication Management: Centralized auth config management
  2. Improved Security: API keys stored securely in Composio
  3. Scalability: Better handling of multiple integrations
  4. Monitoring: Built-in logging and monitoring in Composio dashboard
  5. Flexibility: Easier to add new tools and integrations

Resources

Support

If you encounter issues during migration:

  1. Check the Composio dashboard for connection status
  2. Review the logs in your development console
  3. Consult the mapbox_mcp/README.md file
  4. Open an issue in the QCX repository

Rollback

If you need to rollback to Smithery:

# Reinstall Smithery packages
bun install @smithery/cli@^1.2.5 @smithery/sdk@^1.0.4 smithery@^0.5.2

# Restore old environment variables in .env.local
# Restore old code from git history
git checkout HEAD~1 -- mapbox_mcp/

However, we recommend staying with Composio for the improved features and maintainability.


**File:** mapbox_mcp/README.md (L9-16)
```markdown
## ⚠️ Security Warning

**IMPORTANT**: The Composio integration requires server-side environment variables (`MAPBOX_ACCESS_TOKEN`) that should **NEVER** be exposed to the client. 

- The `useMCPMapClient` hook should **NOT** be used directly in client components
- Instead, create server-side API routes that handle Composio authentication and tool execution
- Only expose necessary data to the client through your API routes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions