Basic Usage
import { Plugin, Provider, Token } from '@frontmcp/sdk';
// Provider for the plugin
@Provider()
class CacheService {
private cache = new Map<string, string>();
async get(key: string) {
return this.cache.get(key);
}
async set(key: string, value: string) {
this.cache.set(key, value);
}
}
export const CacheServiceToken = new Token<CacheService>('CacheService');
// Plugin definition
@Plugin({
name: 'cache',
description: 'In-memory caching for tools',
providers: [
{ provide: CacheServiceToken, useClass: CacheService },
],
})
export class CachePlugin {}
Signature
function Plugin(providedMetadata: PluginMetadata): ClassDecorator
Configuration Options
Required Properties
| Property | Type | Description |
|---|
name | string | Unique plugin identifier |
Optional Properties
| Property | Type | Description |
|---|
id | string | Stable identifier |
description | string | Plugin description |
scope | 'app' | 'server' | Plugin scope level |
Components
| Property | Type | Description |
|---|
providers | ProviderType[] | Plugin providers |
tools | ToolType[] | Plugin tools |
resources | ResourceType[] | Plugin resources |
prompts | PromptType[] | Plugin prompts |
skills | SkillType[] | Plugin skills |
adapters | AdapterType[] | Framework adapters |
plugins | PluginType[] | Nested plugins |
Extensions
| Property | Type | Description |
|---|
contextExtensions | ContextExtension[] | Add properties to context classes |
Context Extensions
Extend all context classes with custom properties:
import { Plugin, Provider, Token, ExecutionContextBase } from '@frontmcp/sdk';
// 1. Define token
export const RememberAccessorToken = new Token<RememberAccessor>('RememberAccessor');
// 2. Define accessor
@Provider()
class RememberAccessor {
async get(key: string): Promise<string | undefined> {
// Implementation
}
async set(key: string, value: string): Promise<void> {
// Implementation
}
}
// 3. Augment types (in .d.ts or separate file)
declare module '@frontmcp/sdk' {
interface ExecutionContextBase {
readonly remember: RememberAccessor;
}
}
// 4. Define plugin with context extension
@Plugin({
name: 'remember',
description: 'Session memory for tools',
providers: [
{ provide: RememberAccessorToken, useClass: RememberAccessor },
],
contextExtensions: [
{
property: 'remember',
token: RememberAccessorToken,
errorMessage: 'Remember plugin not installed',
},
],
})
export class RememberPlugin {}
Now in tools:
@Tool({ name: 'my_tool', inputSchema: {} })
class MyTool extends ToolContext {
async execute() {
// Access extended property
await this.remember.set('lastRun', new Date().toISOString());
const lastRun = await this.remember.get('lastRun');
}
}
Plugin Scopes
App Scope (Default)
Hooks register at app level:
@Plugin({
name: 'app-plugin',
scope: 'app', // Default
})
class AppPlugin {}
Server Scope
Hooks register at gateway/server level:
@Plugin({
name: 'server-plugin',
scope: 'server',
})
class ServerPlugin {}
Server-scoped plugins cannot be used in standalone apps. They require a gateway configuration.
Nested Plugins
Plugins can include other plugins:
@Plugin({
name: 'analytics',
plugins: [MetricsPlugin, LoggingPlugin],
providers: [AnalyticsService],
})
class AnalyticsPlugin {}
Using Plugins
In Apps
@App({
name: 'my-app',
plugins: [CachePlugin, RememberPlugin],
tools: [MyTool],
})
class MyApp {}
In Server
@FrontMcp({
info: { name: 'Server', version: '1.0.0' },
apps: [MyApp],
plugins: [GlobalLoggingPlugin], // Server-level plugins
})
class Server {}
import { Plugin, Tool, ToolContext } from '@frontmcp/sdk';
import { z } from 'zod';
@Tool({
name: 'send_elicitation_result',
description: 'Send user response to pending elicitation',
inputSchema: {
elicitId: z.string(),
response: z.any(),
},
})
class SendElicitationResultTool extends ToolContext {
async execute(input) {
// Plugin-provided tool implementation
}
}
@Plugin({
name: 'elicitation',
tools: [SendElicitationResultTool],
providers: [ElicitationService],
})
export class ElicitationPlugin {}
Full Example
import { Plugin, Provider, Token, Tool, ToolContext, App, FrontMcp } from '@frontmcp/sdk';
import { z } from 'zod';
// Tokens
export const ApprovalServiceToken = new Token<ApprovalService>('ApprovalService');
export const ApprovalAccessorToken = new Token<ApprovalAccessor>('ApprovalAccessor');
// Services
@Provider()
class ApprovalService {
private approvals = new Map<string, boolean>();
approve(toolName: string) {
this.approvals.set(toolName, true);
}
isApproved(toolName: string): boolean {
return this.approvals.get(toolName) === true;
}
revoke(toolName: string) {
this.approvals.delete(toolName);
}
}
@Provider()
class ApprovalAccessor {
constructor(private service: ApprovalService) {}
async isApproved(toolName: string): Promise<boolean> {
return this.service.isApproved(toolName);
}
async approve(toolName: string): Promise<void> {
this.service.approve(toolName);
}
}
// Module augmentation
declare module '@frontmcp/sdk' {
interface ExecutionContextBase {
readonly approval: ApprovalAccessor;
}
}
// Plugin tool
@Tool({
name: 'approve_tool',
description: 'Approve a tool for execution',
inputSchema: { toolName: z.string() },
})
class ApproveToolTool extends ToolContext {
async execute(input: { toolName: string }) {
const accessor = this.get(ApprovalAccessorToken);
await accessor.approve(input.toolName);
return { approved: input.toolName };
}
}
// Plugin definition
@Plugin({
name: 'approval',
description: 'Tool approval system',
providers: [
{ provide: ApprovalServiceToken, useClass: ApprovalService },
{ provide: ApprovalAccessorToken, useClass: ApprovalAccessor },
],
tools: [ApproveToolTool],
contextExtensions: [
{
property: 'approval',
token: ApprovalAccessorToken,
errorMessage: 'Approval plugin not installed',
},
],
})
export class ApprovalPlugin {}
// Using the plugin
@Tool({
name: 'dangerous_operation',
inputSchema: { data: z.string() },
})
class DangerousOperationTool extends ToolContext {
async execute(input: { data: string }) {
// Check approval via context extension
const isApproved = await this.approval.isApproved('dangerous_operation');
if (!isApproved) {
return { error: 'This tool requires approval. Please run approve_tool first.' };
}
// Proceed with operation
return { result: 'Operation completed' };
}
}
@App({
name: 'secure-app',
plugins: [ApprovalPlugin],
tools: [DangerousOperationTool],
})
class SecureApp {}
@FrontMcp({
info: { name: 'Secure Server', version: '1.0.0' },
apps: [SecureApp],
})
export default class SecureServer {}
Official Plugins
FrontMCP provides several official plugins:
RememberPlugin
Session memory for tools
CachePlugin
Response caching
CodeCallPlugin
Dynamic code execution
PluginRegistry
Plugin registry API
@Provider
Dependency providers
Creating Plugins
Plugin development guide