Documentation Index
Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
Use this file to discover all available pages before exploring further.
Creating Plugins
Build custom plugins to extend FrontMCP with your own functionality.
Basic Plugin Structure
import { Plugin, PluginContext } from '@frontmcp/sdk';
export class MyPlugin implements Plugin {
name = 'my-plugin';
constructor(private options: MyPluginOptions) {}
async onInit(ctx: PluginContext) {
console.log('Plugin initialized');
}
async beforeTool(ctx: ToolContext) {
console.log(`Before: ${ctx.toolName}`);
}
async afterTool(ctx: ToolContext, result: any) {
console.log(`After: ${ctx.toolName}`);
return result; // Can modify result
}
}
Plugins can add tools to the server:
export class AnalyticsPlugin implements Plugin {
name = 'analytics';
getTools() {
return [
{
name: 'trackEvent',
description: 'Track an analytics event',
schema: z.object({
event: z.string(),
properties: z.record(z.any()).optional()
}),
handler: async ({ event, properties }) => {
await this.analytics.track(event, properties);
return { tracked: true };
}
}
];
}
}
Adding Resources
Plugins can add resources:
export class ConfigPlugin implements Plugin {
name = 'config';
getResources() {
return [
{
name: 'config',
description: 'Server configuration',
uri: 'config://settings',
handler: async () => this.config
}
];
}
}
Intercepting Calls
Modify tool behavior:
export class LoggingPlugin implements Plugin {
name = 'logging';
async beforeTool(ctx: ToolContext) {
ctx.startTime = Date.now();
this.logger.info(`Calling ${ctx.toolName}`, { params: ctx.params });
}
async afterTool(ctx: ToolContext, result: any) {
const duration = Date.now() - ctx.startTime;
this.logger.info(`${ctx.toolName} completed`, { duration, result });
return result;
}
async onError(error: Error, ctx: ToolContext) {
this.logger.error(`${ctx.toolName} failed`, { error: error.message });
}
}
Providing Services
Share services with apps:
export class DatabasePlugin implements Plugin {
name = 'database';
private client: DatabaseClient;
async onInit() {
this.client = await Database.connect(this.options.url);
}
async onDestroy() {
await this.client.disconnect();
}
getProviders() {
return [
{
provide: 'Database',
useValue: this.client
}
];
}
}
Configuration
Make plugins configurable:
interface RateLimitOptions {
maxRequests: number;
windowMs: number;
}
export class RateLimitPlugin implements Plugin {
name = 'rate-limit';
constructor(private options: RateLimitOptions) {}
async beforeTool(ctx: ToolContext) {
const key = `${ctx.userId}:${ctx.toolName}`;
const count = await this.increment(key);
if (count > this.options.maxRequests) {
throw new Error('Rate limit exceeded');
}
}
}
Publishing Plugins
# Package structure
my-plugin/
├── src/
│ └── index.ts
├── package.json
└── README.md
# Publish
npm publish
Next Steps
Cache Plugin
Learn from Cache Plugin
Community
Share your plugin