Custom Plugins
Create your own plugins for any service
Creating Custom Plugins
The Integrate SDK's plugin system is extensible, allowing you to create custom plugins for any service supported by the MCP server.
Using the Generic OAuth Plugin
The easiest way to create a plugin is using the genericOAuthPlugin helper:
import { createMCPClient, genericOAuthPlugin } from "integrate-sdk";
const slackPlugin = genericOAuthPlugin({
id: "slack",
provider: "slack",
clientId: process.env.SLACK_CLIENT_ID!,
clientSecret: process.env.SLACK_CLIENT_SECRET!,
scopes: ["chat:write", "channels:read", "users:read"],
tools: [
"slack_send_message",
"slack_list_channels",
"slack_get_channel",
"slack_invite_user",
],
redirectUri: "https://your-app.com/callback",
});
const client = createMCPClient({
plugins: [slackPlugin],
});Generic OAuth Plugin Options
| Option | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique plugin identifier |
provider | string | Yes | OAuth provider name (e.g., 'slack', 'notion') |
clientId | string | Yes | OAuth client ID |
clientSecret | string | Yes | OAuth client secret |
scopes | string[] | Yes | OAuth scopes |
tools | string[] | Yes | Tool names to enable |
redirectUri | string | No | OAuth redirect URI |
Creating a Simple Plugin (No OAuth)
For tools that don't require OAuth, use createSimplePlugin:
import { createSimplePlugin } from "integrate-sdk";
const mathPlugin = createSimplePlugin({
id: "math",
tools: ["math_add", "math_subtract", "math_multiply", "math_divide"],
onInit: async (client) => {
console.log("Math plugin initialized");
},
});
const client = createMCPClient({
plugins: [mathPlugin],
});Creating a Custom Plugin from Scratch
For more control, implement the MCPPlugin interface:
import type { MCPPlugin } from "integrate-sdk";
interface NotionPluginConfig {
clientId: string;
clientSecret: string;
scopes?: string[];
}
export function notionPlugin(config: NotionPluginConfig): MCPPlugin {
return {
id: "notion",
tools: [
"notion_search",
"notion_create_page",
"notion_update_page",
"notion_query_database",
],
oauth: {
provider: "notion",
clientId: config.clientId,
clientSecret: config.clientSecret,
scopes: config.scopes || ["read_content", "update_content"],
},
async onInit(client) {
console.log("Notion plugin initialized");
},
async onBeforeConnect(client) {
console.log("Notion plugin: preparing to connect");
},
async onAfterConnect(client) {
console.log("Notion plugin: connected successfully");
// You can call tools here if needed
const tools = client.getEnabledTools();
console.log("Notion tools available:", tools.length);
},
async onDisconnect(client) {
console.log("Notion plugin: disconnected");
},
};
}Plugin Interface
interface MCPPlugin {
id: string; // Unique identifier
tools: string[]; // Tool names to enable
oauth?: OAuthConfig; // OAuth configuration (optional)
onInit?: PluginHook; // Called when plugin is created
onBeforeConnect?: PluginHook; // Called before connecting
onAfterConnect?: PluginHook; // Called after connecting
onDisconnect?: PluginHook; // Called on disconnect
}
interface OAuthConfig {
provider: string; // OAuth provider name
clientId: string; // Client ID
clientSecret: string; // Client secret
scopes: string[]; // OAuth scopes
redirectUri?: string; // Redirect URI (optional)
}
type PluginHook = (client: MCPClient) => Promise<void> | void;Lifecycle Hooks
Plugins support four lifecycle hooks:
onInit
Called when the plugin is created (during createMCPClient):
async onInit(client) {
// Initialize plugin state
console.log('Plugin initialized');
}onBeforeConnect
Called before establishing the connection to the MCP server:
async onBeforeConnect(client) {
// Prepare for connection
console.log('About to connect');
}onAfterConnect
Called after successfully connecting to the MCP server:
async onAfterConnect(client) {
// Verify tools are available
const tools = client.getEnabledTools();
console.log('Tools available:', tools.length);
}onDisconnect
Called when disconnecting from the server:
async onDisconnect(client) {
// Cleanup
console.log('Disconnected');
}Example: Slack Plugin
Here's a complete example of a Slack plugin:
import { genericOAuthPlugin } from "integrate-sdk";
export const slackPlugin = (config: {
clientId: string;
clientSecret: string;
scopes?: string[];
}) =>
genericOAuthPlugin({
id: "slack",
provider: "slack",
clientId: config.clientId,
clientSecret: config.clientSecret,
scopes: config.scopes || [
"chat:write",
"channels:read",
"channels:manage",
"users:read",
],
tools: [
"slack_send_message",
"slack_list_channels",
"slack_get_channel",
"slack_create_channel",
"slack_invite_user",
"slack_list_users",
],
});
// Usage
const client = createMCPClient({
plugins: [
slackPlugin({
clientId: process.env.SLACK_CLIENT_ID!,
clientSecret: process.env.SLACK_CLIENT_SECRET!,
}),
],
});Example: Notion Plugin
import type { MCPPlugin } from "integrate-sdk";
interface NotionConfig {
clientId: string;
clientSecret: string;
scopes?: string[];
}
export function notionPlugin(config: NotionConfig): MCPPlugin {
return {
id: "notion",
tools: [
"notion_search",
"notion_create_page",
"notion_update_page",
"notion_get_page",
"notion_query_database",
"notion_create_database",
],
oauth: {
provider: "notion",
clientId: config.clientId,
clientSecret: config.clientSecret,
scopes: config.scopes || ["read_content", "update_content"],
},
};
}
// Usage
const client = createMCPClient({
plugins: [
notionPlugin({
clientId: process.env.NOTION_CLIENT_ID!,
clientSecret: process.env.NOTION_CLIENT_SECRET!,
}),
],
});Discovering Available Tools
Before creating a plugin, you might want to see what tools are available on the MCP server:
// Create client without filters to see all tools
const client = createMCPClient({
plugins: [],
});
await client.connect();
const allTools = client.getAvailableTools();
console.log("All available tools:");
allTools.forEach((tool) => {
console.log(`- ${tool.name}: ${tool.description}`);
});Best Practices
- Use meaningful IDs - Plugin IDs should be unique and descriptive
- Provide sensible defaults - Set default scopes for common use cases
- Document required scopes - Let users know what permissions are needed
- Handle errors gracefully - Use lifecycle hooks to validate configuration
- List all tools - Include all relevant tools in the
toolsarray - Test thoroughly - Verify tools work as expected
Next Steps
- See the Advanced Usage guide
- Learn about Vercel AI SDK Integration
- Check the API Reference