@frontmcp/skills 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +135 -0
- package/catalog/TEMPLATE.md +49 -0
- package/catalog/adapters/create-adapter/SKILL.md +127 -0
- package/catalog/adapters/official-adapters/SKILL.md +136 -0
- package/catalog/auth/configure-auth/SKILL.md +250 -0
- package/catalog/auth/configure-auth/references/auth-modes.md +77 -0
- package/catalog/auth/configure-session/SKILL.md +201 -0
- package/catalog/config/configure-elicitation/SKILL.md +136 -0
- package/catalog/config/configure-http/SKILL.md +167 -0
- package/catalog/config/configure-throttle/SKILL.md +189 -0
- package/catalog/config/configure-throttle/references/guard-config.md +68 -0
- package/catalog/config/configure-transport/SKILL.md +151 -0
- package/catalog/config/configure-transport/references/protocol-presets.md +57 -0
- package/catalog/deployment/build-for-browser/SKILL.md +95 -0
- package/catalog/deployment/build-for-cli/SKILL.md +100 -0
- package/catalog/deployment/build-for-sdk/SKILL.md +218 -0
- package/catalog/deployment/deploy-to-cloudflare/SKILL.md +192 -0
- package/catalog/deployment/deploy-to-lambda/SKILL.md +304 -0
- package/catalog/deployment/deploy-to-node/SKILL.md +229 -0
- package/catalog/deployment/deploy-to-node/references/Dockerfile.example +45 -0
- package/catalog/deployment/deploy-to-vercel/SKILL.md +196 -0
- package/catalog/deployment/deploy-to-vercel/references/vercel.json.example +60 -0
- package/catalog/development/create-agent/SKILL.md +563 -0
- package/catalog/development/create-agent/references/llm-config.md +46 -0
- package/catalog/development/create-job/SKILL.md +566 -0
- package/catalog/development/create-prompt/SKILL.md +400 -0
- package/catalog/development/create-provider/SKILL.md +233 -0
- package/catalog/development/create-resource/SKILL.md +437 -0
- package/catalog/development/create-skill/SKILL.md +526 -0
- package/catalog/development/create-skill-with-tools/SKILL.md +579 -0
- package/catalog/development/create-tool/SKILL.md +418 -0
- package/catalog/development/create-tool/references/output-schema-types.md +56 -0
- package/catalog/development/create-tool/references/tool-annotations.md +34 -0
- package/catalog/development/create-workflow/SKILL.md +709 -0
- package/catalog/development/decorators-guide/SKILL.md +598 -0
- package/catalog/plugins/create-plugin/SKILL.md +336 -0
- package/catalog/plugins/create-plugin-hooks/SKILL.md +282 -0
- package/catalog/plugins/official-plugins/SKILL.md +667 -0
- package/catalog/setup/frontmcp-skills-usage/SKILL.md +200 -0
- package/catalog/setup/multi-app-composition/SKILL.md +358 -0
- package/catalog/setup/nx-workflow/SKILL.md +357 -0
- package/catalog/setup/project-structure-nx/SKILL.md +186 -0
- package/catalog/setup/project-structure-standalone/SKILL.md +153 -0
- package/catalog/setup/setup-project/SKILL.md +493 -0
- package/catalog/setup/setup-redis/SKILL.md +385 -0
- package/catalog/setup/setup-sqlite/SKILL.md +359 -0
- package/catalog/skills-manifest.json +414 -0
- package/catalog/testing/setup-testing/SKILL.md +539 -0
- package/catalog/testing/setup-testing/references/test-auth.md +88 -0
- package/catalog/testing/setup-testing/references/test-browser-build.md +57 -0
- package/catalog/testing/setup-testing/references/test-cli-binary.md +48 -0
- package/catalog/testing/setup-testing/references/test-direct-client.md +62 -0
- package/catalog/testing/setup-testing/references/test-e2e-handler.md +51 -0
- package/catalog/testing/setup-testing/references/test-tool-unit.md +41 -0
- package/package.json +34 -0
- package/src/index.d.ts +3 -0
- package/src/index.js +16 -0
- package/src/index.js.map +1 -0
- package/src/loader.d.ts +46 -0
- package/src/loader.js +75 -0
- package/src/loader.js.map +1 -0
- package/src/manifest.d.ts +81 -0
- package/src/manifest.js +26 -0
- package/src/manifest.js.map +1 -0
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: official-plugins
|
|
3
|
+
description: Install and configure official FrontMCP plugins including CodeCall, Remember, Approval, Cache, Feature Flags, and Dashboard. Use when adding caching, memory, tool approval, feature gating, or CodeCall orchestration.
|
|
4
|
+
tags: [plugins, codecall, remember, approval, cache, feature-flags, dashboard]
|
|
5
|
+
priority: 9
|
|
6
|
+
visibility: both
|
|
7
|
+
license: Apache-2.0
|
|
8
|
+
metadata:
|
|
9
|
+
docs: https://docs.agentfront.dev/frontmcp/plugins/overview
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Official FrontMCP Plugins
|
|
13
|
+
|
|
14
|
+
FrontMCP ships 6 official plugins that extend server behavior with cross-cutting concerns: semantic tool discovery, session memory, authorization workflows, result caching, feature gating, and visual monitoring. Install individually or via `@frontmcp/plugins` (meta-package re-exporting cache, codecall, dashboard, and remember).
|
|
15
|
+
|
|
16
|
+
All plugins follow the `DynamicPlugin` pattern and are registered via `@FrontMcp({ plugins: [...] })`.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { FrontMcp } from '@frontmcp/sdk';
|
|
20
|
+
import CodeCallPlugin from '@frontmcp/plugin-codecall';
|
|
21
|
+
import RememberPlugin from '@frontmcp/plugin-remember';
|
|
22
|
+
import { ApprovalPlugin } from '@frontmcp/plugin-approval';
|
|
23
|
+
import CachePlugin from '@frontmcp/plugin-cache';
|
|
24
|
+
import FeatureFlagPlugin from '@frontmcp/plugin-feature-flags';
|
|
25
|
+
import DashboardPlugin from '@frontmcp/plugin-dashboard';
|
|
26
|
+
|
|
27
|
+
@App()
|
|
28
|
+
class MyApp {}
|
|
29
|
+
|
|
30
|
+
@FrontMcp({
|
|
31
|
+
info: { name: 'my-server', version: '1.0.0' },
|
|
32
|
+
apps: [MyApp],
|
|
33
|
+
plugins: [
|
|
34
|
+
CodeCallPlugin.init({ mode: 'codecall_only', vm: { preset: 'secure' } }),
|
|
35
|
+
RememberPlugin.init({ type: 'memory' }),
|
|
36
|
+
ApprovalPlugin.init({ mode: 'recheck' }),
|
|
37
|
+
CachePlugin.init({ type: 'memory', defaultTTL: 86400 }),
|
|
38
|
+
FeatureFlagPlugin.init({ adapter: 'static', flags: { 'new-tool': true } }),
|
|
39
|
+
DashboardPlugin.init({ enabled: true }),
|
|
40
|
+
],
|
|
41
|
+
tools: [
|
|
42
|
+
/* your tools */
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
class MyServer {}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 1. CodeCall Plugin (`@frontmcp/plugin-codecall`)
|
|
51
|
+
|
|
52
|
+
Meta-tools for semantic search and sandboxed VM execution of tools. The AI discovers, describes, and orchestrates your tools via AgentScript instead of calling them individually.
|
|
53
|
+
|
|
54
|
+
### Installation
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import CodeCallPlugin from '@frontmcp/plugin-codecall';
|
|
58
|
+
|
|
59
|
+
@FrontMcp({
|
|
60
|
+
plugins: [
|
|
61
|
+
CodeCallPlugin.init({
|
|
62
|
+
mode: 'codecall_only', // 'codecall_only' | 'codecall_opt_in' | 'metadata_driven'
|
|
63
|
+
topK: 8, // Number of search results returned
|
|
64
|
+
maxDefinitions: 8, // Max tool definitions per describe call
|
|
65
|
+
vm: {
|
|
66
|
+
preset: 'secure', // 'locked_down' | 'secure' | 'balanced' | 'experimental'
|
|
67
|
+
timeoutMs: 5000,
|
|
68
|
+
allowLoops: false,
|
|
69
|
+
},
|
|
70
|
+
embedding: {
|
|
71
|
+
strategy: 'tfidf', // 'tfidf' | 'ml'
|
|
72
|
+
synonymExpansion: { enabled: true },
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
76
|
+
})
|
|
77
|
+
class MyServer {}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Modes
|
|
81
|
+
|
|
82
|
+
- `codecall_only` -- Hides all tools from `list_tools` except CodeCall meta-tools. All other tools are discovered only via `codecall:search`. Best when the server has a large number of tools and you want the AI to search-then-execute.
|
|
83
|
+
- `codecall_opt_in` -- Shows all tools in `list_tools` normally. Tools opt-in to CodeCall execution via metadata. Useful when only some tools benefit from orchestrated execution.
|
|
84
|
+
- `metadata_driven` -- Per-tool `metadata.codecall` controls visibility and CodeCall availability independently. Most granular control.
|
|
85
|
+
|
|
86
|
+
### VM Presets
|
|
87
|
+
|
|
88
|
+
The sandboxed VM runs AgentScript (a restricted JavaScript subset). Presets control security boundaries:
|
|
89
|
+
|
|
90
|
+
- `locked_down` -- Most restrictive. No loops, no console, minimal builtins. Suitable for untrusted environments.
|
|
91
|
+
- `secure` -- Default. Reasonable limits for production use. Loops disabled, console available.
|
|
92
|
+
- `balanced` -- Relaxed constraints for development. Loops allowed with iteration limits.
|
|
93
|
+
- `experimental` -- Minimal restrictions. Full loop support, extended builtins. Development only.
|
|
94
|
+
|
|
95
|
+
### Meta-Tools Exposed
|
|
96
|
+
|
|
97
|
+
CodeCall contributes 4 tools to your server:
|
|
98
|
+
|
|
99
|
+
- `codecall:search` -- Semantic search over all registered tools using TF-IDF scoring with synonym expansion. Returns ranked tool names, descriptions, and relevance scores.
|
|
100
|
+
- `codecall:describe` -- Returns full input/output JSON schemas for one or more tools. Use after search to understand tool interfaces before execution.
|
|
101
|
+
- `codecall:execute` -- Runs an AgentScript program in the sandboxed VM. The script can call multiple tools, branch on results, and compose outputs.
|
|
102
|
+
- `codecall:invoke` -- Direct single-tool invocation (available when `directCalls` is enabled). Bypasses the VM for simple one-shot calls.
|
|
103
|
+
|
|
104
|
+
### Per-Tool CodeCall Metadata
|
|
105
|
+
|
|
106
|
+
Control how individual tools interact with CodeCall:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
@Tool({
|
|
110
|
+
name: 'my_tool',
|
|
111
|
+
codecall: {
|
|
112
|
+
visibleInListTools: false, // Hide from list_tools (only discoverable via codecall:search)
|
|
113
|
+
enabledInCodeCall: true, // Available for execution via codecall:execute
|
|
114
|
+
tags: ['data', 'query'], // Extra indexing hints for semantic search
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
class MyTool extends ToolContext {
|
|
118
|
+
/* ... */
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Power Features
|
|
123
|
+
|
|
124
|
+
- **TF-IDF Search** -- Term frequency-inverse document frequency scoring indexes tool names, descriptions, and tags. No external embedding service required.
|
|
125
|
+
- **Synonym Expansion** -- Automatically expands search queries with synonyms (e.g., "delete" also matches "remove", "erase"). Enable via `embedding.synonymExpansion.enabled`.
|
|
126
|
+
- **Pass-by-Reference via Sidecar** -- Large results are stored in a sidecar map and passed by reference between tool calls in AgentScript, avoiding serialization overhead.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 2. Remember Plugin (`@frontmcp/plugin-remember`)
|
|
131
|
+
|
|
132
|
+
Encrypted session memory with multi-scope persistence. Tools can remember values across invocations and sessions using a human-friendly API.
|
|
133
|
+
|
|
134
|
+
### Installation
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import RememberPlugin from '@frontmcp/plugin-remember';
|
|
138
|
+
|
|
139
|
+
// In-memory (development)
|
|
140
|
+
@FrontMcp({
|
|
141
|
+
plugins: [RememberPlugin.init({ type: 'memory' })],
|
|
142
|
+
})
|
|
143
|
+
class DevServer {}
|
|
144
|
+
|
|
145
|
+
// Redis (production)
|
|
146
|
+
@FrontMcp({
|
|
147
|
+
plugins: [
|
|
148
|
+
RememberPlugin.init({
|
|
149
|
+
type: 'redis',
|
|
150
|
+
config: { host: 'localhost', port: 6379 },
|
|
151
|
+
keyPrefix: 'remember:',
|
|
152
|
+
encryption: { enabled: true },
|
|
153
|
+
tools: { enabled: true }, // Expose LLM tools
|
|
154
|
+
}),
|
|
155
|
+
],
|
|
156
|
+
})
|
|
157
|
+
class ProdServer {}
|
|
158
|
+
|
|
159
|
+
// Redis client (bring your own ioredis instance)
|
|
160
|
+
@FrontMcp({
|
|
161
|
+
plugins: [
|
|
162
|
+
RememberPlugin.init({
|
|
163
|
+
type: 'redis-client',
|
|
164
|
+
client: existingRedisClient,
|
|
165
|
+
}),
|
|
166
|
+
],
|
|
167
|
+
})
|
|
168
|
+
class ClientServer {}
|
|
169
|
+
|
|
170
|
+
// Vercel KV
|
|
171
|
+
@FrontMcp({
|
|
172
|
+
plugins: [RememberPlugin.init({ type: 'vercel-kv' })],
|
|
173
|
+
})
|
|
174
|
+
class VercelServer {}
|
|
175
|
+
|
|
176
|
+
// Global store (uses @FrontMcp redis config)
|
|
177
|
+
@FrontMcp({
|
|
178
|
+
redis: { host: 'localhost', port: 6379 },
|
|
179
|
+
plugins: [RememberPlugin.init({ type: 'global-store' })],
|
|
180
|
+
})
|
|
181
|
+
class GlobalStoreServer {}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Storage Types
|
|
185
|
+
|
|
186
|
+
- `memory` -- In-process Map. Fastest, no persistence. Good for development.
|
|
187
|
+
- `redis` -- Dedicated Redis connection. Plugin manages the client lifecycle.
|
|
188
|
+
- `redis-client` -- Bring your own ioredis client instance.
|
|
189
|
+
- `vercel-kv` -- Vercel KV (Redis-compatible). Uses `@vercel/kv` package.
|
|
190
|
+
- `global-store` -- Reuses the Redis connection from `@FrontMcp({ redis: {...} })`.
|
|
191
|
+
|
|
192
|
+
### Using `this.remember` in Tools
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
@Tool({ name: 'my_tool' })
|
|
196
|
+
class MyTool extends ToolContext {
|
|
197
|
+
async execute(input: { query: string }) {
|
|
198
|
+
// Store values (default scope: 'session')
|
|
199
|
+
await this.remember.set('theme', 'dark');
|
|
200
|
+
await this.remember.set('language', 'en', { scope: 'user' });
|
|
201
|
+
await this.remember.set('temp_token', 'xyz', { ttl: 300 });
|
|
202
|
+
|
|
203
|
+
// Retrieve values
|
|
204
|
+
const theme = await this.remember.get('theme', { defaultValue: 'light' });
|
|
205
|
+
|
|
206
|
+
// Check existence
|
|
207
|
+
if (await this.remember.knows('onboarding_complete')) {
|
|
208
|
+
// Skip onboarding
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Remove values
|
|
212
|
+
await this.remember.forget('temp_token');
|
|
213
|
+
|
|
214
|
+
// List keys matching pattern
|
|
215
|
+
const keys = await this.remember.list({ pattern: 'user:*' });
|
|
216
|
+
|
|
217
|
+
return { content: [{ type: 'text', text: `Theme: ${theme}` }] };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Memory Scopes
|
|
223
|
+
|
|
224
|
+
- `session` -- Valid only for the current session. Default scope. Cleared when the session ends.
|
|
225
|
+
- `user` -- Persists for the user across sessions. Tied to user identity.
|
|
226
|
+
- `tool` -- Scoped to a specific tool + session combination. Isolated per tool.
|
|
227
|
+
- `global` -- Shared across all sessions and users. Use carefully.
|
|
228
|
+
|
|
229
|
+
### Tools Exposed (when `tools.enabled: true`)
|
|
230
|
+
|
|
231
|
+
- `remember_this` -- Store a key-value pair in memory
|
|
232
|
+
- `recall` -- Retrieve a previously stored value by key
|
|
233
|
+
- `forget` -- Remove a stored value by key
|
|
234
|
+
- `list_memories` -- List all stored keys, optionally filtered by pattern
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 3. Approval Plugin (`@frontmcp/plugin-approval`)
|
|
239
|
+
|
|
240
|
+
Tool authorization workflow with PKCE webhook security. Require explicit user or system approval before sensitive tools execute.
|
|
241
|
+
|
|
242
|
+
### Installation
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { ApprovalPlugin } from '@frontmcp/plugin-approval';
|
|
246
|
+
|
|
247
|
+
// Recheck mode (default) -- re-evaluates approval on each call
|
|
248
|
+
@FrontMcp({
|
|
249
|
+
plugins: [ApprovalPlugin.init()],
|
|
250
|
+
})
|
|
251
|
+
class BasicServer {}
|
|
252
|
+
|
|
253
|
+
// Recheck mode with explicit config
|
|
254
|
+
@FrontMcp({
|
|
255
|
+
plugins: [
|
|
256
|
+
ApprovalPlugin.init({
|
|
257
|
+
mode: 'recheck',
|
|
258
|
+
enableAudit: true,
|
|
259
|
+
}),
|
|
260
|
+
],
|
|
261
|
+
})
|
|
262
|
+
class AuditedServer {}
|
|
263
|
+
|
|
264
|
+
// Webhook mode -- PKCE-secured external approval flow
|
|
265
|
+
@FrontMcp({
|
|
266
|
+
plugins: [
|
|
267
|
+
ApprovalPlugin.init({
|
|
268
|
+
mode: 'webhook',
|
|
269
|
+
webhook: {
|
|
270
|
+
url: 'https://approval.example.com/webhook',
|
|
271
|
+
challengeTtl: 300,
|
|
272
|
+
callbackPath: '/approval/callback',
|
|
273
|
+
},
|
|
274
|
+
enableAudit: true,
|
|
275
|
+
maxDelegationDepth: 3,
|
|
276
|
+
}),
|
|
277
|
+
],
|
|
278
|
+
})
|
|
279
|
+
class WebhookServer {}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Modes
|
|
283
|
+
|
|
284
|
+
- `recheck` -- Re-evaluates approval status on every tool call. Approval can be granted programmatically via `this.approval.grantSessionApproval()`. Good for interactive approval flows where the user confirms in-band.
|
|
285
|
+
- `webhook` -- Sends a PKCE-secured webhook to an external approval service. The external service calls back to confirm or deny. Suitable for compliance workflows requiring out-of-band approval.
|
|
286
|
+
|
|
287
|
+
### Using `this.approval` in Tools
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
@Tool({ name: 'dangerous_action' })
|
|
291
|
+
class DangerousActionTool extends ToolContext {
|
|
292
|
+
async execute(input: { target: string }) {
|
|
293
|
+
// Check if tool is currently approved
|
|
294
|
+
const isApproved = await this.approval.isApproved('dangerous_action');
|
|
295
|
+
|
|
296
|
+
if (!isApproved) {
|
|
297
|
+
// Grant session-scoped approval programmatically
|
|
298
|
+
await this.approval.grantSessionApproval('dangerous_action', {
|
|
299
|
+
reason: 'User confirmed via prompt',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Additional approval API methods:
|
|
304
|
+
// await this.approval.getApproval('tool-id') -- Get approval record
|
|
305
|
+
// await this.approval.getSessionApprovals() -- List session approvals
|
|
306
|
+
// await this.approval.getUserApprovals() -- List user approvals
|
|
307
|
+
// await this.approval.grantUserApproval('tool-id') -- Persist across sessions
|
|
308
|
+
// await this.approval.grantTimeLimitedApproval('tool-id', 60000) -- Auto-expire
|
|
309
|
+
// await this.approval.revokeApproval('tool-id') -- Revoke any approval
|
|
310
|
+
|
|
311
|
+
return { content: [{ type: 'text', text: 'Action completed' }] };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Per-Tool Approval Metadata
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
@Tool({
|
|
320
|
+
name: 'file_write',
|
|
321
|
+
approval: {
|
|
322
|
+
required: true,
|
|
323
|
+
defaultScope: 'session', // 'session' | 'user' | 'time-limited'
|
|
324
|
+
category: 'write',
|
|
325
|
+
riskLevel: 'medium', // 'low' | 'medium' | 'high' | 'critical'
|
|
326
|
+
approvalMessage: 'Allow file writing for this session?',
|
|
327
|
+
},
|
|
328
|
+
})
|
|
329
|
+
class FileWriteTool extends ToolContext {
|
|
330
|
+
/* ... */
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
When `approval.required` is `true`, the plugin automatically intercepts tool execution and checks approval status before allowing the tool to run.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 4. Cache Plugin (`@frontmcp/plugin-cache`)
|
|
339
|
+
|
|
340
|
+
Automatic tool result caching. Cache responses by tool name patterns or per-tool metadata. Supports sliding window TTL and cache bypass headers.
|
|
341
|
+
|
|
342
|
+
### Installation
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import CachePlugin from '@frontmcp/plugin-cache';
|
|
346
|
+
|
|
347
|
+
// In-memory cache
|
|
348
|
+
@FrontMcp({
|
|
349
|
+
plugins: [
|
|
350
|
+
CachePlugin.init({
|
|
351
|
+
type: 'memory',
|
|
352
|
+
defaultTTL: 3600, // 1 hour in seconds
|
|
353
|
+
toolPatterns: ['api:get-*', 'search:*'], // Cache tools matching glob patterns
|
|
354
|
+
bypassHeader: 'x-frontmcp-disable-cache', // Header to skip cache
|
|
355
|
+
}),
|
|
356
|
+
],
|
|
357
|
+
})
|
|
358
|
+
class CachedServer {}
|
|
359
|
+
|
|
360
|
+
// Redis cache
|
|
361
|
+
@FrontMcp({
|
|
362
|
+
plugins: [
|
|
363
|
+
CachePlugin.init({
|
|
364
|
+
type: 'redis',
|
|
365
|
+
config: { host: 'localhost', port: 6379 },
|
|
366
|
+
defaultTTL: 86400, // 1 day in seconds
|
|
367
|
+
}),
|
|
368
|
+
],
|
|
369
|
+
})
|
|
370
|
+
class RedisCachedServer {}
|
|
371
|
+
|
|
372
|
+
// Global store (uses @FrontMcp redis config)
|
|
373
|
+
@FrontMcp({
|
|
374
|
+
redis: { host: 'localhost', port: 6379 },
|
|
375
|
+
plugins: [CachePlugin.init({ type: 'global-store' })],
|
|
376
|
+
})
|
|
377
|
+
class GlobalCacheServer {}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Storage Types
|
|
381
|
+
|
|
382
|
+
- `memory` -- In-process Map with automatic eviction. No external dependencies.
|
|
383
|
+
- `redis` -- Dedicated Redis connection with native TTL support. Plugin manages the client.
|
|
384
|
+
- `redis-client` -- Bring your own ioredis client instance.
|
|
385
|
+
- `global-store` -- Reuses the Redis connection from `@FrontMcp({ redis: {...} })`.
|
|
386
|
+
|
|
387
|
+
### Per-Tool Cache Metadata
|
|
388
|
+
|
|
389
|
+
Enable caching on individual tools via the `cache` metadata field:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
// Enable caching with default TTL
|
|
393
|
+
@Tool({ name: 'get_weather', cache: true })
|
|
394
|
+
class GetWeatherTool extends ToolContext {
|
|
395
|
+
/* ... */
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Custom TTL and sliding window
|
|
399
|
+
@Tool({
|
|
400
|
+
name: 'get_user_profile',
|
|
401
|
+
cache: {
|
|
402
|
+
ttl: 3600, // Override default TTL (seconds)
|
|
403
|
+
slideWindow: true, // Refresh TTL on cache hit
|
|
404
|
+
},
|
|
405
|
+
})
|
|
406
|
+
class GetUserProfileTool extends ToolContext {
|
|
407
|
+
/* ... */
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Tool Patterns
|
|
412
|
+
|
|
413
|
+
Use glob patterns to cache groups of tools without modifying each tool:
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
CachePlugin.init({
|
|
417
|
+
type: 'memory',
|
|
418
|
+
defaultTTL: 3600,
|
|
419
|
+
toolPatterns: [
|
|
420
|
+
'namespace:*', // All tools in a namespace
|
|
421
|
+
'api:get-*', // All GET-like API tools
|
|
422
|
+
'search:*', // All search tools
|
|
423
|
+
],
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
A tool is cached if it matches any pattern OR has `cache: true` (or a cache object) in its metadata.
|
|
428
|
+
|
|
429
|
+
### Cache Bypass
|
|
430
|
+
|
|
431
|
+
Send the bypass header to skip caching for a specific request:
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
x-frontmcp-disable-cache: true
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
The header name is configurable via `bypassHeader` in the plugin options. Default: `'x-frontmcp-disable-cache'`.
|
|
438
|
+
|
|
439
|
+
### Cache Key
|
|
440
|
+
|
|
441
|
+
The cache key is computed from the tool name and the serialized input arguments. Two calls with identical tool name and arguments return the same cached result.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 5. Feature Flags Plugin (`@frontmcp/plugin-feature-flags`)
|
|
446
|
+
|
|
447
|
+
Gate tools, resources, prompts, and skills behind feature flags. Integrates with popular feature flag services or static configuration.
|
|
448
|
+
|
|
449
|
+
### Installation
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
import FeatureFlagPlugin from '@frontmcp/plugin-feature-flags';
|
|
453
|
+
|
|
454
|
+
// Static flags (no external dependency)
|
|
455
|
+
@FrontMcp({
|
|
456
|
+
plugins: [
|
|
457
|
+
FeatureFlagPlugin.init({
|
|
458
|
+
adapter: 'static',
|
|
459
|
+
flags: {
|
|
460
|
+
'beta-tools': true,
|
|
461
|
+
'experimental-agent': false,
|
|
462
|
+
'new-search': true,
|
|
463
|
+
},
|
|
464
|
+
}),
|
|
465
|
+
],
|
|
466
|
+
})
|
|
467
|
+
class StaticFlagServer {}
|
|
468
|
+
|
|
469
|
+
// Split.io
|
|
470
|
+
@FrontMcp({
|
|
471
|
+
plugins: [
|
|
472
|
+
FeatureFlagPlugin.init({
|
|
473
|
+
adapter: 'splitio',
|
|
474
|
+
config: { apiKey: 'sdk-key-xxx' },
|
|
475
|
+
}),
|
|
476
|
+
],
|
|
477
|
+
})
|
|
478
|
+
class SplitServer {}
|
|
479
|
+
|
|
480
|
+
// LaunchDarkly
|
|
481
|
+
@FrontMcp({
|
|
482
|
+
plugins: [
|
|
483
|
+
FeatureFlagPlugin.init({
|
|
484
|
+
adapter: 'launchdarkly',
|
|
485
|
+
config: { sdkKey: 'sdk-xxx' },
|
|
486
|
+
}),
|
|
487
|
+
],
|
|
488
|
+
})
|
|
489
|
+
class LDServer {}
|
|
490
|
+
|
|
491
|
+
// Unleash
|
|
492
|
+
@FrontMcp({
|
|
493
|
+
plugins: [
|
|
494
|
+
FeatureFlagPlugin.init({
|
|
495
|
+
adapter: 'unleash',
|
|
496
|
+
config: {
|
|
497
|
+
url: 'https://unleash.example.com/api',
|
|
498
|
+
appName: 'my-mcp-server',
|
|
499
|
+
apiKey: 'xxx',
|
|
500
|
+
},
|
|
501
|
+
}),
|
|
502
|
+
],
|
|
503
|
+
})
|
|
504
|
+
class UnleashServer {}
|
|
505
|
+
|
|
506
|
+
// Custom adapter
|
|
507
|
+
@FrontMcp({
|
|
508
|
+
plugins: [
|
|
509
|
+
FeatureFlagPlugin.init({
|
|
510
|
+
adapter: 'custom',
|
|
511
|
+
adapterInstance: myCustomAdapter,
|
|
512
|
+
}),
|
|
513
|
+
],
|
|
514
|
+
})
|
|
515
|
+
class CustomFlagServer {}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Adapters
|
|
519
|
+
|
|
520
|
+
- `static` -- Hardcoded flag map. No external service. Good for development and testing.
|
|
521
|
+
- `splitio` -- Split.io integration. Requires `@splitsoftware/splitio` package.
|
|
522
|
+
- `launchdarkly` -- LaunchDarkly integration. Requires `launchdarkly-node-server-sdk` package.
|
|
523
|
+
- `unleash` -- Unleash integration. Requires `unleash-client` package.
|
|
524
|
+
- `custom` -- Provide your own adapter instance implementing the `FeatureFlagAdapter` interface.
|
|
525
|
+
|
|
526
|
+
### Using `this.featureFlags` in Tools
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
@Tool({ name: 'beta_feature' })
|
|
530
|
+
class BetaFeatureTool extends ToolContext {
|
|
531
|
+
async execute(input: unknown) {
|
|
532
|
+
// Check if a flag is enabled (returns boolean)
|
|
533
|
+
const enabled = await this.featureFlags.isEnabled('beta-feature-flag');
|
|
534
|
+
if (!enabled) {
|
|
535
|
+
return { content: [{ type: 'text', text: 'Feature not available' }] };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Get variant value (for multivariate flags)
|
|
539
|
+
const variant = await this.featureFlags.getVariant('experiment-flag');
|
|
540
|
+
// variant may be 'control', 'treatment-a', 'treatment-b', etc.
|
|
541
|
+
|
|
542
|
+
return { content: [{ type: 'text', text: `Running variant: ${variant}` }] };
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Per-Tool Feature Flag Gating
|
|
548
|
+
|
|
549
|
+
Tools gated by a feature flag are automatically hidden from `list_tools` and blocked from execution when the flag is off:
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
// Simple string key -- flag must be truthy to enable the tool
|
|
553
|
+
@Tool({ name: 'beta_tool', featureFlag: 'enable-beta-tools' })
|
|
554
|
+
class BetaTool extends ToolContext {
|
|
555
|
+
/* ... */
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Object with default value -- if flag evaluation fails, use the default
|
|
559
|
+
@Tool({
|
|
560
|
+
name: 'experimental_tool',
|
|
561
|
+
featureFlag: { key: 'experimental-flag', defaultValue: false },
|
|
562
|
+
})
|
|
563
|
+
class ExperimentalTool extends ToolContext {
|
|
564
|
+
/* ... */
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
The plugin hooks into listing and execution flows for tools, resources, prompts, and skills. When a flag evaluates to `false`, the corresponding entry is filtered from list results and direct invocation returns an error.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 6. Dashboard Plugin (`@frontmcp/plugin-dashboard`)
|
|
573
|
+
|
|
574
|
+
Visual monitoring web UI for your FrontMCP server. View server structure (tools, resources, prompts, apps, plugins) as an interactive graph.
|
|
575
|
+
|
|
576
|
+
### Installation
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
import DashboardPlugin from '@frontmcp/plugin-dashboard';
|
|
580
|
+
|
|
581
|
+
// Basic (auto-enabled in dev, disabled in production)
|
|
582
|
+
@FrontMcp({
|
|
583
|
+
plugins: [DashboardPlugin.init({})],
|
|
584
|
+
})
|
|
585
|
+
class DevServer {}
|
|
586
|
+
|
|
587
|
+
// With authentication and custom CDN
|
|
588
|
+
@FrontMcp({
|
|
589
|
+
plugins: [
|
|
590
|
+
DashboardPlugin.init({
|
|
591
|
+
enabled: true,
|
|
592
|
+
basePath: '/dashboard',
|
|
593
|
+
auth: {
|
|
594
|
+
enabled: true,
|
|
595
|
+
token: 'my-secret-token',
|
|
596
|
+
},
|
|
597
|
+
cdn: {
|
|
598
|
+
entrypoint: 'https://cdn.example.com/dashboard-ui@1.0.0/index.js',
|
|
599
|
+
},
|
|
600
|
+
}),
|
|
601
|
+
],
|
|
602
|
+
})
|
|
603
|
+
class ProdServer {}
|
|
604
|
+
// Access: http://localhost:3000/dashboard?token=my-secret-token
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### Options
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
interface DashboardPluginOptionsInput {
|
|
611
|
+
enabled?: boolean; // Auto: enabled in dev, disabled in prod
|
|
612
|
+
basePath?: string; // Default: '/dashboard'
|
|
613
|
+
auth?: {
|
|
614
|
+
enabled?: boolean; // Default: false
|
|
615
|
+
token?: string; // Query param auth (?token=xxx)
|
|
616
|
+
};
|
|
617
|
+
cdn?: {
|
|
618
|
+
entrypoint?: string; // Custom UI bundle URL
|
|
619
|
+
react?: string; // React CDN URL override
|
|
620
|
+
reactDom?: string; // React DOM CDN URL override
|
|
621
|
+
xyflow?: string; // XYFlow (React Flow) CDN URL override
|
|
622
|
+
dagre?: string; // Dagre layout CDN URL override
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
- `enabled` -- When omitted, the dashboard is automatically enabled in development (`NODE_ENV !== 'production'`) and disabled in production.
|
|
628
|
+
- `basePath` -- URL path where the dashboard is served. Default: `'/dashboard'`.
|
|
629
|
+
- `auth.token` -- When set, the dashboard requires `?token=<value>` as a query parameter.
|
|
630
|
+
- `cdn` -- Override default CDN URLs for the dashboard UI bundle and its dependencies. Useful for air-gapped environments.
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Registration Pattern
|
|
635
|
+
|
|
636
|
+
All official plugins use the static `init()` pattern inherited from `DynamicPlugin`. Register them in the `plugins` array of your `@FrontMcp` decorator:
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
@FrontMcp({
|
|
640
|
+
info: { name: 'production-server', version: '1.0.0' },
|
|
641
|
+
apps: [MyApp],
|
|
642
|
+
plugins: [
|
|
643
|
+
CodeCallPlugin.init({ mode: 'codecall_only', vm: { preset: 'secure' } }),
|
|
644
|
+
RememberPlugin.init({ type: 'redis', config: { host: 'redis.internal' } }),
|
|
645
|
+
ApprovalPlugin.init({ mode: 'recheck' }),
|
|
646
|
+
CachePlugin.init({ type: 'redis', config: { host: 'redis.internal' }, defaultTTL: 86400 }),
|
|
647
|
+
FeatureFlagPlugin.init({ adapter: 'launchdarkly', config: { sdkKey: 'sdk-xxx' } }),
|
|
648
|
+
DashboardPlugin.init({ enabled: true, auth: { enabled: true, token: process.env.DASH_TOKEN } }),
|
|
649
|
+
],
|
|
650
|
+
tools: [
|
|
651
|
+
/* ... */
|
|
652
|
+
],
|
|
653
|
+
})
|
|
654
|
+
class ProductionServer {}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## Reference
|
|
658
|
+
|
|
659
|
+
- Plugins docs: [docs.agentfront.dev/frontmcp/plugins/overview](https://docs.agentfront.dev/frontmcp/plugins/overview)
|
|
660
|
+
- `DynamicPlugin` base class: import from `@frontmcp/sdk`
|
|
661
|
+
- CodeCall: `@frontmcp/plugin-codecall` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-codecall) | [docs](https://docs.agentfront.dev/frontmcp/plugins/codecall/overview)
|
|
662
|
+
- Remember: `@frontmcp/plugin-remember` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-remember) | [docs](https://docs.agentfront.dev/frontmcp/plugins/remember-plugin)
|
|
663
|
+
- Approval: `@frontmcp/plugin-approval` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-approval)
|
|
664
|
+
- Cache: `@frontmcp/plugin-cache` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-cache) | [docs](https://docs.agentfront.dev/frontmcp/plugins/cache-plugin)
|
|
665
|
+
- Feature Flags: `@frontmcp/plugin-feature-flags` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-feature-flags) | [docs](https://docs.agentfront.dev/frontmcp/plugins/feature-flags-plugin)
|
|
666
|
+
- Dashboard: `@frontmcp/plugin-dashboard` — [source](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-dashboard)
|
|
667
|
+
- Meta-package: `@frontmcp/plugins` (re-exports cache, codecall, dashboard, remember)
|