@frontmcp/skills 1.3.0 → 1.4.0
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 +38 -29
- package/catalog/TEMPLATE.md +26 -0
- package/catalog/create-tool/SKILL.md +318 -0
- package/catalog/create-tool/examples/01-basic-class-tool.md +112 -0
- package/catalog/create-tool/examples/02-basic-function-tool.md +80 -0
- package/catalog/create-tool/examples/03-tool-with-zod-shape-output.md +78 -0
- package/catalog/create-tool/examples/04-tool-with-zod-schema-output.md +97 -0
- package/catalog/create-tool/examples/05-tool-with-primitive-output.md +93 -0
- package/catalog/create-tool/examples/06-tool-with-media-output.md +109 -0
- package/catalog/create-tool/examples/08-tool-with-provider-injection.md +110 -0
- package/catalog/create-tool/examples/09-tool-with-multiple-providers.md +107 -0
- package/catalog/create-tool/examples/11-tool-with-fetch.md +94 -0
- package/catalog/create-tool/examples/12-tool-with-fetch-and-retries.md +115 -0
- package/catalog/create-tool/examples/13-tool-with-single-auth-provider.md +85 -0
- package/catalog/create-tool/examples/14-tool-with-multiple-auth-providers.md +105 -0
- package/catalog/create-tool/examples/15-tool-with-credential-vault.md +115 -0
- package/catalog/create-tool/examples/16-tool-with-rate-limit.md +71 -0
- package/catalog/create-tool/examples/17-tool-with-concurrency-and-timeout.md +101 -0
- package/catalog/create-tool/examples/18-tool-with-progress-and-notify.md +96 -0
- package/catalog/create-tool/examples/19-tool-with-elicitation.md +102 -0
- package/catalog/create-tool/examples/20-tool-with-annotations.md +125 -0
- package/catalog/create-tool/examples/21-tool-with-availability-constraints.md +107 -0
- package/catalog/create-tool/examples/22-tool-with-ui-html-template.md +93 -0
- package/catalog/create-tool/examples/23-tool-with-ui-filesource-tsx.md +112 -0
- package/catalog/create-tool/examples/24-tool-with-ui-csp-and-bridge.md +127 -0
- package/catalog/create-tool/examples/25-tool-handing-off-to-job.md +143 -0
- package/catalog/create-tool/examples/26-tool-with-resource-link-output.md +94 -0
- package/catalog/create-tool/examples/27-tool-with-examples-metadata.md +90 -0
- package/catalog/create-tool/references/annotations.md +96 -0
- package/catalog/create-tool/references/auth-providers.md +167 -0
- package/catalog/create-tool/references/availability.md +106 -0
- package/catalog/create-tool/references/decorator-options.md +95 -0
- package/catalog/create-tool/references/derived-types.md +102 -0
- package/catalog/create-tool/references/elicitation.md +128 -0
- package/catalog/create-tool/references/error-handling.md +128 -0
- package/catalog/create-tool/references/execution-context.md +158 -0
- package/catalog/create-tool/references/file-layout.md +96 -0
- package/catalog/create-tool/references/function-style-builder.md +118 -0
- package/catalog/create-tool/references/input-schema.md +141 -0
- package/catalog/create-tool/references/output-schema.md +175 -0
- package/catalog/create-tool/references/quick-start.md +124 -0
- package/catalog/create-tool/references/registration.md +132 -0
- package/catalog/create-tool/references/remote-and-esm.md +68 -0
- package/catalog/create-tool/references/testing.md +59 -0
- package/catalog/create-tool/references/throttling.md +109 -0
- package/catalog/create-tool/references/ui-widgets.md +198 -0
- package/catalog/create-tool/rules/always-define-output-schema.md +77 -0
- package/catalog/create-tool/rules/derive-execute-types.md +57 -0
- package/catalog/create-tool/rules/input-schema-is-raw-shape.md +76 -0
- package/catalog/create-tool/rules/no-toolcontext-generics.md +50 -0
- package/catalog/create-tool/rules/no-try-catch-around-execute.md +79 -0
- package/catalog/create-tool/rules/register-in-app.md +76 -0
- package/catalog/create-tool/rules/snake-case-tool-names.md +45 -0
- package/catalog/create-tool/rules/use-this-fail-for-business-errors.md +75 -0
- package/catalog/create-tool/rules/widget-paths-anchor-with-import-meta-url.md +76 -0
- package/catalog/create-tool/rules/widget-resource-mode-host-detect.md +61 -0
- package/catalog/frontmcp-auth-ui/SKILL.md +146 -0
- package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/login-slot.md +97 -0
- package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/multi-step-auth-extra.md +133 -0
- package/catalog/frontmcp-auth-ui/references/custom-auth-ui.md +162 -0
- package/catalog/frontmcp-authorities/SKILL.md +55 -18
- package/catalog/frontmcp-authorities/references/authority-profiles.md +25 -1
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +1 -1
- package/catalog/frontmcp-authorities/references/rbac-abac-rebac.md +9 -0
- package/catalog/frontmcp-channels/SKILL.md +7 -1
- package/catalog/frontmcp-config/SKILL.md +9 -2
- package/catalog/frontmcp-config/examples/configure-auth/local-credential-vault.md +94 -0
- package/catalog/frontmcp-config/examples/configure-auth/local-secure-store.md +138 -0
- package/catalog/frontmcp-config/examples/configure-auth/remote-oauth-with-vault.md +45 -23
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-behind-tunnel.md +73 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-consent-enforcement.md +87 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-dcr-control.md +67 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-minimal.md +62 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-multi-provider-orchestration.md +93 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +18 -20
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-single-operator.md +66 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +37 -23
- package/catalog/frontmcp-config/examples/configure-http/custom-http-routes.md +98 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +17 -9
- package/catalog/frontmcp-config/references/configure-auth-modes.md +86 -23
- package/catalog/frontmcp-config/references/configure-auth.md +296 -50
- package/catalog/frontmcp-config/references/configure-http.md +149 -15
- package/catalog/frontmcp-deployment/SKILL.md +15 -13
- package/catalog/frontmcp-deployment/references/deploy-manifest-yaml.md +308 -0
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare-skills-only.md +174 -0
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +38 -2
- package/catalog/frontmcp-development/SKILL.md +30 -44
- package/catalog/frontmcp-development/references/decorators-guide.md +15 -15
- package/catalog/frontmcp-extensibility/SKILL.md +1 -1
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +8 -6
- package/catalog/frontmcp-extensibility/references/skill-audit-log.md +7 -2
- package/catalog/frontmcp-guides/SKILL.md +1 -1
- package/catalog/frontmcp-observability/SKILL.md +1 -1
- package/catalog/frontmcp-production-readiness/SKILL.md +1 -1
- package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +3 -2
- package/catalog/frontmcp-setup/SKILL.md +1 -1
- package/catalog/frontmcp-setup/examples/multi-app-composition/per-app-auth-and-isolation.md +7 -4
- package/catalog/frontmcp-setup/references/multi-app-composition.md +6 -5
- package/catalog/frontmcp-testing/SKILL.md +9 -1
- package/catalog/frontmcp-testing/references/test-auth.md +24 -0
- package/catalog/skills-manifest.json +653 -149
- package/package.json +1 -1
- package/src/manifest.d.ts +72 -1
- package/src/manifest.js +4 -1
- package/src/manifest.js.map +1 -1
- package/catalog/frontmcp-development/examples/create-tool/basic-class-tool.md +0 -80
- package/catalog/frontmcp-development/examples/create-tool/tool-with-di-and-errors.md +0 -132
- package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +0 -110
- package/catalog/frontmcp-development/examples/create-tool-annotations/destructive-delete-tool.md +0 -92
- package/catalog/frontmcp-development/examples/create-tool-annotations/readonly-query-tool.md +0 -59
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/primitive-and-media-outputs.md +0 -101
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-raw-shape-output.md +0 -62
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-schema-advanced-output.md +0 -101
- package/catalog/frontmcp-development/references/create-tool-annotations.md +0 -48
- package/catalog/frontmcp-development/references/create-tool-output-schema-types.md +0 -71
- package/catalog/frontmcp-development/references/create-tool.md +0 -806
package/package.json
CHANGED
package/src/manifest.d.ts
CHANGED
|
@@ -12,7 +12,21 @@ export type SkillTarget = 'node' | 'vercel' | 'lambda' | 'cloudflare' | 'all';
|
|
|
12
12
|
/**
|
|
13
13
|
* Skill categories for organizing the catalog.
|
|
14
14
|
*/
|
|
15
|
-
export type SkillCategory = 'setup' | 'deployment' | 'development' | 'config' | 'testing' | 'guides' | 'production' | 'extensibility' | 'observability';
|
|
15
|
+
export type SkillCategory = 'setup' | 'deployment' | 'development' | 'development/create' | 'config' | 'testing' | 'guides' | 'production' | 'extensibility' | 'observability';
|
|
16
|
+
/**
|
|
17
|
+
* Catalog layouts the validator understands.
|
|
18
|
+
*
|
|
19
|
+
* - `router` (default): the legacy shape used by skills like `frontmcp-development`
|
|
20
|
+
* — a Scenario Routing Table SKILL.md plus `references/<topic>.md` files with
|
|
21
|
+
* examples grouped in `examples/<topic>/<example>.md` subdirectories.
|
|
22
|
+
*
|
|
23
|
+
* - `component`: the new per-thing layout used by skills like `create-tool`
|
|
24
|
+
* — flat `examples/<example>.md` (no per-reference grouping), an optional
|
|
25
|
+
* `rules/` directory with short DO/DON'T files, and rich SKILL.md frontmatter
|
|
26
|
+
* designed for Claude Code's auto-trigger heuristics (explicit `triggers:`,
|
|
27
|
+
* `paths:` globs, `when_to_use`).
|
|
28
|
+
*/
|
|
29
|
+
export type SkillLayout = 'router' | 'component';
|
|
16
30
|
/**
|
|
17
31
|
* Bundle membership for curated scaffold presets.
|
|
18
32
|
*/
|
|
@@ -67,6 +81,38 @@ export interface SkillReferenceEntry {
|
|
|
67
81
|
/** Example files for this reference, located in examples/<reference-name>/ */
|
|
68
82
|
examples?: SkillReferenceExampleEntry[];
|
|
69
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Top-level example entry used by `layout: 'component'` skills, where
|
|
86
|
+
* examples live flat under `examples/<example>.md` (not grouped under a
|
|
87
|
+
* parent reference). Shape mirrors {@link SkillReferenceExampleEntry} so
|
|
88
|
+
* downstream consumers can use a uniform metadata type.
|
|
89
|
+
*/
|
|
90
|
+
export interface SkillComponentExampleEntry {
|
|
91
|
+
/** Example name — matches filename without extension */
|
|
92
|
+
name: string;
|
|
93
|
+
/** Short description of what the example demonstrates */
|
|
94
|
+
description: string;
|
|
95
|
+
/** Complexity level */
|
|
96
|
+
level: SkillExampleLevel;
|
|
97
|
+
/** Searchable tags for the example */
|
|
98
|
+
tags: string[];
|
|
99
|
+
/** Concrete APIs or patterns the example demonstrates */
|
|
100
|
+
features: string[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Top-level rule entry used by `layout: 'component'` skills. Rules are short
|
|
104
|
+
* DO / DON'T constraint files under `rules/<rule>.md`. The body explains the
|
|
105
|
+
* rule, gives good / bad examples, and (where possible) ends with a grep-based
|
|
106
|
+
* verification snippet.
|
|
107
|
+
*/
|
|
108
|
+
export interface SkillComponentRuleEntry {
|
|
109
|
+
/** Rule name — matches filename without extension */
|
|
110
|
+
name: string;
|
|
111
|
+
/** One-sentence statement of the rule */
|
|
112
|
+
constraint: string;
|
|
113
|
+
/** Enforcement strength — `required` for must-follow, `recommended` for nudges */
|
|
114
|
+
severity?: 'required' | 'recommended';
|
|
115
|
+
}
|
|
70
116
|
/**
|
|
71
117
|
* A single entry in the skills catalog manifest.
|
|
72
118
|
*
|
|
@@ -88,6 +134,29 @@ export interface SkillCatalogEntry {
|
|
|
88
134
|
hasResources: boolean;
|
|
89
135
|
/** Resolved reference metadata from references/ directory */
|
|
90
136
|
references?: SkillReferenceEntry[];
|
|
137
|
+
/**
|
|
138
|
+
* Catalog layout — see {@link SkillLayout}. Defaults to `'router'` when
|
|
139
|
+
* absent for backward compatibility with the legacy frontmcp-* router
|
|
140
|
+
* skills.
|
|
141
|
+
*/
|
|
142
|
+
layout?: SkillLayout;
|
|
143
|
+
/**
|
|
144
|
+
* Top-level example entries — only populated when `layout === 'component'`.
|
|
145
|
+
* Router-layout skills group examples under `references[].examples`
|
|
146
|
+
* instead.
|
|
147
|
+
*/
|
|
148
|
+
examples?: SkillComponentExampleEntry[];
|
|
149
|
+
/**
|
|
150
|
+
* Top-level rule entries — only populated when `layout === 'component'`.
|
|
151
|
+
* Each rule corresponds to a file in `rules/<name>.md`.
|
|
152
|
+
*/
|
|
153
|
+
rules?: SkillComponentRuleEntry[];
|
|
154
|
+
/**
|
|
155
|
+
* Priority hint surfaced to Claude Code's auto-discovery. Higher number =
|
|
156
|
+
* earlier in the ranking. Mirrors `metadata.priority` in SKILL.md
|
|
157
|
+
* frontmatter.
|
|
158
|
+
*/
|
|
159
|
+
priority?: number;
|
|
91
160
|
/** Target-specific storage defaults (e.g., { node: 'redis-docker', vercel: 'vercel-kv' }) */
|
|
92
161
|
storageDefault?: Record<string, string>;
|
|
93
162
|
/** Tags for secondary filtering and search */
|
|
@@ -125,5 +194,7 @@ export declare const VALID_EXAMPLE_LEVELS: readonly SkillExampleLevel[];
|
|
|
125
194
|
export declare const VALID_TARGETS: readonly SkillTarget[];
|
|
126
195
|
/** Valid categories for manifest validation */
|
|
127
196
|
export declare const VALID_CATEGORIES: readonly SkillCategory[];
|
|
197
|
+
/** Valid layouts for manifest validation */
|
|
198
|
+
export declare const VALID_LAYOUTS: readonly SkillLayout[];
|
|
128
199
|
/** Valid bundles for manifest validation */
|
|
129
200
|
export declare const VALID_BUNDLES: readonly SkillBundle[];
|
package/src/manifest.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module skills/manifest
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.VALID_BUNDLES = exports.VALID_CATEGORIES = exports.VALID_TARGETS = exports.VALID_EXAMPLE_LEVELS = void 0;
|
|
10
|
+
exports.VALID_BUNDLES = exports.VALID_LAYOUTS = exports.VALID_CATEGORIES = exports.VALID_TARGETS = exports.VALID_EXAMPLE_LEVELS = void 0;
|
|
11
11
|
/** Valid example levels for manifest validation */
|
|
12
12
|
exports.VALID_EXAMPLE_LEVELS = ['basic', 'intermediate', 'advanced'];
|
|
13
13
|
/** Valid deployment targets for manifest validation */
|
|
@@ -17,6 +17,7 @@ exports.VALID_CATEGORIES = [
|
|
|
17
17
|
'setup',
|
|
18
18
|
'deployment',
|
|
19
19
|
'development',
|
|
20
|
+
'development/create',
|
|
20
21
|
'config',
|
|
21
22
|
'testing',
|
|
22
23
|
'guides',
|
|
@@ -24,6 +25,8 @@ exports.VALID_CATEGORIES = [
|
|
|
24
25
|
'extensibility',
|
|
25
26
|
'observability',
|
|
26
27
|
];
|
|
28
|
+
/** Valid layouts for manifest validation */
|
|
29
|
+
exports.VALID_LAYOUTS = ['router', 'component'];
|
|
27
30
|
/** Valid bundles for manifest validation */
|
|
28
31
|
exports.VALID_BUNDLES = ['recommended', 'minimal', 'full'];
|
|
29
32
|
//# sourceMappingURL=manifest.js.map
|
package/src/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/manifest.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/manifest.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAiNH,mDAAmD;AACtC,QAAA,oBAAoB,GAAiC,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;AAExG,uDAAuD;AAC1C,QAAA,aAAa,GAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AAEvG,+CAA+C;AAClC,QAAA,gBAAgB,GAA6B;IACxD,OAAO;IACP,YAAY;IACZ,aAAa;IACb,oBAAoB;IACpB,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,YAAY;IACZ,eAAe;IACf,eAAe;CAChB,CAAC;AAEF,4CAA4C;AAC/B,QAAA,aAAa,GAA2B,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAE7E,4CAA4C;AAC/B,QAAA,aAAa,GAA2B,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC","sourcesContent":["/**\n * Skills catalog manifest types.\n *\n * Defines the contract between the catalog, scaffold tooling, and future installer.\n *\n * @module skills/manifest\n */\n\n/**\n * Supported deployment targets for skill filtering.\n */\nexport type SkillTarget = 'node' | 'vercel' | 'lambda' | 'cloudflare' | 'all';\n\n/**\n * Skill categories for organizing the catalog.\n */\nexport type SkillCategory =\n | 'setup'\n | 'deployment'\n | 'development'\n | 'development/create'\n | 'config'\n | 'testing'\n | 'guides'\n | 'production'\n | 'extensibility'\n | 'observability';\n\n/**\n * Catalog layouts the validator understands.\n *\n * - `router` (default): the legacy shape used by skills like `frontmcp-development`\n * — a Scenario Routing Table SKILL.md plus `references/<topic>.md` files with\n * examples grouped in `examples/<topic>/<example>.md` subdirectories.\n *\n * - `component`: the new per-thing layout used by skills like `create-tool`\n * — flat `examples/<example>.md` (no per-reference grouping), an optional\n * `rules/` directory with short DO/DON'T files, and rich SKILL.md frontmatter\n * designed for Claude Code's auto-trigger heuristics (explicit `triggers:`,\n * `paths:` globs, `when_to_use`).\n */\nexport type SkillLayout = 'router' | 'component';\n\n/**\n * Bundle membership for curated scaffold presets.\n */\nexport type SkillBundle = 'recommended' | 'minimal' | 'full';\n\n/**\n * Install destination types for future provider wiring.\n */\nexport type SkillDestination = 'project-local' | '.claude/skills' | 'codex' | 'gemini';\n\n/**\n * Merge strategy when installing a skill that already exists at the destination.\n */\nexport type SkillMergeStrategy = 'overwrite' | 'skip-existing';\n\n/**\n * Install configuration for a catalog skill.\n */\nexport interface SkillInstallConfig {\n /** Where this skill can be installed */\n destinations: SkillDestination[];\n /** How to handle existing skills at the destination */\n mergeStrategy: SkillMergeStrategy;\n /** Other skills this depends on (by name) */\n dependencies?: string[];\n}\n\n/**\n * Complexity level for a reference example.\n */\nexport type SkillExampleLevel = 'basic' | 'intermediate' | 'advanced';\n\n/**\n * Metadata for a single example file within a reference's examples/ directory.\n */\nexport interface SkillReferenceExampleEntry {\n /** Example name — matches filename without extension */\n name: string;\n /** Short description of what the example demonstrates */\n description: string;\n /** Complexity level */\n level: SkillExampleLevel;\n /** Searchable tags for the example */\n tags: string[];\n /** Concrete APIs or patterns the example demonstrates */\n features: string[];\n}\n\n/**\n * Metadata for a single reference file within a skill's references/ directory.\n * Extracted from YAML frontmatter or inferred from the markdown heading.\n */\nexport interface SkillReferenceEntry {\n /** Reference name — matches filename without extension */\n name: string;\n /** Short description from frontmatter or first paragraph */\n description: string;\n /** Example files for this reference, located in examples/<reference-name>/ */\n examples?: SkillReferenceExampleEntry[];\n}\n\n/**\n * Top-level example entry used by `layout: 'component'` skills, where\n * examples live flat under `examples/<example>.md` (not grouped under a\n * parent reference). Shape mirrors {@link SkillReferenceExampleEntry} so\n * downstream consumers can use a uniform metadata type.\n */\nexport interface SkillComponentExampleEntry {\n /** Example name — matches filename without extension */\n name: string;\n /** Short description of what the example demonstrates */\n description: string;\n /** Complexity level */\n level: SkillExampleLevel;\n /** Searchable tags for the example */\n tags: string[];\n /** Concrete APIs or patterns the example demonstrates */\n features: string[];\n}\n\n/**\n * Top-level rule entry used by `layout: 'component'` skills. Rules are short\n * DO / DON'T constraint files under `rules/<rule>.md`. The body explains the\n * rule, gives good / bad examples, and (where possible) ends with a grep-based\n * verification snippet.\n */\nexport interface SkillComponentRuleEntry {\n /** Rule name — matches filename without extension */\n name: string;\n /** One-sentence statement of the rule */\n constraint: string;\n /** Enforcement strength — `required` for must-follow, `recommended` for nudges */\n severity?: 'required' | 'recommended';\n}\n\n/**\n * A single entry in the skills catalog manifest.\n *\n * This is the core contract connecting SKILL.md files to scaffolding,\n * future installation, and provider-specific destinations.\n */\nexport interface SkillCatalogEntry {\n /** Unique skill name — matches SKILL.md frontmatter `name` */\n name: string;\n /** Skill category for organization */\n category: SkillCategory;\n /** Short description */\n description: string;\n /** Path to the skill directory, relative to catalog/ */\n path: string;\n /** Deployment targets this skill applies to */\n targets: SkillTarget[];\n /** Whether the skill has scripts/, references/, or assets/ directories */\n hasResources: boolean;\n /** Resolved reference metadata from references/ directory */\n references?: SkillReferenceEntry[];\n /**\n * Catalog layout — see {@link SkillLayout}. Defaults to `'router'` when\n * absent for backward compatibility with the legacy frontmcp-* router\n * skills.\n */\n layout?: SkillLayout;\n /**\n * Top-level example entries — only populated when `layout === 'component'`.\n * Router-layout skills group examples under `references[].examples`\n * instead.\n */\n examples?: SkillComponentExampleEntry[];\n /**\n * Top-level rule entries — only populated when `layout === 'component'`.\n * Each rule corresponds to a file in `rules/<name>.md`.\n */\n rules?: SkillComponentRuleEntry[];\n /**\n * Priority hint surfaced to Claude Code's auto-discovery. Higher number =\n * earlier in the ranking. Mirrors `metadata.priority` in SKILL.md\n * frontmatter.\n */\n priority?: number;\n /** Target-specific storage defaults (e.g., { node: 'redis-docker', vercel: 'vercel-kv' }) */\n storageDefault?: Record<string, string>;\n /** Tags for secondary filtering and search */\n tags: string[];\n /** Bundle membership for scaffold presets */\n bundle?: SkillBundle[];\n /** Install configuration for future distribution (optional — not yet used by CLI) */\n install?: SkillInstallConfig;\n /**\n * Optional skill quality rating (0..5, one decimal). Surfaced via the\n * Skills HTTP API for consumers that want to filter by `min-rating` or\n * sort by quality. Mirrors `SkillMetadata.rating` introduced in v1.2.0.\n */\n rating?: number;\n /**\n * Other catalog skills this skill depends on (by `name`). Used by the\n * dependency resolver introduced in v1.2.0 to register dependencies first\n * during scaffold/install. Aligns with the agentskills Skill Package\n * Manifest proposal `requires` field.\n */\n requires?: string[];\n}\n\n/**\n * The skills catalog manifest — single source of truth for scaffold and install tooling.\n */\nexport interface SkillManifest {\n /** Manifest schema version */\n version: 1;\n /** All catalog skills */\n skills: SkillCatalogEntry[];\n}\n\n/** Valid example levels for manifest validation */\nexport const VALID_EXAMPLE_LEVELS: readonly SkillExampleLevel[] = ['basic', 'intermediate', 'advanced'];\n\n/** Valid deployment targets for manifest validation */\nexport const VALID_TARGETS: readonly SkillTarget[] = ['node', 'vercel', 'lambda', 'cloudflare', 'all'];\n\n/** Valid categories for manifest validation */\nexport const VALID_CATEGORIES: readonly SkillCategory[] = [\n 'setup',\n 'deployment',\n 'development',\n 'development/create',\n 'config',\n 'testing',\n 'guides',\n 'production',\n 'extensibility',\n 'observability',\n];\n\n/** Valid layouts for manifest validation */\nexport const VALID_LAYOUTS: readonly SkillLayout[] = ['router', 'component'];\n\n/** Valid bundles for manifest validation */\nexport const VALID_BUNDLES: readonly SkillBundle[] = ['recommended', 'minimal', 'full'];\n"]}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: basic-class-tool
|
|
3
|
-
reference: create-tool
|
|
4
|
-
level: basic
|
|
5
|
-
description: 'A minimal tool using the class-based pattern with Zod input validation, output schema, and types derived from the schemas.'
|
|
6
|
-
tags: [development, tool, class]
|
|
7
|
-
features:
|
|
8
|
-
- 'Extending `ToolContext` and implementing the `execute()` method'
|
|
9
|
-
- 'Using a Zod raw shape for `inputSchema` (not wrapped in `z.object()`)'
|
|
10
|
-
- 'Defining `outputSchema` to validate and restrict output fields'
|
|
11
|
-
- 'Deriving `execute()` input/output types from the schemas via `ToolInputOf<>` / `ToolOutputOf<>` (no duplicated annotation)'
|
|
12
|
-
- 'Co-locating schema and tool in sibling files (`<name>.schema.ts` / `<name>.tool.ts`)'
|
|
13
|
-
- 'Registering the tool in an `@App` via the `tools` array'
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Basic Class-Based Tool
|
|
17
|
-
|
|
18
|
-
A minimal tool using the class-based pattern with Zod input validation, output schema, and types derived from the schemas.
|
|
19
|
-
|
|
20
|
-
## Code
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
// src/apps/main/tools/greet-user.schema.ts
|
|
24
|
-
import { ToolInputOf, ToolOutputOf, z } from '@frontmcp/sdk';
|
|
25
|
-
|
|
26
|
-
// Hoist only the schemas — keep `@Tool({…})` self-contained in the tool file.
|
|
27
|
-
export const inputSchema = {
|
|
28
|
-
name: z.string().describe('The name of the user to greet'),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const outputSchema = {
|
|
32
|
-
greeting: z.string(),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export type GreetUserInput = ToolInputOf<{ inputSchema: typeof inputSchema }>;
|
|
36
|
-
export type GreetUserOutput = ToolOutputOf<{ outputSchema: typeof outputSchema }>;
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
// src/apps/main/tools/greet-user.tool.ts
|
|
41
|
-
import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
42
|
-
|
|
43
|
-
import { inputSchema, outputSchema, type GreetUserInput, type GreetUserOutput } from './greet-user.schema';
|
|
44
|
-
|
|
45
|
-
@Tool({
|
|
46
|
-
name: 'greet_user',
|
|
47
|
-
description: 'Greet a user by name',
|
|
48
|
-
inputSchema,
|
|
49
|
-
outputSchema,
|
|
50
|
-
})
|
|
51
|
-
class GreetUserTool extends ToolContext {
|
|
52
|
-
async execute(input: GreetUserInput): Promise<GreetUserOutput> {
|
|
53
|
-
return { greeting: `Hello, ${input.name}!` };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// src/apps/main/index.ts
|
|
60
|
-
import { App } from '@frontmcp/sdk';
|
|
61
|
-
|
|
62
|
-
@App({
|
|
63
|
-
name: 'main',
|
|
64
|
-
tools: [GreetUserTool],
|
|
65
|
-
})
|
|
66
|
-
class MainApp {}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## What This Demonstrates
|
|
70
|
-
|
|
71
|
-
- Extending `ToolContext` and implementing the `execute()` method
|
|
72
|
-
- Using a Zod raw shape for `inputSchema` (not wrapped in `z.object()`)
|
|
73
|
-
- Defining `outputSchema` to validate and restrict output fields
|
|
74
|
-
- Deriving `execute()` input/output types from the schemas via `ToolInputOf<>` / `ToolOutputOf<>` (no duplicated annotation)
|
|
75
|
-
- Co-locating schema and tool in sibling files (`<name>.schema.ts` / `<name>.tool.ts`)
|
|
76
|
-
- Registering the tool in an `@App` via the `tools` array
|
|
77
|
-
|
|
78
|
-
## Related
|
|
79
|
-
|
|
80
|
-
- See `create-tool` for the full API reference including the derive-types pattern, file layouts, annotations, rate limiting, and elicitation
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tool-with-di-and-errors
|
|
3
|
-
reference: create-tool
|
|
4
|
-
level: intermediate
|
|
5
|
-
description: 'A tool that resolves a database service via DI and uses `this.fail()` for business-logic errors, with `execute()` types derived from the schemas.'
|
|
6
|
-
tags: [development, database, tool, di, errors]
|
|
7
|
-
features:
|
|
8
|
-
- 'Defining a typed DI token with `Token<T>` and resolving it via `this.get()`'
|
|
9
|
-
- 'Using `this.fail()` with `ResourceNotFoundError` for MCP-compliant error responses'
|
|
10
|
-
- 'Letting infrastructure errors (database failures) propagate naturally to the framework'
|
|
11
|
-
- 'Deriving `execute()` types from `inputSchema` / `outputSchema` via `ToolInputOf<>` / `ToolOutputOf<>`'
|
|
12
|
-
- 'Folder-per-tool layout (`tools/delete-record/{schema,tool,index}.ts`) for tools with local helpers or error types'
|
|
13
|
-
- 'Registering both the provider and tool in the same `@App`'
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Tool with Dependency Injection and Error Handling
|
|
17
|
-
|
|
18
|
-
A tool that resolves a database service via DI and uses `this.fail()` for business-logic errors, with `execute()` types derived from the schemas.
|
|
19
|
-
|
|
20
|
-
## File layout
|
|
21
|
-
|
|
22
|
-
```text
|
|
23
|
-
src/apps/main/
|
|
24
|
-
├── tokens.ts # shared DI tokens
|
|
25
|
-
└── tools/
|
|
26
|
-
└── delete-record/
|
|
27
|
-
├── delete-record.schema.ts # input/output schemas + derived types
|
|
28
|
-
├── delete-record.tool.ts # @Tool class, execute()
|
|
29
|
-
└── index.ts # barrel re-export
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Code
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// src/apps/main/tokens.ts
|
|
36
|
-
import type { Token } from '@frontmcp/di';
|
|
37
|
-
|
|
38
|
-
export interface DatabaseService {
|
|
39
|
-
query(sql: string, params: unknown[]): Promise<unknown[]>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const DATABASE: Token<DatabaseService> = Symbol('database');
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
// src/apps/main/tools/delete-record/delete-record.schema.ts
|
|
47
|
-
import { ToolInputOf, ToolOutputOf, z } from '@frontmcp/sdk';
|
|
48
|
-
|
|
49
|
-
// Only the schemas live here — decorator config (`name`, `description`, …)
|
|
50
|
-
// stays inside @Tool({…}) in the tool file.
|
|
51
|
-
export const inputSchema = {
|
|
52
|
-
id: z.string().uuid().describe('Record UUID'),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const outputSchema = {
|
|
56
|
-
message: z.string(),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type DeleteRecordInput = ToolInputOf<{ inputSchema: typeof inputSchema }>;
|
|
60
|
-
export type DeleteRecordOutput = ToolOutputOf<{ outputSchema: typeof outputSchema }>;
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
// src/apps/main/tools/delete-record/delete-record.tool.ts
|
|
65
|
-
import { ResourceNotFoundError, Tool, ToolContext } from '@frontmcp/sdk';
|
|
66
|
-
|
|
67
|
-
import { DATABASE } from '../../tokens';
|
|
68
|
-
import { inputSchema, outputSchema, type DeleteRecordInput, type DeleteRecordOutput } from './delete-record.schema';
|
|
69
|
-
|
|
70
|
-
@Tool({
|
|
71
|
-
name: 'delete_record',
|
|
72
|
-
description: 'Delete a record by ID',
|
|
73
|
-
inputSchema,
|
|
74
|
-
outputSchema,
|
|
75
|
-
})
|
|
76
|
-
export class DeleteRecordTool extends ToolContext {
|
|
77
|
-
async execute(input: DeleteRecordInput): Promise<DeleteRecordOutput> {
|
|
78
|
-
const db = this.get(DATABASE);
|
|
79
|
-
const rows = await db.query('SELECT * FROM records WHERE id = $1', [input.id]);
|
|
80
|
-
|
|
81
|
-
if (rows.length === 0) {
|
|
82
|
-
this.fail(new ResourceNotFoundError(`Record ${input.id}`));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
await db.query('DELETE FROM records WHERE id = $1', [input.id]);
|
|
86
|
-
return { message: `Record ${input.id} deleted successfully` };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
// src/apps/main/tools/delete-record/index.ts
|
|
93
|
-
export { DeleteRecordTool } from './delete-record.tool';
|
|
94
|
-
export {
|
|
95
|
-
inputSchema as deleteRecordInputSchema,
|
|
96
|
-
outputSchema as deleteRecordOutputSchema,
|
|
97
|
-
type DeleteRecordInput,
|
|
98
|
-
type DeleteRecordOutput,
|
|
99
|
-
} from './delete-record.schema';
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// src/apps/main/index.ts
|
|
104
|
-
import { App } from '@frontmcp/sdk';
|
|
105
|
-
|
|
106
|
-
// `DatabaseProvider` is the singleton that backs `DATABASE` — see the
|
|
107
|
-
// `create-provider` skill for an `AsyncProvider({ useFactory })` reference
|
|
108
|
-
// implementation that opens a connection pool at startup.
|
|
109
|
-
import { DatabaseProvider } from './providers/database';
|
|
110
|
-
import { DeleteRecordTool } from './tools/delete-record';
|
|
111
|
-
|
|
112
|
-
@App({
|
|
113
|
-
name: 'main',
|
|
114
|
-
providers: [DatabaseProvider],
|
|
115
|
-
tools: [DeleteRecordTool],
|
|
116
|
-
})
|
|
117
|
-
class MainApp {}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## What This Demonstrates
|
|
121
|
-
|
|
122
|
-
- Defining a typed DI token with `Token<T>` and resolving it via `this.get()`
|
|
123
|
-
- Using `this.fail()` with `ResourceNotFoundError` for MCP-compliant error responses
|
|
124
|
-
- Letting infrastructure errors (database failures) propagate naturally to the framework
|
|
125
|
-
- Deriving `execute()` types from `inputSchema` / `outputSchema` via `ToolInputOf<>` / `ToolOutputOf<>`
|
|
126
|
-
- Folder-per-tool layout (`tools/delete-record/{schema,tool,index}.ts`) for tools with local helpers or error types
|
|
127
|
-
- Registering both the provider and tool in the same `@App`
|
|
128
|
-
|
|
129
|
-
## Related
|
|
130
|
-
|
|
131
|
-
- See `create-tool` for all context methods, the derive-types pattern, and error handling
|
|
132
|
-
- See `create-provider` for how to implement the `DatabaseProvider` class
|
package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tool-with-rate-limiting-and-progress
|
|
3
|
-
reference: create-tool
|
|
4
|
-
level: advanced
|
|
5
|
-
description: 'A batch processing tool that uses rate limiting, concurrency control, progress notifications, and annotations, with `execute()` types derived from the schemas.'
|
|
6
|
-
tags: [development, throttle, tool, rate, limiting, progress]
|
|
7
|
-
features:
|
|
8
|
-
- 'Configuring `rateLimit`, `concurrency`, and `timeout` for throttling protection'
|
|
9
|
-
- 'Sending progress updates to the client with `this.progress(progress, total, message?)`'
|
|
10
|
-
- 'Using `this.mark(stage)` for execution stage tracking and debugging'
|
|
11
|
-
- 'Sending log-level notifications with `this.notify(message, level)`'
|
|
12
|
-
- 'Setting tool `annotations` to communicate behavioral hints to clients'
|
|
13
|
-
- 'Deriving `execute()` types from the schemas via `ToolInputOf<>` / `ToolOutputOf<>`'
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Tool with Rate Limiting, Progress, and Annotations
|
|
17
|
-
|
|
18
|
-
A batch processing tool that uses rate limiting, concurrency control, progress notifications, and annotations, with `execute()` types derived from the schemas.
|
|
19
|
-
|
|
20
|
-
## Code
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
// src/apps/main/tools/batch-process.schema.ts
|
|
24
|
-
import { ToolInputOf, ToolOutputOf, z } from '@frontmcp/sdk';
|
|
25
|
-
|
|
26
|
-
// Schemas only — `annotations`, `rateLimit`, `concurrency`, `timeout` etc.
|
|
27
|
-
// stay inside @Tool({…}) in the tool file.
|
|
28
|
-
export const inputSchema = {
|
|
29
|
-
items: z.array(z.string()).min(1).describe('Items to process'),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const outputSchema = {
|
|
33
|
-
processed: z.number(),
|
|
34
|
-
results: z.array(z.string()),
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type BatchProcessInput = ToolInputOf<{ inputSchema: typeof inputSchema }>;
|
|
38
|
-
export type BatchProcessOutput = ToolOutputOf<{ outputSchema: typeof outputSchema }>;
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// src/apps/main/tools/batch-process.tool.ts
|
|
43
|
-
import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
44
|
-
|
|
45
|
-
import { inputSchema, outputSchema, type BatchProcessInput, type BatchProcessOutput } from './batch-process.schema';
|
|
46
|
-
|
|
47
|
-
@Tool({
|
|
48
|
-
name: 'batch_process',
|
|
49
|
-
description: 'Process a batch of items with progress tracking',
|
|
50
|
-
inputSchema,
|
|
51
|
-
outputSchema,
|
|
52
|
-
annotations: {
|
|
53
|
-
title: 'Batch Processor',
|
|
54
|
-
readOnlyHint: false,
|
|
55
|
-
idempotentHint: true,
|
|
56
|
-
openWorldHint: false,
|
|
57
|
-
},
|
|
58
|
-
rateLimit: { maxRequests: 10, windowMs: 60_000 },
|
|
59
|
-
concurrency: { maxConcurrent: 2 },
|
|
60
|
-
timeout: { executeMs: 30_000 },
|
|
61
|
-
})
|
|
62
|
-
class BatchProcessTool extends ToolContext {
|
|
63
|
-
async execute(input: BatchProcessInput): Promise<BatchProcessOutput> {
|
|
64
|
-
this.mark('validation');
|
|
65
|
-
if (input.items.some((item) => item.trim() === '')) {
|
|
66
|
-
this.fail(new Error('Items must not be empty strings'));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
this.mark('processing');
|
|
70
|
-
const results: string[] = [];
|
|
71
|
-
for (let i = 0; i < input.items.length; i++) {
|
|
72
|
-
await this.progress(i + 1, input.items.length, `Processing item ${i + 1}`);
|
|
73
|
-
const result = await this.processItem(input.items[i]);
|
|
74
|
-
results.push(result);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this.mark('complete');
|
|
78
|
-
await this.notify(`Processed ${results.length} items`, 'info');
|
|
79
|
-
return { processed: results.length, results };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private async processItem(item: string): Promise<string> {
|
|
83
|
-
return `processed:${item}`;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
// src/apps/main/index.ts
|
|
90
|
-
import { App } from '@frontmcp/sdk';
|
|
91
|
-
|
|
92
|
-
@App({
|
|
93
|
-
name: 'main',
|
|
94
|
-
tools: [BatchProcessTool],
|
|
95
|
-
})
|
|
96
|
-
class MainApp {}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## What This Demonstrates
|
|
100
|
-
|
|
101
|
-
- Configuring `rateLimit`, `concurrency`, and `timeout` for throttling protection
|
|
102
|
-
- Sending progress updates to the client with `this.progress(progress, total, message?)`
|
|
103
|
-
- Using `this.mark(stage)` for execution stage tracking and debugging
|
|
104
|
-
- Sending log-level notifications with `this.notify(message, level)`
|
|
105
|
-
- Setting tool `annotations` to communicate behavioral hints to clients
|
|
106
|
-
- Deriving `execute()` types from the schemas via `ToolInputOf<>` / `ToolOutputOf<>`
|
|
107
|
-
|
|
108
|
-
## Related
|
|
109
|
-
|
|
110
|
-
- See `create-tool` for the full derive-types pattern, annotation fields, elicitation, and auth provider patterns
|
package/catalog/frontmcp-development/examples/create-tool-annotations/destructive-delete-tool.md
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: destructive-delete-tool
|
|
3
|
-
reference: create-tool-annotations
|
|
4
|
-
level: intermediate
|
|
5
|
-
description: 'Demonstrates annotating a tool that deletes data, enabling MCP clients to warn users before execution.'
|
|
6
|
-
tags: [development, elicitation, tool, annotations, destructive, delete]
|
|
7
|
-
features:
|
|
8
|
-
- 'Setting `destructiveHint: true` on the delete tool so MCP clients can trigger confirmation warnings'
|
|
9
|
-
- 'Setting `idempotentHint: true` on the delete tool because deleting the same user twice produces the same outcome'
|
|
10
|
-
- 'Setting `openWorldHint: true` on the email tool because it interacts with an external SMTP service'
|
|
11
|
-
- 'Setting `idempotentHint: false` on the email tool because each call sends a new email'
|
|
12
|
-
- 'How different annotation combinations express different behavioral contracts'
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Destructive Delete Tool with Annotations
|
|
16
|
-
|
|
17
|
-
Demonstrates annotating a tool that deletes data, enabling MCP clients to warn users before execution.
|
|
18
|
-
|
|
19
|
-
## Code
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
// src/tools/delete-user.tool.ts
|
|
23
|
-
import { Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
24
|
-
|
|
25
|
-
@Tool({
|
|
26
|
-
name: 'delete_user',
|
|
27
|
-
description: 'Permanently delete a user account and all associated data',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
userId: z.string().describe('ID of the user to delete'),
|
|
30
|
-
confirm: z.boolean().describe('Must be true to confirm deletion'),
|
|
31
|
-
},
|
|
32
|
-
annotations: {
|
|
33
|
-
title: 'Delete User Account',
|
|
34
|
-
readOnlyHint: false,
|
|
35
|
-
destructiveHint: true,
|
|
36
|
-
idempotentHint: true,
|
|
37
|
-
openWorldHint: false,
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
class DeleteUserTool extends ToolContext {
|
|
41
|
-
async execute(input: { userId: string; confirm: boolean }) {
|
|
42
|
-
if (!input.confirm) {
|
|
43
|
-
return { deleted: false, reason: 'Confirmation required' };
|
|
44
|
-
}
|
|
45
|
-
const db = this.get(DatabaseToken);
|
|
46
|
-
await db.deleteUser(input.userId);
|
|
47
|
-
return { deleted: true, userId: input.userId };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
// src/tools/send-email.tool.ts
|
|
54
|
-
import { Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
55
|
-
|
|
56
|
-
@Tool({
|
|
57
|
-
name: 'send_email',
|
|
58
|
-
description: 'Send an email to a recipient via external SMTP service',
|
|
59
|
-
inputSchema: {
|
|
60
|
-
to: z.string().email().describe('Recipient email address'),
|
|
61
|
-
subject: z.string().describe('Email subject'),
|
|
62
|
-
body: z.string().describe('Email body text'),
|
|
63
|
-
},
|
|
64
|
-
annotations: {
|
|
65
|
-
title: 'Send Email',
|
|
66
|
-
readOnlyHint: false,
|
|
67
|
-
destructiveHint: false,
|
|
68
|
-
idempotentHint: false,
|
|
69
|
-
openWorldHint: true,
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
class SendEmailTool extends ToolContext {
|
|
73
|
-
async execute(input: { to: string; subject: string; body: string }) {
|
|
74
|
-
const mailer = this.get(MailerToken);
|
|
75
|
-
const result = await mailer.send(input.to, input.subject, input.body);
|
|
76
|
-
return { sent: true, messageId: result.id };
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## What This Demonstrates
|
|
82
|
-
|
|
83
|
-
- Setting `destructiveHint: true` on the delete tool so MCP clients can trigger confirmation warnings
|
|
84
|
-
- Setting `idempotentHint: true` on the delete tool because deleting the same user twice produces the same outcome
|
|
85
|
-
- Setting `openWorldHint: true` on the email tool because it interacts with an external SMTP service
|
|
86
|
-
- Setting `idempotentHint: false` on the email tool because each call sends a new email
|
|
87
|
-
- How different annotation combinations express different behavioral contracts
|
|
88
|
-
|
|
89
|
-
## Related
|
|
90
|
-
|
|
91
|
-
- See `create-tool-annotations` for all annotation fields and their default values
|
|
92
|
-
- See `decorators-guide` for the full `@Tool` decorator field reference
|
package/catalog/frontmcp-development/examples/create-tool-annotations/readonly-query-tool.md
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: readonly-query-tool
|
|
3
|
-
reference: create-tool-annotations
|
|
4
|
-
level: basic
|
|
5
|
-
description: 'Demonstrates annotating a tool that only reads data, signaling to MCP clients that it has no side effects and is safe to retry.'
|
|
6
|
-
tags: [development, database, local, tool, annotations, readonly]
|
|
7
|
-
features:
|
|
8
|
-
- 'Setting `readOnlyHint: true` to indicate the tool performs no mutations'
|
|
9
|
-
- 'Setting `destructiveHint: false` to tell clients no data will be deleted or overwritten'
|
|
10
|
-
- 'Setting `idempotentHint: true` because repeated calls with the same input produce the same result'
|
|
11
|
-
- 'Setting `openWorldHint: false` because the tool only accesses local database data'
|
|
12
|
-
- 'Using `title` to provide a human-friendly display name for MCP client UIs'
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Read-Only Query Tool with Annotations
|
|
16
|
-
|
|
17
|
-
Demonstrates annotating a tool that only reads data, signaling to MCP clients that it has no side effects and is safe to retry.
|
|
18
|
-
|
|
19
|
-
## Code
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
// src/tools/search-users.tool.ts
|
|
23
|
-
import { Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
24
|
-
|
|
25
|
-
@Tool({
|
|
26
|
-
name: 'search_users',
|
|
27
|
-
description: 'Search for users by name or email',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
query: z.string().describe('Search query'),
|
|
30
|
-
limit: z.number().optional().default(10),
|
|
31
|
-
},
|
|
32
|
-
annotations: {
|
|
33
|
-
title: 'Search Users',
|
|
34
|
-
readOnlyHint: true,
|
|
35
|
-
destructiveHint: false,
|
|
36
|
-
idempotentHint: true,
|
|
37
|
-
openWorldHint: false,
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
class SearchUsersTool extends ToolContext {
|
|
41
|
-
async execute(input: { query: string; limit: number }) {
|
|
42
|
-
const db = this.get(DatabaseToken);
|
|
43
|
-
const users = await db.searchUsers(input.query, input.limit);
|
|
44
|
-
return { users };
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## What This Demonstrates
|
|
50
|
-
|
|
51
|
-
- Setting `readOnlyHint: true` to indicate the tool performs no mutations
|
|
52
|
-
- Setting `destructiveHint: false` to tell clients no data will be deleted or overwritten
|
|
53
|
-
- Setting `idempotentHint: true` because repeated calls with the same input produce the same result
|
|
54
|
-
- Setting `openWorldHint: false` because the tool only accesses local database data
|
|
55
|
-
- Using `title` to provide a human-friendly display name for MCP client UIs
|
|
56
|
-
|
|
57
|
-
## Related
|
|
58
|
-
|
|
59
|
-
- See `create-tool-annotations` for the full fields reference and default values
|