@frontmcp/skills 0.0.1 → 1.0.0-beta.10
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/README.md +2 -2
- package/catalog/TEMPLATE.md +58 -13
- package/catalog/frontmcp-config/SKILL.md +143 -0
- package/catalog/frontmcp-config/references/configure-auth.md +238 -0
- package/catalog/frontmcp-config/references/configure-elicitation.md +178 -0
- package/catalog/frontmcp-config/references/configure-http.md +205 -0
- package/catalog/frontmcp-config/references/configure-session.md +205 -0
- package/catalog/frontmcp-config/references/configure-throttle.md +229 -0
- package/catalog/frontmcp-config/references/configure-transport.md +195 -0
- package/catalog/frontmcp-config/references/setup-redis.md +4 -0
- package/catalog/frontmcp-config/references/setup-sqlite.md +4 -0
- package/catalog/frontmcp-deployment/SKILL.md +127 -0
- package/catalog/frontmcp-deployment/references/build-for-browser.md +138 -0
- package/catalog/frontmcp-deployment/references/build-for-cli.md +138 -0
- package/catalog/{deployment/build-for-sdk/SKILL.md → frontmcp-deployment/references/build-for-sdk.md} +65 -24
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +213 -0
- package/catalog/{deployment/deploy-to-lambda/SKILL.md → frontmcp-deployment/references/deploy-to-lambda.md} +76 -63
- package/catalog/{deployment/deploy-to-node/references/Dockerfile.example → frontmcp-deployment/references/deploy-to-node-dockerfile.md} +13 -4
- package/catalog/{deployment/deploy-to-node/SKILL.md → frontmcp-deployment/references/deploy-to-node.md} +68 -40
- package/catalog/frontmcp-deployment/references/deploy-to-vercel-config.md +60 -0
- package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +224 -0
- package/catalog/frontmcp-development/SKILL.md +121 -0
- package/catalog/frontmcp-development/references/create-adapter.md +165 -0
- package/catalog/{development/create-agent/references/llm-config.md → frontmcp-development/references/create-agent-llm-config.md} +5 -5
- package/catalog/{development/create-agent/SKILL.md → frontmcp-development/references/create-agent.md} +82 -44
- package/catalog/{development/create-job/SKILL.md → frontmcp-development/references/create-job.md} +61 -19
- package/catalog/{plugins/create-plugin-hooks/SKILL.md → frontmcp-development/references/create-plugin-hooks.md} +63 -11
- package/catalog/{plugins/create-plugin/SKILL.md → frontmcp-development/references/create-plugin.md} +65 -60
- package/catalog/{development/create-prompt/SKILL.md → frontmcp-development/references/create-prompt.md} +62 -26
- package/catalog/{development/create-provider/SKILL.md → frontmcp-development/references/create-provider.md} +62 -27
- package/catalog/{development/create-resource/SKILL.md → frontmcp-development/references/create-resource.md} +62 -30
- package/catalog/{development/create-skill-with-tools/SKILL.md → frontmcp-development/references/create-skill-with-tools.md} +69 -24
- package/catalog/{development/create-skill/SKILL.md → frontmcp-development/references/create-skill.md} +96 -22
- package/catalog/{development/create-tool/SKILL.md → frontmcp-development/references/create-tool.md} +62 -26
- package/catalog/{development/create-workflow/SKILL.md → frontmcp-development/references/create-workflow.md} +60 -18
- package/catalog/{development/decorators-guide/SKILL.md → frontmcp-development/references/decorators-guide.md} +123 -34
- package/catalog/frontmcp-development/references/official-adapters.md +194 -0
- package/catalog/{plugins/official-plugins/SKILL.md → frontmcp-development/references/official-plugins.md} +96 -31
- package/catalog/frontmcp-guides/SKILL.md +420 -0
- package/catalog/frontmcp-guides/references/example-knowledge-base.md +636 -0
- package/catalog/frontmcp-guides/references/example-task-manager.md +512 -0
- package/catalog/frontmcp-guides/references/example-weather-api.md +292 -0
- package/catalog/frontmcp-production-readiness/SKILL.md +253 -0
- package/catalog/frontmcp-setup/SKILL.md +130 -0
- package/catalog/frontmcp-setup/references/frontmcp-skills-usage.md +265 -0
- package/catalog/{setup/multi-app-composition/SKILL.md → frontmcp-setup/references/multi-app-composition.md} +65 -23
- package/catalog/{setup/nx-workflow/SKILL.md → frontmcp-setup/references/nx-workflow.md} +78 -21
- package/catalog/frontmcp-setup/references/project-structure-nx.md +246 -0
- package/catalog/frontmcp-setup/references/project-structure-standalone.md +212 -0
- package/catalog/{setup/setup-project/SKILL.md → frontmcp-setup/references/setup-project.md} +62 -62
- package/catalog/{setup/setup-redis/SKILL.md → frontmcp-setup/references/setup-redis.md} +59 -86
- package/catalog/{setup/setup-sqlite/SKILL.md → frontmcp-setup/references/setup-sqlite.md} +64 -76
- package/catalog/frontmcp-testing/SKILL.md +127 -0
- package/catalog/{testing/setup-testing/SKILL.md → frontmcp-testing/references/setup-testing.md} +78 -67
- package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-tool-unit.md +1 -0
- package/catalog/skills-manifest.json +39 -378
- package/package.json +2 -2
- package/src/loader.js +0 -1
- package/src/loader.js.map +1 -1
- package/src/manifest.d.ts +3 -3
- package/src/manifest.js +2 -3
- package/src/manifest.js.map +1 -1
- package/catalog/adapters/create-adapter/SKILL.md +0 -127
- package/catalog/adapters/official-adapters/SKILL.md +0 -136
- package/catalog/auth/configure-auth/SKILL.md +0 -250
- package/catalog/auth/configure-session/SKILL.md +0 -201
- package/catalog/config/configure-elicitation/SKILL.md +0 -136
- package/catalog/config/configure-http/SKILL.md +0 -167
- package/catalog/config/configure-throttle/SKILL.md +0 -189
- package/catalog/config/configure-transport/SKILL.md +0 -151
- package/catalog/deployment/build-for-browser/SKILL.md +0 -95
- package/catalog/deployment/build-for-cli/SKILL.md +0 -100
- package/catalog/deployment/deploy-to-cloudflare/SKILL.md +0 -192
- package/catalog/deployment/deploy-to-vercel/SKILL.md +0 -196
- package/catalog/deployment/deploy-to-vercel/references/vercel.json.example +0 -60
- package/catalog/setup/frontmcp-skills-usage/SKILL.md +0 -200
- package/catalog/setup/project-structure-nx/SKILL.md +0 -186
- package/catalog/setup/project-structure-standalone/SKILL.md +0 -153
- /package/catalog/{auth/configure-auth/references/auth-modes.md → frontmcp-config/references/configure-auth-modes.md} +0 -0
- /package/catalog/{config/configure-throttle/references/guard-config.md → frontmcp-config/references/configure-throttle-guard-config.md} +0 -0
- /package/catalog/{config/configure-transport/references/protocol-presets.md → frontmcp-config/references/configure-transport-protocol-presets.md} +0 -0
- /package/catalog/{development/create-tool/references/tool-annotations.md → frontmcp-development/references/create-tool-annotations.md} +0 -0
- /package/catalog/{development/create-tool/references/output-schema-types.md → frontmcp-development/references/create-tool-output-schema-types.md} +0 -0
- /package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-auth.md +0 -0
- /package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-browser-build.md +0 -0
- /package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-cli-binary.md +0 -0
- /package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-direct-client.md +0 -0
- /package/catalog/{testing/setup-testing → frontmcp-testing}/references/test-e2e-handler.md +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Creating Custom Adapters
|
|
2
|
+
|
|
3
|
+
Build adapters that automatically generate MCP tools, resources, and prompts from external sources — databases, GraphQL schemas, proprietary APIs, or any definition format.
|
|
4
|
+
|
|
5
|
+
## When to Use This Skill
|
|
6
|
+
|
|
7
|
+
### Must Use
|
|
8
|
+
|
|
9
|
+
- Integrating a non-OpenAPI source (GraphQL, gRPC, database schema) that should generate MCP tools automatically
|
|
10
|
+
- Building a reusable adapter that converts external definitions into tools, resources, or prompts at startup
|
|
11
|
+
- Creating tools dynamically at runtime based on external state or configuration
|
|
12
|
+
|
|
13
|
+
### Recommended
|
|
14
|
+
|
|
15
|
+
- Wrapping a proprietary internal API that has its own schema format
|
|
16
|
+
- Auto-generating tools from a database schema or config file on server start
|
|
17
|
+
- Building an adapter that polls an external source and refreshes tool definitions periodically
|
|
18
|
+
|
|
19
|
+
### Skip When
|
|
20
|
+
|
|
21
|
+
- The external API has an OpenAPI/Swagger spec (see `official-adapters`)
|
|
22
|
+
- You need cross-cutting middleware behavior like logging or caching (see `create-plugin`)
|
|
23
|
+
- You are building a single static tool manually (see `create-tool`)
|
|
24
|
+
|
|
25
|
+
> **Decision:** Use this skill when you need to auto-generate MCP tools, resources, or prompts from a non-OpenAPI external source by extending `DynamicAdapter`.
|
|
26
|
+
|
|
27
|
+
## Step 1: Extend DynamicAdapter
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { DynamicAdapter, type FrontMcpAdapterResponse } from '@frontmcp/sdk';
|
|
31
|
+
|
|
32
|
+
interface MyAdapterOptions {
|
|
33
|
+
endpoint: string;
|
|
34
|
+
apiKey: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class MyApiAdapter extends DynamicAdapter<MyAdapterOptions> {
|
|
38
|
+
declare __options_brand: MyAdapterOptions;
|
|
39
|
+
|
|
40
|
+
async fetch(): Promise<FrontMcpAdapterResponse> {
|
|
41
|
+
// Fetch definitions from external source
|
|
42
|
+
const res = await globalThis.fetch(this.options.endpoint, {
|
|
43
|
+
headers: { Authorization: `Bearer ${this.options.apiKey}` },
|
|
44
|
+
});
|
|
45
|
+
const schema = await res.json();
|
|
46
|
+
|
|
47
|
+
// Convert to MCP tool definitions
|
|
48
|
+
return {
|
|
49
|
+
tools: schema.operations.map((op: { name: string; description: string; params: Record<string, unknown> }) => ({
|
|
50
|
+
name: op.name,
|
|
51
|
+
description: op.description,
|
|
52
|
+
inputSchema: this.convertParams(op.params),
|
|
53
|
+
execute: async (input: Record<string, unknown>) => {
|
|
54
|
+
return this.callApi(op.name, input);
|
|
55
|
+
},
|
|
56
|
+
})),
|
|
57
|
+
resources: [],
|
|
58
|
+
prompts: [],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private convertParams(params: Record<string, unknown>) {
|
|
63
|
+
// Convert external param definitions to Zod schemas
|
|
64
|
+
// ...
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private async callApi(operation: string, input: Record<string, unknown>) {
|
|
68
|
+
// Call the external API
|
|
69
|
+
// ...
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Step 2: Register
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
@App({
|
|
78
|
+
name: 'MyApp',
|
|
79
|
+
adapters: [
|
|
80
|
+
MyApiAdapter.init({
|
|
81
|
+
name: 'my-api',
|
|
82
|
+
endpoint: 'https://api.example.com/schema',
|
|
83
|
+
apiKey: process.env.API_KEY!,
|
|
84
|
+
}),
|
|
85
|
+
],
|
|
86
|
+
})
|
|
87
|
+
class MyApp {}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## FrontMcpAdapterResponse
|
|
91
|
+
|
|
92
|
+
The `fetch()` method returns tools, resources, and prompts to register:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface FrontMcpAdapterResponse {
|
|
96
|
+
tools?: AdapterToolDefinition[];
|
|
97
|
+
resources?: AdapterResourceDefinition[];
|
|
98
|
+
prompts?: AdapterPromptDefinition[];
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Static init()
|
|
103
|
+
|
|
104
|
+
`DynamicAdapter` provides a static `init()` method inherited by all subclasses:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Usage — no manual instantiation needed
|
|
108
|
+
const adapter = MyApiAdapter.init({
|
|
109
|
+
name: 'my-api', // Required: adapter name (used for tool namespacing)
|
|
110
|
+
endpoint: '...',
|
|
111
|
+
apiKey: '...',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Register in @App
|
|
115
|
+
@App({ adapters: [adapter] })
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Nx Generator
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
nx generate @frontmcp/nx:adapter my-adapter --project=my-app
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Creates a `DynamicAdapter` subclass in `src/adapters/my-adapter.adapter.ts`.
|
|
125
|
+
|
|
126
|
+
## Common Patterns
|
|
127
|
+
|
|
128
|
+
| Pattern | Correct | Incorrect | Why |
|
|
129
|
+
| ----------------------- | ------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------- |
|
|
130
|
+
| Adapter registration | `MyAdapter.init({ name: 'my-api', ... })` in `adapters` array | `new MyAdapter({ ... })` directly | `init()` returns the proper provider entry for DI wiring |
|
|
131
|
+
| Options branding | `declare __options_brand: MyAdapterOptions;` in adapter class | Omitting the brand declaration | Brand ensures TypeScript infers the correct options type for `init()` |
|
|
132
|
+
| Fetch return type | Return `{ tools: [...], resources: [...], prompts: [...] }` | Returning raw API response without conversion | `fetch()` must return `FrontMcpAdapterResponse` with MCP-compatible definitions |
|
|
133
|
+
| Tool naming | Namespace tools: `name: 'my-api:operation-name'` | Flat names without namespace: `name: 'operation-name'` | Namespacing prevents collisions when multiple adapters are registered |
|
|
134
|
+
| Error handling in fetch | Throw descriptive errors with endpoint info | Silently returning empty arrays on failure | Adapter errors should surface at startup so misconfigurations are caught early |
|
|
135
|
+
|
|
136
|
+
## Verification Checklist
|
|
137
|
+
|
|
138
|
+
### Configuration
|
|
139
|
+
|
|
140
|
+
- [ ] Adapter class extends `DynamicAdapter<TOptions>`
|
|
141
|
+
- [ ] `__options_brand` is declared with the correct options type
|
|
142
|
+
- [ ] `fetch()` method is implemented and returns `FrontMcpAdapterResponse`
|
|
143
|
+
- [ ] Adapter is registered via `.init()` in the `adapters` array of `@App`
|
|
144
|
+
|
|
145
|
+
### Runtime
|
|
146
|
+
|
|
147
|
+
- [ ] Generated tools appear in `tools/list` MCP response
|
|
148
|
+
- [ ] Tool names are namespaced with the adapter name (e.g., `my-api:operationId`)
|
|
149
|
+
- [ ] Generated tools accept valid input and return expected output
|
|
150
|
+
- [ ] Adapter fetch errors produce clear startup error messages
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
|
|
154
|
+
| Problem | Cause | Solution |
|
|
155
|
+
| ------------------------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
156
|
+
| No tools appear after adapter registration | `fetch()` returns empty `tools` array | Verify external source is reachable and response is parsed correctly |
|
|
157
|
+
| TypeScript error on `.init()` options | Missing `__options_brand` declaration | Add `declare __options_brand: MyAdapterOptions;` to the adapter class |
|
|
158
|
+
| Tool input validation fails | `inputSchema` conversion does not produce valid Zod schemas | Verify `convertParams` produces `z.object()` shapes matching the external schema |
|
|
159
|
+
| Duplicate tool name error | Multiple adapters produce tools with the same name | Use unique `name` parameter in `init()` to namespace tools |
|
|
160
|
+
| Adapter not found at runtime | Registered in wrong `@App` or not in `adapters` array | Ensure `.init()` result is in the `adapters` array of the correct `@App` |
|
|
161
|
+
|
|
162
|
+
## Reference
|
|
163
|
+
|
|
164
|
+
- [Adapter Documentation](https://docs.agentfront.dev/frontmcp/adapters/overview)
|
|
165
|
+
- Related skills: `official-adapters`, `create-plugin`, `create-tool`
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Agent LLM Configuration Reference
|
|
2
2
|
|
|
3
|
-
## Supported
|
|
3
|
+
## Supported Providers
|
|
4
4
|
|
|
5
5
|
### Anthropic
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
llm: {
|
|
9
|
-
|
|
10
|
-
model: 'claude-sonnet-4-20250514',
|
|
9
|
+
provider: 'anthropic', // Any supported provider — 'anthropic', 'openai', etc.
|
|
10
|
+
model: 'claude-sonnet-4-20250514', // Any supported model for the chosen provider
|
|
11
11
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
12
12
|
maxTokens: 4096,
|
|
13
13
|
}
|
|
@@ -17,8 +17,8 @@ llm: {
|
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
19
|
llm: {
|
|
20
|
-
|
|
21
|
-
model: 'gpt-4o',
|
|
20
|
+
provider: 'openai',
|
|
21
|
+
model: 'gpt-4o', // Any supported model for the chosen provider
|
|
22
22
|
apiKey: { env: 'OPENAI_API_KEY' },
|
|
23
23
|
maxTokens: 4096,
|
|
24
24
|
}
|
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: create-agent
|
|
3
|
-
description: Create autonomous AI agents with inner tools, LLM providers, and multi-agent swarms. Use when building agents, configuring LLM adapters, adding inner tools, or setting up agent handoff.
|
|
4
|
-
tags: [agent, ai, llm, tools, autonomous]
|
|
5
|
-
parameters:
|
|
6
|
-
- name: llm-provider
|
|
7
|
-
description: LLM provider to use
|
|
8
|
-
type: string
|
|
9
|
-
default: anthropic
|
|
10
|
-
- name: name
|
|
11
|
-
description: Agent name
|
|
12
|
-
type: string
|
|
13
|
-
required: true
|
|
14
|
-
examples:
|
|
15
|
-
- scenario: Create a code review agent with GitHub tools
|
|
16
|
-
expected-outcome: Agent autonomously reviews PRs using inner tools
|
|
17
|
-
- scenario: Create a multi-agent swarm for complex workflows
|
|
18
|
-
expected-outcome: Agents hand off tasks to each other
|
|
19
|
-
priority: 8
|
|
20
|
-
visibility: both
|
|
21
|
-
license: Apache-2.0
|
|
22
|
-
metadata:
|
|
23
|
-
docs: https://docs.agentfront.dev/frontmcp/servers/agents
|
|
24
|
-
---
|
|
25
|
-
|
|
26
1
|
# Creating an Autonomous Agent
|
|
27
2
|
|
|
28
3
|
Agents are autonomous AI entities that use an LLM to reason, plan, and invoke inner tools to accomplish goals. In FrontMCP, agents are TypeScript classes that extend `AgentContext`, decorated with `@Agent`, and registered on a `@FrontMcp` server or inside an `@App`.
|
|
29
4
|
|
|
30
|
-
## When to Use
|
|
5
|
+
## When to Use This Skill
|
|
6
|
+
|
|
7
|
+
### Must Use
|
|
8
|
+
|
|
9
|
+
- Building an autonomous AI entity that uses LLM reasoning to decide which tools to call
|
|
10
|
+
- Orchestrating multi-step workflows where the agent plans, acts, and iterates toward a goal
|
|
11
|
+
- Creating multi-agent swarms with handoff between specialized agents
|
|
12
|
+
|
|
13
|
+
### Recommended
|
|
14
|
+
|
|
15
|
+
- Performing complex tasks that require chaining multiple inner tools with LLM-driven decisions
|
|
16
|
+
- Implementing structured multi-pass review (security pass, quality pass, synthesis)
|
|
17
|
+
- Composing nested sub-agents with different LLM configs for specialized subtasks
|
|
31
18
|
|
|
32
|
-
|
|
19
|
+
### Skip When
|
|
20
|
+
|
|
21
|
+
- You need a direct, deterministic function that executes a single action (see `create-tool`)
|
|
22
|
+
- You are building a reusable conversation template without autonomous execution (see `create-prompt`)
|
|
23
|
+
- You only need to expose readable data at a URI (see `create-resource`)
|
|
24
|
+
|
|
25
|
+
> **Decision:** Use this skill when the task requires autonomous LLM-driven reasoning, tool invocation, and iterative planning -- not a single deterministic action.
|
|
26
|
+
|
|
27
|
+
### @Agent vs @Tool Quick Comparison
|
|
33
28
|
|
|
34
29
|
| Aspect | @Agent | @Tool |
|
|
35
30
|
| --------------- | ------------------------------- | ---------------------------- |
|
|
@@ -50,8 +45,8 @@ import { z } from 'zod';
|
|
|
50
45
|
name: 'code_reviewer',
|
|
51
46
|
description: 'Reviews code changes and provides feedback',
|
|
52
47
|
llm: {
|
|
53
|
-
|
|
54
|
-
model: 'claude-sonnet-4-20250514',
|
|
48
|
+
provider: 'anthropic', // Any supported provider — 'anthropic', 'openai', etc.
|
|
49
|
+
model: 'claude-sonnet-4-20250514', // Any supported model for the chosen provider
|
|
55
50
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
56
51
|
},
|
|
57
52
|
inputSchema: {
|
|
@@ -110,7 +105,7 @@ The `llm` field is required and configures which LLM provider and model the agen
|
|
|
110
105
|
name: 'my_agent',
|
|
111
106
|
description: 'An agent with LLM config',
|
|
112
107
|
llm: {
|
|
113
|
-
|
|
108
|
+
provider: 'anthropic', // 'anthropic' or 'openai'
|
|
114
109
|
model: 'claude-sonnet-4-20250514',
|
|
115
110
|
apiKey: { env: 'ANTHROPIC_API_KEY' }, // read from env var
|
|
116
111
|
},
|
|
@@ -122,7 +117,7 @@ The `apiKey` field accepts either an object `{ env: 'ENV_VAR_NAME' }` to read fr
|
|
|
122
117
|
```typescript
|
|
123
118
|
// OpenAI example
|
|
124
119
|
llm: {
|
|
125
|
-
|
|
120
|
+
provider: 'openai',
|
|
126
121
|
model: 'gpt-4o',
|
|
127
122
|
apiKey: { env: 'OPENAI_API_KEY' },
|
|
128
123
|
},
|
|
@@ -139,7 +134,7 @@ Override `execute()` when you need custom orchestration logic:
|
|
|
139
134
|
name: 'structured_reviewer',
|
|
140
135
|
description: 'Reviews code with a structured multi-pass approach',
|
|
141
136
|
llm: {
|
|
142
|
-
|
|
137
|
+
provider: 'anthropic',
|
|
143
138
|
model: 'claude-sonnet-4-20250514',
|
|
144
139
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
145
140
|
},
|
|
@@ -193,7 +188,7 @@ Use `completion()` for a single LLM call that returns the full response, and `st
|
|
|
193
188
|
name: 'summarizer',
|
|
194
189
|
description: 'Summarizes text using LLM',
|
|
195
190
|
llm: {
|
|
196
|
-
|
|
191
|
+
provider: 'anthropic',
|
|
197
192
|
model: 'claude-sonnet-4-20250514',
|
|
198
193
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
199
194
|
},
|
|
@@ -287,7 +282,7 @@ class PostReviewCommentTool extends ToolContext {
|
|
|
287
282
|
name: 'pr_reviewer',
|
|
288
283
|
description: 'Autonomously reviews GitHub pull requests',
|
|
289
284
|
llm: {
|
|
290
|
-
|
|
285
|
+
provider: 'anthropic',
|
|
291
286
|
model: 'claude-sonnet-4-20250514',
|
|
292
287
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
293
288
|
},
|
|
@@ -315,7 +310,7 @@ Use `exports: { tools: [] }` to expose specific tools that the agent makes avail
|
|
|
315
310
|
name: 'data_pipeline',
|
|
316
311
|
description: 'Data processing pipeline agent',
|
|
317
312
|
llm: {
|
|
318
|
-
|
|
313
|
+
provider: 'openai',
|
|
319
314
|
model: 'gpt-4o',
|
|
320
315
|
apiKey: { env: 'OPENAI_API_KEY' },
|
|
321
316
|
},
|
|
@@ -333,7 +328,7 @@ Use the `agents` array to compose agents from smaller, specialized sub-agents. E
|
|
|
333
328
|
@Agent({
|
|
334
329
|
name: 'security_auditor',
|
|
335
330
|
description: 'Audits code for security vulnerabilities',
|
|
336
|
-
llm: {
|
|
331
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: { env: 'ANTHROPIC_API_KEY' } },
|
|
337
332
|
systemInstructions: 'Focus on OWASP Top 10 vulnerabilities.',
|
|
338
333
|
tools: [StaticAnalysisTool],
|
|
339
334
|
})
|
|
@@ -342,7 +337,7 @@ class SecurityAuditorAgent extends AgentContext {}
|
|
|
342
337
|
@Agent({
|
|
343
338
|
name: 'performance_auditor',
|
|
344
339
|
description: 'Audits code for performance issues',
|
|
345
|
-
llm: {
|
|
340
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: { env: 'ANTHROPIC_API_KEY' } },
|
|
346
341
|
systemInstructions: 'Focus on time complexity, memory leaks, and N+1 queries.',
|
|
347
342
|
tools: [ProfilerTool],
|
|
348
343
|
})
|
|
@@ -351,7 +346,7 @@ class PerformanceAuditorAgent extends AgentContext {}
|
|
|
351
346
|
@Agent({
|
|
352
347
|
name: 'code_auditor',
|
|
353
348
|
description: 'Comprehensive code auditor that delegates to specialized sub-agents',
|
|
354
|
-
llm: {
|
|
349
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: { env: 'ANTHROPIC_API_KEY' } },
|
|
355
350
|
inputSchema: {
|
|
356
351
|
repository: z.string().describe('Repository URL'),
|
|
357
352
|
branch: z.string().default('main').describe('Branch to audit'),
|
|
@@ -372,7 +367,7 @@ Swarm mode enables multi-agent handoff, where agents can transfer control to eac
|
|
|
372
367
|
@Agent({
|
|
373
368
|
name: 'triage_agent',
|
|
374
369
|
description: 'Triages incoming requests and hands off to specialists',
|
|
375
|
-
llm: {
|
|
370
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: { env: 'ANTHROPIC_API_KEY' } },
|
|
376
371
|
inputSchema: {
|
|
377
372
|
request: z.string().describe('The incoming user request'),
|
|
378
373
|
},
|
|
@@ -391,7 +386,7 @@ class TriageAgent extends AgentContext {}
|
|
|
391
386
|
@Agent({
|
|
392
387
|
name: 'billing_agent',
|
|
393
388
|
description: 'Handles billing and payment inquiries',
|
|
394
|
-
llm: {
|
|
389
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: { env: 'ANTHROPIC_API_KEY' } },
|
|
395
390
|
tools: [LookupInvoiceTool, ProcessRefundTool],
|
|
396
391
|
swarm: {
|
|
397
392
|
role: 'specialist',
|
|
@@ -413,7 +408,7 @@ const QuickSummarizer = agent({
|
|
|
413
408
|
name: 'quick_summarizer',
|
|
414
409
|
description: 'Summarizes text quickly',
|
|
415
410
|
llm: {
|
|
416
|
-
|
|
411
|
+
provider: 'anthropic',
|
|
417
412
|
model: 'claude-sonnet-4-20250514',
|
|
418
413
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
419
414
|
},
|
|
@@ -494,7 +489,7 @@ Protect agents with throttling controls:
|
|
|
494
489
|
name: 'expensive_agent',
|
|
495
490
|
description: 'An agent that performs expensive LLM operations',
|
|
496
491
|
llm: {
|
|
497
|
-
|
|
492
|
+
provider: 'anthropic',
|
|
498
493
|
model: 'claude-sonnet-4-20250514',
|
|
499
494
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
500
495
|
},
|
|
@@ -523,7 +518,7 @@ Agents can include their own providers and plugins for self-contained dependency
|
|
|
523
518
|
name: 'database_agent',
|
|
524
519
|
description: 'Agent that interacts with databases',
|
|
525
520
|
llm: {
|
|
526
|
-
|
|
521
|
+
provider: 'anthropic',
|
|
527
522
|
model: 'claude-sonnet-4-20250514',
|
|
528
523
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
529
524
|
},
|
|
@@ -548,7 +543,7 @@ Agents can include resources and prompts that are available within the agent's s
|
|
|
548
543
|
name: 'docs_agent',
|
|
549
544
|
description: 'Agent that manages documentation',
|
|
550
545
|
llm: {
|
|
551
|
-
|
|
546
|
+
provider: 'anthropic',
|
|
552
547
|
model: 'claude-sonnet-4-20250514',
|
|
553
548
|
apiKey: { env: 'ANTHROPIC_API_KEY' },
|
|
554
549
|
},
|
|
@@ -561,3 +556,46 @@ Agents can include resources and prompts that are available within the agent's s
|
|
|
561
556
|
})
|
|
562
557
|
class DocsAgent extends AgentContext {}
|
|
563
558
|
```
|
|
559
|
+
|
|
560
|
+
## Common Patterns
|
|
561
|
+
|
|
562
|
+
| Pattern | Correct | Incorrect | Why |
|
|
563
|
+
| ----------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
564
|
+
| LLM config | `llm: { provider: 'anthropic', model: '...', apiKey: { env: 'KEY' } }` | `llm: { provider: 'anthropic', apiKey: 'sk-hardcoded' }` | Environment variable references prevent leaking secrets in code |
|
|
565
|
+
| Inner tools vs exported | `tools: [...]` for agent-private; `exports: { tools: [...] }` for MCP-visible | Putting all tools in `tools` and expecting clients to see them | Inner tools are private to the agent; only exported tools appear in MCP listing |
|
|
566
|
+
| Custom execute | Override `execute()` for multi-pass orchestration | Putting all logic in system instructions | Custom `execute()` gives structured control over completion calls and stages |
|
|
567
|
+
| Sub-agents | Use `agents: [SubAgent]` for composition | Calling another agent's `execute()` directly | The `agents` array enables proper lifecycle, scope isolation, and handoff |
|
|
568
|
+
| Swarm handoff | Use `swarm.handoff` with `agent` name and `condition` | Manually routing between agents in `execute()` | Swarm config enables declarative, LLM-driven handoff between agents |
|
|
569
|
+
|
|
570
|
+
## Verification Checklist
|
|
571
|
+
|
|
572
|
+
### Configuration
|
|
573
|
+
|
|
574
|
+
- [ ] Agent class extends `AgentContext` and has `@Agent` decorator with `name`, `description`, and `llm`
|
|
575
|
+
- [ ] `inputSchema` is defined with Zod raw shape for input validation
|
|
576
|
+
- [ ] Inner tools in `tools` array are valid `@Tool` classes
|
|
577
|
+
- [ ] Agent is registered in `agents` array of `@App` or `@FrontMcp`
|
|
578
|
+
- [ ] API key uses `{ env: 'VAR_NAME' }` pattern, not hardcoded strings
|
|
579
|
+
|
|
580
|
+
### Runtime
|
|
581
|
+
|
|
582
|
+
- [ ] Agent appears in MCP tool listing (agents surface as callable tools)
|
|
583
|
+
- [ ] LLM adapter connects successfully to the configured provider
|
|
584
|
+
- [ ] Inner tools are invoked correctly during the agent loop
|
|
585
|
+
- [ ] `this.completion()` and `this.streamCompletion()` return valid responses
|
|
586
|
+
- [ ] Swarm handoff transfers control to the correct specialist agent
|
|
587
|
+
|
|
588
|
+
## Troubleshooting
|
|
589
|
+
|
|
590
|
+
| Problem | Cause | Solution |
|
|
591
|
+
| ----------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
592
|
+
| Agent not appearing in tool listing | Not registered in `agents` array | Add agent class to `@App` or `@FrontMcp` `agents` array |
|
|
593
|
+
| LLM authentication error | API key not set or incorrect env variable | Verify the environment variable name in `apiKey: { env: '...' }` is set |
|
|
594
|
+
| Inner tools not being called | Tools not listed in `tools` array of `@Agent` | Add tool classes to the `tools` field in the `@Agent` decorator |
|
|
595
|
+
| Agent times out | No timeout or rate limit configured | Add `timeout: { executeMs: 120_000 }` and `rateLimit` to `@Agent` options |
|
|
596
|
+
| Swarm handoff fails | Target agent name does not match any registered agent | Ensure `handoff.agent` matches the `name` of a registered agent in the same scope |
|
|
597
|
+
|
|
598
|
+
## Reference
|
|
599
|
+
|
|
600
|
+
- [Agents Documentation](https://docs.agentfront.dev/frontmcp/servers/agents)
|
|
601
|
+
- Related skills: `create-tool`, `create-provider`, `create-prompt`, `create-resource`
|
package/catalog/{development/create-job/SKILL.md → frontmcp-development/references/create-job.md}
RENAMED
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: create-job
|
|
3
|
-
description: Create long-running jobs with retry policies, progress tracking, and permission controls. Use when building background tasks, data processing pipelines, or scheduled operations.
|
|
4
|
-
tags: [job, background, retry, progress, long-running]
|
|
5
|
-
priority: 6
|
|
6
|
-
visibility: both
|
|
7
|
-
license: Apache-2.0
|
|
8
|
-
metadata:
|
|
9
|
-
docs: https://docs.agentfront.dev/frontmcp/servers/jobs
|
|
10
|
-
---
|
|
11
|
-
|
|
12
1
|
# Creating Jobs
|
|
13
2
|
|
|
14
3
|
Jobs are long-running background tasks with built-in retry policies, progress tracking, and permission controls. Unlike tools (which execute synchronously within a request), jobs run asynchronously and persist their state across retries and restarts.
|
|
15
4
|
|
|
16
|
-
## When to Use
|
|
5
|
+
## When to Use This Skill
|
|
6
|
+
|
|
7
|
+
### Must Use
|
|
8
|
+
|
|
9
|
+
- Running work that takes longer than a request cycle (ETL pipelines, large imports)
|
|
10
|
+
- Tasks that need automatic retry with exponential backoff on failure
|
|
11
|
+
- Background operations that must track and report progress over time
|
|
12
|
+
|
|
13
|
+
### Recommended
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
- Scheduled maintenance tasks or periodic data synchronization
|
|
16
|
+
- Operations requiring permission controls (role-based, scope-based access)
|
|
17
|
+
- Work that must persist state across retries and server restarts
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
- File imports and exports
|
|
22
|
-
- Report generation
|
|
23
|
-
- Scheduled maintenance tasks
|
|
24
|
-
- External API synchronization
|
|
19
|
+
### Skip When
|
|
25
20
|
|
|
26
|
-
|
|
21
|
+
- The work completes in a few seconds and needs no retry or progress tracking (see `create-tool`)
|
|
22
|
+
- You need to expose read-only data at a URI (see `create-resource`)
|
|
23
|
+
- The task requires autonomous LLM reasoning rather than a deterministic pipeline (see `create-agent`)
|
|
24
|
+
|
|
25
|
+
> **Decision:** Use this skill when you need a long-running background task with retry policies, progress tracking, or permission controls.
|
|
27
26
|
|
|
28
27
|
## Class-Based Pattern
|
|
29
28
|
|
|
@@ -564,3 +563,46 @@ class DataApp {}
|
|
|
564
563
|
})
|
|
565
564
|
class DataServer {}
|
|
566
565
|
```
|
|
566
|
+
|
|
567
|
+
## Common Patterns
|
|
568
|
+
|
|
569
|
+
| Pattern | Correct | Incorrect | Why |
|
|
570
|
+
| ----------------- | ------------------------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------------------------------------ |
|
|
571
|
+
| Progress tracking | `this.progress(50, 100, 'Processing batch 5')` | Not reporting progress | Progress is persisted and queryable; essential for long-running visibility |
|
|
572
|
+
| Retry config | `retry: { maxAttempts: 3, backoffMs: 2000, backoffMultiplier: 2 }` | Implementing retry logic manually in `execute()` | Framework handles retry with exponential backoff and attempt tracking |
|
|
573
|
+
| Attempt awareness | Check `this.attempt` for retry-specific logic | Ignoring attempt number | `this.attempt` is 1-based; use it to log retry context or adjust behavior |
|
|
574
|
+
| Job logging | `this.log('message')` for persistent, queryable logs | Using `console.log()` | `this.log()` persists with job state; `console.log` is ephemeral |
|
|
575
|
+
| Permissions | Use `permissions: { roles: [...], scopes: [...] }` declaratively | Checking roles manually inside `execute()` | Declarative permissions are enforced before execution and are self-documenting |
|
|
576
|
+
|
|
577
|
+
## Verification Checklist
|
|
578
|
+
|
|
579
|
+
### Configuration
|
|
580
|
+
|
|
581
|
+
- [ ] Job class extends `JobContext` and implements `execute(input)`
|
|
582
|
+
- [ ] `@Job` decorator has `name`, `inputSchema`, and `outputSchema`
|
|
583
|
+
- [ ] `retry` policy is configured if the job may fail transiently
|
|
584
|
+
- [ ] `timeout` is set appropriately for the expected execution duration
|
|
585
|
+
- [ ] Job is registered in `jobs` array of `@App`
|
|
586
|
+
|
|
587
|
+
### Runtime
|
|
588
|
+
|
|
589
|
+
- [ ] `jobs.enabled: true` is set in `@FrontMcp` configuration with a store
|
|
590
|
+
- [ ] Job executes and returns output matching `outputSchema`
|
|
591
|
+
- [ ] Progress is reported and queryable during execution
|
|
592
|
+
- [ ] Retry fires with correct backoff delays on transient failures
|
|
593
|
+
- [ ] Permissions block unauthorized users before execution starts
|
|
594
|
+
|
|
595
|
+
## Troubleshooting
|
|
596
|
+
|
|
597
|
+
| Problem | Cause | Solution |
|
|
598
|
+
| -------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
599
|
+
| Job not activated | `jobs.enabled` not set to `true` in `@FrontMcp` | Add `jobs: { enabled: true, store: { ... } }` to `@FrontMcp` config |
|
|
600
|
+
| Job fails without retrying | No `retry` policy configured | Add `retry: { maxAttempts: 3, backoffMs: 2000 }` to `@Job` options |
|
|
601
|
+
| Progress not visible | Not calling `this.progress()` during execution | Add `this.progress(pct, total, message)` calls at each stage |
|
|
602
|
+
| Job times out unexpectedly | Default 5-minute timeout too short | Set `timeout` in `@Job` to a higher value (e.g., `600000` for 10 minutes) |
|
|
603
|
+
| Permission denied error | User lacks required roles or scopes | Verify user has one of the `roles` and all `scopes` defined in `permissions` |
|
|
604
|
+
|
|
605
|
+
## Reference
|
|
606
|
+
|
|
607
|
+
- [Jobs Documentation](https://docs.agentfront.dev/frontmcp/servers/jobs)
|
|
608
|
+
- Related skills: `create-tool`, `create-provider`, `create-agent`, `create-workflow`
|
|
@@ -1,18 +1,29 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: create-plugin-hooks
|
|
3
|
-
description: Create plugins with flow lifecycle hooks using @Will, @Did, @Stage, and @Around decorators. Use when intercepting tool calls, adding logging, modifying request/response, or implementing cross-cutting middleware.
|
|
4
|
-
tags: [plugin, hooks, will, did, stage, around, flow, middleware]
|
|
5
|
-
priority: 7
|
|
6
|
-
visibility: both
|
|
7
|
-
license: Apache-2.0
|
|
8
|
-
metadata:
|
|
9
|
-
docs: https://docs.agentfront.dev/frontmcp/plugins/creating-plugins
|
|
10
|
-
---
|
|
11
|
-
|
|
12
1
|
# Creating Plugins with Flow Lifecycle Hooks
|
|
13
2
|
|
|
14
3
|
Plugins intercept and extend FrontMCP flows using lifecycle hook decorators. Every flow (tool calls, resource reads, prompt gets, etc.) is composed of **stages**, and hooks let you run logic before, after, around, or instead of any stage.
|
|
15
4
|
|
|
5
|
+
## When to Use This Skill
|
|
6
|
+
|
|
7
|
+
### Must Use
|
|
8
|
+
|
|
9
|
+
- Adding before/after logic to tool execution (logging, metrics, input enrichment)
|
|
10
|
+
- Implementing authorization checks that intercept flows before they reach the tool
|
|
11
|
+
- Wrapping stage execution with caching, retry, or timing logic via `@Around`
|
|
12
|
+
|
|
13
|
+
### Recommended
|
|
14
|
+
|
|
15
|
+
- Replacing a built-in stage entirely with custom logic using `@Stage`
|
|
16
|
+
- Adding hooks directly on a `@Tool` class for tool-specific pre/post processing
|
|
17
|
+
- Filtering hook execution by tool name or context properties using `filter` predicates
|
|
18
|
+
|
|
19
|
+
### Skip When
|
|
20
|
+
|
|
21
|
+
- You need providers, context extensions, or contributed tools (see `create-plugin`)
|
|
22
|
+
- You want to use an existing official plugin that already provides hooks (see `official-plugins`)
|
|
23
|
+
- You are building a simple tool with no cross-cutting concerns (see `create-tool`)
|
|
24
|
+
|
|
25
|
+
> **Decision:** Use this skill when you need to intercept or wrap flow stages with `@Will`, `@Did`, `@Around`, or `@Stage` decorators.
|
|
26
|
+
|
|
16
27
|
## Hook Decorator Types
|
|
17
28
|
|
|
18
29
|
FrontMCP provides four hook decorators obtained via `FlowHooksOf(flowName)`:
|
|
@@ -280,3 +291,44 @@ parseInput → findTool → checkToolAuthorization → createToolCallContext
|
|
|
280
291
|
```
|
|
281
292
|
|
|
282
293
|
Any stage can have `@Will`, `@Did`, `@Stage`, or `@Around` hooks.
|
|
294
|
+
|
|
295
|
+
## Common Patterns
|
|
296
|
+
|
|
297
|
+
| Pattern | Correct | Incorrect | Why |
|
|
298
|
+
| --------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
299
|
+
| Hook decorator source | `const { Will, Did } = ToolHook;` or `FlowHooksOf('tools:call-tool')` | Importing `Will` directly from `@frontmcp/sdk` | Decorators must be bound to a specific flow via `FlowHooksOf` or pre-built exports |
|
|
300
|
+
| Hook priority | `@Will('execute', { priority: 100 })` for early hooks | Relying on array order without priority | Multiple hooks on the same stage need explicit priority; higher runs first |
|
|
301
|
+
| Around next() | `const result = await next(); return result;` | Forgetting to call `next()` in `@Around` | Omitting `next()` silently skips the wrapped stage and all downstream hooks |
|
|
302
|
+
| Filter predicate | `filter: (ctx) => ctx.toolName !== 'health_check'` | Checking tool name inside the hook body and returning early | Filters skip the hook cleanly; returning early may leave state inconsistent |
|
|
303
|
+
| Tool-level hooks | `@Will('execute')` on a `@Tool` class (scoped to that tool) | `@Will('execute')` on a `@Plugin` class expecting tool-scoped behavior | Plugin hooks fire for all tools; tool-level hooks fire only for that tool |
|
|
304
|
+
|
|
305
|
+
## Verification Checklist
|
|
306
|
+
|
|
307
|
+
### Configuration
|
|
308
|
+
|
|
309
|
+
- [ ] Hook decorator is obtained from `FlowHooksOf(flowName)` or a pre-built export (e.g., `ToolHook`)
|
|
310
|
+
- [ ] Stage name matches an actual stage in the targeted flow (e.g., `execute`, `validateInput`)
|
|
311
|
+
- [ ] Plugin with hooks is registered in `plugins` array of `@App` or `@FrontMcp`
|
|
312
|
+
|
|
313
|
+
### Runtime
|
|
314
|
+
|
|
315
|
+
- [ ] `@Will` hook fires before the targeted stage
|
|
316
|
+
- [ ] `@Did` hook fires after the targeted stage completes
|
|
317
|
+
- [ ] `@Around` hook calls `next()` and the wrapped stage executes
|
|
318
|
+
- [ ] `@Stage` replacement returns a valid response for the flow
|
|
319
|
+
- [ ] Hook `filter` correctly skips invocations for excluded tools
|
|
320
|
+
|
|
321
|
+
## Troubleshooting
|
|
322
|
+
|
|
323
|
+
| Problem | Cause | Solution |
|
|
324
|
+
| --------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
|
|
325
|
+
| Hook never fires | Plugin not registered in `plugins` array | Add plugin class to `@App` or `@FrontMcp` `plugins` array |
|
|
326
|
+
| Hook fires for wrong flow | Used wrong flow name in `FlowHooksOf` | Verify flow name matches (e.g., `'tools:call-tool'` not `'tool:call'`) |
|
|
327
|
+
| `@Around` skips the stage entirely | `next()` not called inside the around handler | Always `await next()` to execute the wrapped stage |
|
|
328
|
+
| Multiple hooks execute in wrong order | Priorities not set or conflicting | Set explicit `priority` values; higher numbers execute first |
|
|
329
|
+
| `@Stage` replacement causes downstream errors | Return value shape does not match stage contract | Ensure the return matches what the next stage expects (e.g., MCP response format) |
|
|
330
|
+
|
|
331
|
+
## Reference
|
|
332
|
+
|
|
333
|
+
- [Plugin Hooks Documentation](https://docs.agentfront.dev/frontmcp/plugins/creating-plugins)
|
|
334
|
+
- Related skills: `create-plugin`, `official-plugins`, `create-tool`
|