@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.
Files changed (65) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +135 -0
  3. package/catalog/TEMPLATE.md +49 -0
  4. package/catalog/adapters/create-adapter/SKILL.md +127 -0
  5. package/catalog/adapters/official-adapters/SKILL.md +136 -0
  6. package/catalog/auth/configure-auth/SKILL.md +250 -0
  7. package/catalog/auth/configure-auth/references/auth-modes.md +77 -0
  8. package/catalog/auth/configure-session/SKILL.md +201 -0
  9. package/catalog/config/configure-elicitation/SKILL.md +136 -0
  10. package/catalog/config/configure-http/SKILL.md +167 -0
  11. package/catalog/config/configure-throttle/SKILL.md +189 -0
  12. package/catalog/config/configure-throttle/references/guard-config.md +68 -0
  13. package/catalog/config/configure-transport/SKILL.md +151 -0
  14. package/catalog/config/configure-transport/references/protocol-presets.md +57 -0
  15. package/catalog/deployment/build-for-browser/SKILL.md +95 -0
  16. package/catalog/deployment/build-for-cli/SKILL.md +100 -0
  17. package/catalog/deployment/build-for-sdk/SKILL.md +218 -0
  18. package/catalog/deployment/deploy-to-cloudflare/SKILL.md +192 -0
  19. package/catalog/deployment/deploy-to-lambda/SKILL.md +304 -0
  20. package/catalog/deployment/deploy-to-node/SKILL.md +229 -0
  21. package/catalog/deployment/deploy-to-node/references/Dockerfile.example +45 -0
  22. package/catalog/deployment/deploy-to-vercel/SKILL.md +196 -0
  23. package/catalog/deployment/deploy-to-vercel/references/vercel.json.example +60 -0
  24. package/catalog/development/create-agent/SKILL.md +563 -0
  25. package/catalog/development/create-agent/references/llm-config.md +46 -0
  26. package/catalog/development/create-job/SKILL.md +566 -0
  27. package/catalog/development/create-prompt/SKILL.md +400 -0
  28. package/catalog/development/create-provider/SKILL.md +233 -0
  29. package/catalog/development/create-resource/SKILL.md +437 -0
  30. package/catalog/development/create-skill/SKILL.md +526 -0
  31. package/catalog/development/create-skill-with-tools/SKILL.md +579 -0
  32. package/catalog/development/create-tool/SKILL.md +418 -0
  33. package/catalog/development/create-tool/references/output-schema-types.md +56 -0
  34. package/catalog/development/create-tool/references/tool-annotations.md +34 -0
  35. package/catalog/development/create-workflow/SKILL.md +709 -0
  36. package/catalog/development/decorators-guide/SKILL.md +598 -0
  37. package/catalog/plugins/create-plugin/SKILL.md +336 -0
  38. package/catalog/plugins/create-plugin-hooks/SKILL.md +282 -0
  39. package/catalog/plugins/official-plugins/SKILL.md +667 -0
  40. package/catalog/setup/frontmcp-skills-usage/SKILL.md +200 -0
  41. package/catalog/setup/multi-app-composition/SKILL.md +358 -0
  42. package/catalog/setup/nx-workflow/SKILL.md +357 -0
  43. package/catalog/setup/project-structure-nx/SKILL.md +186 -0
  44. package/catalog/setup/project-structure-standalone/SKILL.md +153 -0
  45. package/catalog/setup/setup-project/SKILL.md +493 -0
  46. package/catalog/setup/setup-redis/SKILL.md +385 -0
  47. package/catalog/setup/setup-sqlite/SKILL.md +359 -0
  48. package/catalog/skills-manifest.json +414 -0
  49. package/catalog/testing/setup-testing/SKILL.md +539 -0
  50. package/catalog/testing/setup-testing/references/test-auth.md +88 -0
  51. package/catalog/testing/setup-testing/references/test-browser-build.md +57 -0
  52. package/catalog/testing/setup-testing/references/test-cli-binary.md +48 -0
  53. package/catalog/testing/setup-testing/references/test-direct-client.md +62 -0
  54. package/catalog/testing/setup-testing/references/test-e2e-handler.md +51 -0
  55. package/catalog/testing/setup-testing/references/test-tool-unit.md +41 -0
  56. package/package.json +34 -0
  57. package/src/index.d.ts +3 -0
  58. package/src/index.js +16 -0
  59. package/src/index.js.map +1 -0
  60. package/src/loader.d.ts +46 -0
  61. package/src/loader.js +75 -0
  62. package/src/loader.js.map +1 -0
  63. package/src/manifest.d.ts +81 -0
  64. package/src/manifest.js +26 -0
  65. package/src/manifest.js.map +1 -0
@@ -0,0 +1,418 @@
1
+ ---
2
+ name: create-tool
3
+ description: Create and register an MCP tool with Zod input validation and typed output. Use when building tools, defining input schemas, adding output validation, or registering tools in an app.
4
+ tags: [tools, mcp, zod, schema, decorator]
5
+ tools:
6
+ - name: create_tool
7
+ purpose: Scaffold a new tool class
8
+ parameters:
9
+ - name: name
10
+ description: Tool name in snake_case
11
+ type: string
12
+ required: true
13
+ examples:
14
+ - scenario: Create a calculator tool with add operation
15
+ expected-outcome: Tool registered and callable via MCP
16
+ - scenario: Create a tool with DI and error handling
17
+ expected-outcome: Tool using providers and proper error classes
18
+ priority: 10
19
+ visibility: both
20
+ license: Apache-2.0
21
+ metadata:
22
+ docs: https://docs.agentfront.dev/frontmcp/servers/tools
23
+ ---
24
+
25
+ # Creating an MCP Tool
26
+
27
+ Tools are the primary way to expose executable actions to AI clients in the MCP protocol. In FrontMCP, tools are TypeScript classes that extend `ToolContext`, decorated with `@Tool`, and registered on a `@FrontMcp` server or inside an `@App`.
28
+
29
+ ## When to Use @Tool
30
+
31
+ Use `@Tool` when you need to expose an action that an AI client can invoke. Tools accept validated input, perform work (database queries, API calls, computations), and return structured results. Every tool goes through Zod-based input validation before `execute()` runs.
32
+
33
+ ## Class-Based Pattern
34
+
35
+ Create a class extending `ToolContext<In, Out>` and implement the `execute(input: In): Promise<Out>` method. The `@Tool` decorator requires at minimum a `name` and an `inputSchema`.
36
+
37
+ ```typescript
38
+ import { Tool, ToolContext } from '@frontmcp/sdk';
39
+ import { z } from 'zod';
40
+
41
+ @Tool({
42
+ name: 'greet_user',
43
+ description: 'Greet a user by name',
44
+ inputSchema: {
45
+ name: z.string().describe('The name of the user to greet'),
46
+ },
47
+ })
48
+ class GreetUserTool extends ToolContext {
49
+ async execute(input: { name: string }) {
50
+ return `Hello, ${input.name}!`;
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### Available Context Methods and Properties
56
+
57
+ `ToolContext` extends `ExecutionContextBase`, which provides:
58
+
59
+ **Methods:**
60
+
61
+ - `execute(input: In): Promise<Out>` -- the main method you implement
62
+ - `this.get(token)` -- resolve a dependency from DI (throws if not found)
63
+ - `this.tryGet(token)` -- resolve a dependency from DI (returns `undefined` if not found)
64
+ - `this.fail(err)` -- abort execution, triggers error flow (never returns)
65
+ - `this.mark(stage)` -- set the active execution stage for debugging/tracking
66
+ - `this.fetch(input, init?)` -- HTTP fetch with context propagation
67
+ - `this.notify(message, level?)` -- send a log-level notification to the client
68
+ - `this.respondProgress(value, total?)` -- send a progress notification to the client
69
+
70
+ **Properties:**
71
+
72
+ - `this.input` -- the validated input object
73
+ - `this.output` -- the output (available after execute)
74
+ - `this.metadata` -- tool metadata from the decorator
75
+ - `this.scope` -- the current scope instance
76
+ - `this.context` -- the execution context
77
+
78
+ ## Input Schema: Zod Raw Shapes
79
+
80
+ The `inputSchema` accepts a **Zod raw shape** -- a plain object mapping field names to Zod types. Do NOT wrap it in `z.object()`. The framework wraps it internally.
81
+
82
+ ```typescript
83
+ @Tool({
84
+ name: 'search_documents',
85
+ description: 'Search documents by query and optional filters',
86
+ inputSchema: {
87
+ // This is a raw shape, NOT z.object({...})
88
+ query: z.string().min(1).describe('Search query'),
89
+ limit: z.number().int().min(1).max(100).default(10).describe('Max results'),
90
+ category: z.enum(['blog', 'docs', 'api']).optional().describe('Filter by category'),
91
+ },
92
+ })
93
+ class SearchDocumentsTool extends ToolContext {
94
+ async execute(input: { query: string; limit: number; category?: 'blog' | 'docs' | 'api' }) {
95
+ // input is already validated by Zod before execute() is called
96
+ return { results: [], total: 0 };
97
+ }
98
+ }
99
+ ```
100
+
101
+ The `execute()` parameter type must match the inferred output of `z.object(inputSchema)`. Validated input is also available via `this.input`.
102
+
103
+ ## Output Schema (Recommended Best Practice)
104
+
105
+ **Always define `outputSchema` for every tool.** This is a best practice for three critical reasons:
106
+
107
+ 1. **Output validation** -- Prevents data leaks by ensuring your tool only returns fields you explicitly declare. Without `outputSchema`, any data in the return value passes through unvalidated, risking accidental exposure of sensitive fields (internal IDs, tokens, PII).
108
+ 2. **CodeCall plugin compatibility** -- The CodeCall plugin uses `outputSchema` to understand what a tool returns, enabling correct VM-based orchestration and pass-by-reference. Tools without `outputSchema` degrade CodeCall's ability to chain results.
109
+ 3. **Type safety** -- The `Out` generic on `ToolContext<In, Out>` is inferred from `outputSchema`, giving you compile-time guarantees that `execute()` returns the correct shape.
110
+
111
+ ```typescript
112
+ @Tool({
113
+ name: 'get_weather',
114
+ description: 'Get current weather for a location',
115
+ inputSchema: {
116
+ city: z.string().describe('City name'),
117
+ },
118
+ // Always define outputSchema to validate output and prevent data leaks
119
+ outputSchema: {
120
+ temperature: z.number(),
121
+ unit: z.enum(['celsius', 'fahrenheit']),
122
+ description: z.string(),
123
+ },
124
+ })
125
+ class GetWeatherTool extends ToolContext {
126
+ async execute(input: { city: string }): Promise<{
127
+ temperature: number;
128
+ unit: 'celsius' | 'fahrenheit';
129
+ description: string;
130
+ }> {
131
+ const response = await this.fetch(`https://api.weather.example.com/v1/current?city=${input.city}`);
132
+ const weather = await response.json();
133
+ // Only temperature, unit, and description are returned.
134
+ // Any extra fields from the API (e.g., internalId, apiKey) are stripped by outputSchema validation.
135
+ return {
136
+ temperature: weather.temp,
137
+ unit: 'celsius',
138
+ description: weather.summary,
139
+ };
140
+ }
141
+ }
142
+ ```
143
+
144
+ **Why not omit outputSchema?** Without it:
145
+
146
+ - The tool returns raw unvalidated data — any field your code accidentally includes leaks to the client
147
+ - CodeCall cannot infer return types for chaining tool calls in VM scripts
148
+ - No compile-time type checking on the return value
149
+
150
+ Supported `outputSchema` types:
151
+
152
+ - **Zod raw shapes** (recommended): `{ field: z.string(), count: z.number() }` — structured JSON output with validation
153
+ - **Zod schemas**: `z.object(...)`, `z.array(...)`, `z.union([...])` — for complex types
154
+ - **Primitive literals**: `'string'`, `'number'`, `'boolean'`, `'date'` — for simple returns
155
+ - **Media types**: `'image'`, `'audio'`, `'resource'`, `'resource_link'` — for binary/link content
156
+ - **Arrays**: `['string', 'image']` for multi-content responses
157
+
158
+ ## Dependency Injection
159
+
160
+ Access providers registered in the scope using `this.get(token)` (throws if not found) or `this.tryGet(token)` (returns `undefined` if not found).
161
+
162
+ ```typescript
163
+ import type { Token } from '@frontmcp/di';
164
+
165
+ interface DatabaseService {
166
+ query(sql: string, params: unknown[]): Promise<unknown[]>;
167
+ }
168
+ const DATABASE: Token<DatabaseService> = Symbol('database');
169
+
170
+ @Tool({
171
+ name: 'run_query',
172
+ description: 'Execute a database query',
173
+ inputSchema: {
174
+ sql: z.string().describe('SQL query to execute'),
175
+ },
176
+ })
177
+ class RunQueryTool extends ToolContext {
178
+ async execute(input: { sql: string }) {
179
+ const db = this.get(DATABASE); // throws if DATABASE not registered
180
+ const rows = await db.query(input.sql, []);
181
+ return { rows, count: rows.length };
182
+ }
183
+ }
184
+ ```
185
+
186
+ Use `this.tryGet(token)` when the dependency is optional:
187
+
188
+ ```typescript
189
+ async execute(input: { data: string }) {
190
+ const cache = this.tryGet(CACHE); // returns undefined if not registered
191
+ if (cache) {
192
+ const cached = await cache.get(input.data);
193
+ if (cached) return cached;
194
+ }
195
+ // proceed without cache
196
+ }
197
+ ```
198
+
199
+ ## Error Handling
200
+
201
+ Use `this.fail(err)` to abort execution and trigger the error flow. The method throws internally and never returns.
202
+
203
+ ```typescript
204
+ @Tool({
205
+ name: 'delete_record',
206
+ description: 'Delete a record by ID',
207
+ inputSchema: {
208
+ id: z.string().uuid().describe('Record UUID'),
209
+ },
210
+ })
211
+ class DeleteRecordTool extends ToolContext {
212
+ async execute(input: { id: string }) {
213
+ const record = await this.findRecord(input.id);
214
+ if (!record) {
215
+ this.fail(new Error(`Record not found: ${input.id}`));
216
+ }
217
+
218
+ await this.deleteRecord(record);
219
+ return `Record ${input.id} deleted successfully`;
220
+ }
221
+
222
+ private async findRecord(id: string) {
223
+ return null;
224
+ }
225
+
226
+ private async deleteRecord(record: unknown) {
227
+ // delete implementation
228
+ }
229
+ }
230
+ ```
231
+
232
+ For MCP-specific errors, use error classes with JSON-RPC codes:
233
+
234
+ ```typescript
235
+ import { ResourceNotFoundError, PublicMcpError, MCP_ERROR_CODES } from '@frontmcp/sdk';
236
+
237
+ this.fail(new ResourceNotFoundError(`Record ${input.id}`));
238
+ ```
239
+
240
+ ## Progress and Notifications
241
+
242
+ Use `this.notify(message, level?)` to send log-level notifications and `this.respondProgress(value, total?)` to send progress updates to the client.
243
+
244
+ ```typescript
245
+ @Tool({
246
+ name: 'batch_process',
247
+ description: 'Process a batch of items',
248
+ inputSchema: {
249
+ items: z.array(z.string()).min(1).describe('Items to process'),
250
+ },
251
+ })
252
+ class BatchProcessTool extends ToolContext {
253
+ async execute(input: { items: string[] }) {
254
+ this.mark('validation');
255
+ this.validateItems(input.items);
256
+
257
+ this.mark('processing');
258
+ const results: string[] = [];
259
+ for (let i = 0; i < input.items.length; i++) {
260
+ await this.respondProgress(i + 1, input.items.length);
261
+ const result = await this.processItem(input.items[i]);
262
+ results.push(result);
263
+ }
264
+
265
+ this.mark('complete');
266
+ await this.notify(`Processed ${results.length} items`, 'info');
267
+ return { processed: results.length, results };
268
+ }
269
+
270
+ private validateItems(items: string[]) {
271
+ /* ... */
272
+ }
273
+ private async processItem(item: string): Promise<string> {
274
+ return item;
275
+ }
276
+ }
277
+ ```
278
+
279
+ ## Tool Annotations
280
+
281
+ Provide behavioral hints to clients using `annotations`. These hints help clients decide how to present and gate tool usage.
282
+
283
+ ```typescript
284
+ @Tool({
285
+ name: 'web_search',
286
+ description: 'Search the web',
287
+ inputSchema: {
288
+ query: z.string(),
289
+ },
290
+ annotations: {
291
+ title: 'Web Search',
292
+ readOnlyHint: true,
293
+ openWorldHint: true,
294
+ },
295
+ })
296
+ class WebSearchTool extends ToolContext {
297
+ async execute(input: { query: string }) {
298
+ return await this.performSearch(input.query);
299
+ }
300
+
301
+ private async performSearch(query: string) {
302
+ return [];
303
+ }
304
+ }
305
+ ```
306
+
307
+ Annotation fields:
308
+
309
+ - `title` -- Human-readable title for the tool
310
+ - `readOnlyHint` -- Tool does not modify its environment (default: false)
311
+ - `destructiveHint` -- Tool may perform destructive updates (default: true, meaningful only when readOnlyHint is false)
312
+ - `idempotentHint` -- Calling repeatedly with same args has no additional effect (default: false)
313
+ - `openWorldHint` -- Tool interacts with external entities (default: true)
314
+
315
+ ## Function-Style Builder
316
+
317
+ For simple tools that do not need a class, use the `tool()` function builder. It returns a value you register the same way as a class tool.
318
+
319
+ ```typescript
320
+ import { tool } from '@frontmcp/sdk';
321
+ import { z } from 'zod';
322
+
323
+ const AddNumbers = tool({
324
+ name: 'add_numbers',
325
+ description: 'Add two numbers',
326
+ inputSchema: {
327
+ a: z.number().describe('First number'),
328
+ b: z.number().describe('Second number'),
329
+ },
330
+ outputSchema: 'number',
331
+ })((input) => {
332
+ return input.a + input.b;
333
+ });
334
+ ```
335
+
336
+ The callback receives `(input, ctx)` where `ctx` provides access to the same context methods (`get`, `tryGet`, `fail`, `mark`, `fetch`, `notify`, `respondProgress`).
337
+
338
+ Register it the same way as a class tool: `tools: [AddNumbers]`.
339
+
340
+ ## Remote and ESM Loading
341
+
342
+ Load tools from external modules or remote URLs without importing them directly.
343
+
344
+ **ESM loading** -- load a tool from an ES module:
345
+
346
+ ```typescript
347
+ const RemoteTool = Tool.esm('@my-org/tools@^1.0.0', 'MyTool', {
348
+ description: 'A tool loaded from an ES module',
349
+ });
350
+ ```
351
+
352
+ **Remote loading** -- load a tool from a remote URL:
353
+
354
+ ```typescript
355
+ const CloudTool = Tool.remote('https://example.com/tools/cloud-tool', 'CloudTool', {
356
+ description: 'A tool loaded from a remote server',
357
+ });
358
+ ```
359
+
360
+ Both return values that can be registered in `tools: [RemoteTool, CloudTool]`.
361
+
362
+ ## Registration
363
+
364
+ Add tool classes (or function-style tools) to the `tools` array in `@FrontMcp` or `@App`.
365
+
366
+ ```typescript
367
+ import { FrontMcp, App } from '@frontmcp/sdk';
368
+
369
+ @App({
370
+ name: 'my-app',
371
+ tools: [GreetUserTool, SearchDocumentsTool, AddNumbers],
372
+ })
373
+ class MyApp {}
374
+
375
+ @FrontMcp({
376
+ info: { name: 'my-server', version: '1.0.0' },
377
+ apps: [MyApp],
378
+ tools: [RunQueryTool], // can also register tools directly on the server
379
+ })
380
+ class MyServer {}
381
+ ```
382
+
383
+ ## Nx Generator
384
+
385
+ Scaffold a new tool using the Nx generator:
386
+
387
+ ```bash
388
+ nx generate @frontmcp/nx:tool
389
+ ```
390
+
391
+ This creates the tool file, spec file, and updates barrel exports.
392
+
393
+ ## Rate Limiting and Concurrency
394
+
395
+ Protect tools with throttling controls:
396
+
397
+ ```typescript
398
+ @Tool({
399
+ name: 'expensive_operation',
400
+ description: 'An expensive operation that should be rate limited',
401
+ inputSchema: {
402
+ data: z.string(),
403
+ },
404
+ rateLimit: { maxRequests: 10, windowMs: 60_000 },
405
+ concurrency: { maxConcurrent: 2 },
406
+ timeout: { executeMs: 30_000 },
407
+ })
408
+ class ExpensiveOperationTool extends ToolContext {
409
+ async execute(input: { data: string }) {
410
+ // At most 10 calls per minute, 2 concurrent, 30s timeout
411
+ return await this.heavyComputation(input.data);
412
+ }
413
+
414
+ private async heavyComputation(data: string) {
415
+ return data;
416
+ }
417
+ }
418
+ ```
@@ -0,0 +1,56 @@
1
+ # Output Schema Types Reference
2
+
3
+ All supported `outputSchema` types for `@Tool`:
4
+
5
+ ## Zod Raw Shapes (Recommended)
6
+
7
+ ```typescript
8
+ outputSchema: {
9
+ name: z.string(),
10
+ count: z.number(),
11
+ items: z.array(z.string()),
12
+ }
13
+ ```
14
+
15
+ Produces structured JSON output. **Best practice for CodeCall compatibility and data leak prevention.**
16
+
17
+ ## Zod Schemas
18
+
19
+ ```typescript
20
+ outputSchema: z.object({ result: z.number() })
21
+ outputSchema: z.array(z.string())
22
+ outputSchema: z.union([z.string(), z.number()])
23
+ outputSchema: z.discriminatedUnion('type', [...])
24
+ ```
25
+
26
+ ## Primitive Literals
27
+
28
+ ```typescript
29
+ outputSchema: 'string'; // Returns plain text
30
+ outputSchema: 'number'; // Returns a number
31
+ outputSchema: 'boolean'; // Returns true/false
32
+ outputSchema: 'date'; // Returns an ISO date string
33
+ ```
34
+
35
+ ## Media Types
36
+
37
+ ```typescript
38
+ outputSchema: 'image'; // Returns base64 image data
39
+ outputSchema: 'audio'; // Returns base64 audio data
40
+ outputSchema: 'resource'; // Returns a resource content
41
+ outputSchema: 'resource_link'; // Returns a resource URI link
42
+ ```
43
+
44
+ ## Multi-Content Arrays
45
+
46
+ ```typescript
47
+ outputSchema: ['string', 'image']; // Returns text + image content
48
+ ```
49
+
50
+ ## No OutputSchema (Not Recommended)
51
+
52
+ When `outputSchema` is omitted, the tool returns unvalidated content. This:
53
+
54
+ - Risks leaking internal fields to the client
55
+ - Prevents CodeCall from inferring return types
56
+ - Loses compile-time type checking on `Out` generic
@@ -0,0 +1,34 @@
1
+ # Tool Annotations Reference
2
+
3
+ Annotations provide hints to MCP clients about tool behavior:
4
+
5
+ ```typescript
6
+ @Tool({
7
+ name: 'my_tool',
8
+ inputSchema: { ... },
9
+ annotations: {
10
+ title: 'My Tool', // Human-readable display name
11
+ readOnlyHint: true, // Tool only reads data, no side effects
12
+ destructiveHint: false, // Tool does NOT destroy/delete data
13
+ idempotentHint: true, // Safe to call multiple times with same input
14
+ openWorldHint: false, // Tool does NOT interact with external world
15
+ },
16
+ })
17
+ ```
18
+
19
+ ## Fields
20
+
21
+ | Field | Type | Default | Description |
22
+ | ----------------- | --------- | ------- | ---------------------------------- |
23
+ | `title` | `string` | — | Human-friendly display name |
24
+ | `readOnlyHint` | `boolean` | `false` | Tool only reads, no mutations |
25
+ | `destructiveHint` | `boolean` | `true` | Tool may delete/overwrite data |
26
+ | `idempotentHint` | `boolean` | `false` | Repeated calls produce same result |
27
+ | `openWorldHint` | `boolean` | `true` | Tool may access external services |
28
+
29
+ ## Usage Guidance
30
+
31
+ - Set `readOnlyHint: true` for query/lookup tools
32
+ - Set `destructiveHint: true` for delete/overwrite operations (triggers client warnings)
33
+ - Set `idempotentHint: true` for safe-to-retry tools
34
+ - Set `openWorldHint: false` for tools that only access local data