Skip to main content

Plugin Class

Every OpenTabs plugin is a subclass of OpenTabsPlugin. This is the one class you need to extend — it holds everything the platform needs to discover, inject, and run your plugin: identity, URL patterns, readiness probe, and tool list. All in one place.

Import

import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';

Class Signature

abstract class OpenTabsPlugin {
  abstract readonly name: string;
  abstract readonly displayName: string;
  abstract readonly description: string;
  abstract readonly urlPatterns: string[];
  readonly excludePatterns?: string[];
  readonly homepage?: string;
  abstract readonly tools: ToolDefinition[];
 
  abstract isReady(): Promise<boolean>;
  teardown?(): void;
 
  // Lifecycle hooks (optional)
  onActivate?(): void;
  onDeactivate?(): void;
  onNavigate?(url: string): void;
  onToolInvocationStart?(toolName: string): void;
  onToolInvocationEnd?(toolName: string, success: boolean, durationMs: number): void;
}

Abstract Properties

These properties are required — your subclass must define them.

PropertyTypeDescription
namestringUnique identifier. Lowercase alphanumeric with hyphens (e.g., 'my-app'). Used as the tool name prefix and config key.
descriptionstringBrief description of the plugin's purpose. Shown to MCP clients.
displayNamestringHuman-readable name shown in the side panel and health endpoint (e.g., 'My App').
urlPatternsstring[]Chrome match patterns. Determines which tabs receive the adapter injection. Example: ['*://*.slack.com/*'].
toolsToolDefinition[]Array of tool definitions. See Tools.

Optional Properties

These properties are optional — override them when your plugin needs URL exclusions or a homepage link.

PropertyTypeDescription
excludePatternsstring[]Chrome match patterns for URLs that should not match this plugin. Tabs matching both urlPatterns and excludePatterns are excluded. Useful when a broad urlPattern overlaps with another plugin's domain.
homepagestringURL to open when no matching tab exists and the user triggers an "open tab" action from the side panel. Should be a concrete URL (e.g., 'https://github.com'), not a match pattern.

Example — excluding URLs:

class MyPlugin extends OpenTabsPlugin {
  readonly urlPatterns = ['*://*.example.com/*'];
  readonly excludePatterns = ['*://docs.example.com/*'];
  // ...
}

Example — setting a homepage:

class MyPlugin extends OpenTabsPlugin {
  readonly urlPatterns = ['*://*.github.com/*'];
  readonly homepage = 'https://github.com';
  // ...
}

Abstract Methods

isReady()

Readiness probe called by the extension to determine if the current tab is ready to accept tool requests. Runs in the page context.

abstract isReady(): Promise<boolean>;

Return true when the user is authenticated and the page is operational. Return false when the page is loading, logged out, or in an error state.

The return value maps to the tab state machine:

ConditionTab State
No matching tab existsclosed
Tab exists, isReady() returns falseunavailable
Tab exists, isReady() returns trueready

Example:

async isReady(): Promise<boolean> {
  // Check for an auth token that the app stores on login
  const token = getPageGlobal('__APP__.authToken') as string | undefined;
  return token !== undefined;
}

teardown()

Optional cleanup method called before re-injection on plugin updates. Remove any event listeners, timers, or global state set up by the previous adapter version.

teardown?(): void;

Plugins that don't set up persistent side effects can omit this.

Lifecycle Hooks

All lifecycle hooks are optional. They run in the page context and are wired automatically by the build process. Errors in hooks are caught and logged — they never affect adapter registration or tool execution.

See Lifecycle Hooks for the complete reference.

Example

import { OpenTabsPlugin, getPageGlobal } from '@opentabs-dev/plugin-sdk';
import type { ToolDefinition } from '@opentabs-dev/plugin-sdk';
 
import { listChannels } from './tools/list-channels.js';
import { sendMessage } from './tools/send-message.js';
 
class SlackPlugin extends OpenTabsPlugin {
  readonly name = 'slack';
  readonly description = 'Interact with Slack through the browser';
  override readonly displayName = 'Slack';
  readonly urlPatterns = ['*://*.slack.com/*'];
  readonly tools: ToolDefinition[] = [listChannels, sendMessage];
 
  async isReady(): Promise<boolean> {
    const token = getPageGlobal('TS.boot_data.api_token') as string | undefined;
    return token !== undefined;
  }
}
 
export default new SlackPlugin();

Last Updated: 10 Mar, 2026