Skip to main content
Core integrations allow you to connect external services to your knowledge graph, automatically sync activities, and expose MCP (Model Context Protocol) tools to AI agents. This guide will help you build your own integration.

Overview

Core integrations serve three main purposes:
  1. Activity Sync - Automatically capture relevant activities from external services into your knowledge graph
  2. Real-time Updates - Receive webhook events for instant synchronization
  3. MCP Tools - Expose service-specific tools to AI agents through the MCP Hub

Integration Architecture

Every Core integration consists of:
  • spec.json - Defines integration metadata, authentication, and MCP configuration
  • index.ts - Main entry point that handles different event types
  • account-create.ts - Handles OAuth flow completion and account setup
  • Event handlers - Process webhooks (webhook-based) or scheduled syncs (schedule-based)

Integration Types

Core supports two primary integration patterns:

1. Webhook-Based Integrations

Best for: Real-time events, chat platforms, collaboration tools Webhook-based integrations receive HTTP callbacks from the external service whenever events occur. This provides instant synchronization with minimal latency. Example: Slack
  • Receives webhook events for messages, reactions, mentions
  • Processes events in real-time as they happen
  • Uses PROCESS and IDENTIFY event types

2. Schedule-Based Sync Integrations

Best for: Services without webhooks, APIs with rate limits, batch processing Schedule-based integrations run on a cron schedule to poll the external API and fetch new activities. This is ideal for services that don’t support webhooks or when you want to batch process data. Example: GitHub
  • Runs every 5-15 minutes (configurable)
  • Fetches notifications, PRs, issues, and comments
  • Maintains state to track last sync time
  • Uses SYNC event type

Integration Components

spec.json

The specification file defines your integration’s core configuration:
{
  "name": "Service Name",
  "key": "service-key",
  "description": "What your integration does",
  "icon": "icon-name",

  // For schedule-based integrations
  "schedule": {
    "frequency": "*/5 * * * *"  // Cron expression
  },

  // OAuth configuration
  "auth": {
    "OAuth2": {
      "token_url": "https://api.service.com/oauth/token",
      "authorization_url": "https://api.service.com/oauth/authorize",
      "scopes": ["read", "write"],
      "scope_separator": ","
    }
  },

  // MCP Hub configuration
  "mcp": {
    "type": "http",  // or "stdio"
    "url": "https://api.service.com/mcp/",
    "headers": {
      "Authorization": "Bearer ${config:access_token}"
    }
  }
}

index.ts

The main entry point routes events to appropriate handlers:
import { IntegrationCLI, IntegrationEventPayload, IntegrationEventType } from '@redplanethq/sdk';

export async function run(eventPayload: IntegrationEventPayload) {
  switch (eventPayload.event) {
    case IntegrationEventType.SETUP:
      // Handle OAuth completion and account creation
      return await integrationCreate(eventPayload.eventBody);

    case IntegrationEventType.SYNC:
      // For schedule-based integrations
      return await handleSchedule(eventPayload.config, eventPayload.state);

    case IntegrationEventType.PROCESS:
      // For webhook-based integrations
      return await createActivityEvent(eventPayload.eventBody.eventData, eventPayload.config);

    case IntegrationEventType.IDENTIFY:
      // Extract user identifier from webhook event
      return [{ type: 'identifier', data: eventPayload.eventBody.event.user }];

    default:
      return { message: `Unknown event type: ${eventPayload.event}` };
  }
}

class YourIntegrationCLI extends IntegrationCLI {
  constructor() {
    super('your-service', '1.0.0');
  }

  protected async handleEvent(eventPayload: IntegrationEventPayload): Promise<any> {
    return await run(eventPayload);
  }

  protected async getSpec(): Promise<Spec> {
    // Return spec.json content
  }
}

Event Types

SETUP

Called when a user completes OAuth authorization. Create the integration account and return configuration. Returns:
[{
  type: 'account',
  data: {
    accountId: 'user-123',
    config: {
      access_token: 'token',
      refresh_token: 'refresh',
      mcp: { tokens: { access_token: 'token' } }
    },
    settings: {
      username: 'user',
      schedule: { frequency: '*/15 * * * *' }
    }
  }
}]

SYNC (Schedule-Based)

Called on cron schedule. Fetch activities since last sync and return them. Returns:
[
  {
    type: 'activity',
    data: {
      text: 'User created PR #123: Add new feature',
      sourceURL: 'https://github.com/org/repo/pull/123'
    }
  },
  {
    type: 'state',
    data: {
      lastSyncTime: '2025-01-01T00:00:00Z',
      // ... other state to persist
    }
  }
]

PROCESS (Webhook-Based)

Called when webhook event is received. Process the event and return activities. Returns:
[{
  type: 'activity',
  data: {
    text: 'User mentioned you in #channel: Hello @user',
    sourceURL: 'https://slack.com/archives/C123/p456'
  }
}]

IDENTIFY (Webhook-Based)

Extract user identifier from webhook event for routing. Returns:
[{
  type: 'identifier',
  data: 'user-id-from-event'
}]

MCP Hub Integration

The MCP Hub allows your integration to expose tools that AI agents can use. Configure this in spec.json:

HTTP-based MCP

For services with existing MCP servers:
{
  "mcp": {
    "type": "http",
    "url": "https://api.githubcopilot.com/mcp/",
    "headers": {
      "Authorization": "Bearer ${config:access_token}",
      "Content-Type": "application/json"
    }
  }
}

Stdio-based MCP

For local command-line MCP servers:
{
  "mcp": {
    "type": "stdio",
    "url": "https://integrations.heysol.ai/slack/mcp/slack-mcp-server",
    "args": [],
    "env": {
      "SLACK_MCP_XOXP_TOKEN": "${config:access_token}",
      "SLACK_MCP_ADD_MESSAGE_TOOL": true
    }
  }
}
The ${config:access_token} placeholder will be replaced with the user’s OAuth access token at runtime.

Best Practices

Activity Messages

  1. Be Descriptive - Include who, what, where, and context
  2. Include URLs - Always provide sourceURL for deep linking
  3. Use Consistent Format - Follow patterns from existing integrations
  4. Filter Noise - Only sync relevant activities (e.g., mentions, assignments)

State Management

For schedule-based integrations:
  1. Track Sync Time - Always save lastSyncTime in state
  2. Default to 24 Hours - On first sync, fetch last 24 hours of data
  3. Use Pagination - Handle large datasets with proper pagination
  4. Error Handling - Continue processing even if individual items fail

Error Handling

  1. Silent Failures - Don’t pollute stdout with errors (return empty arrays)
  2. Graceful Degradation - Continue processing other items if one fails
  3. Validate Tokens - Check for access_token presence early
  4. Return Empty Arrays - On fatal errors, return [] instead of throwing

OAuth Configuration

  1. Request Minimal Scopes - Only ask for permissions you need
  2. Store Refresh Tokens - Enable long-term access
  3. Pass to MCP - Include access_token in mcp config for tool usage

Testing Your Integration

  1. Local Development - Use the SDK CLI to test event handling
  2. OAuth Flow - Test complete authorization flow
  3. Sync/Webhook - Verify activities are created correctly
  4. MCP Tools - Test tool exposure and authentication
  5. Error Cases - Test with invalid tokens, network failures, etc.

Project Structure

integrations/your-service/
├── spec.json                 # Integration specification
├── package.json             # Dependencies
├── tsconfig.json            # TypeScript config
├── tsup.config.ts           # Build configuration
├── src/
│   ├── index.ts             # Main entry point
│   ├── account-create.ts    # OAuth completion handler
│   ├── schedule.ts          # (Schedule-based) Sync handler
│   ├── create-activity.ts   # (Webhook-based) Event processor
│   └── utils.ts             # Helper functions
└── README.md                # Integration documentation

Next Steps

Contributing

We welcome community contributions! To submit your integration:
  1. Fork the Core repository
  2. Create your integration in integrations/your-service/
  3. Follow the patterns from GitHub/Slack examples
  4. Test thoroughly
  5. Submit a pull request
Your integration will be reviewed and added to the Core integration marketplace!