L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Données et recherche · SKILL.md

create-tool

create-tool

ALWAYS use this skill when the user asks to build, modify, or audit a FrontMCP tool. Covers everything inside `@Tool({...})`: class and function-style tools, Zod input/output schemas with derived `execute()` types, dependency injection (`this.get` / `this.tryGet`), error handling (`this.fail`, MCP error classes), throttling (rate-limit / concurrency / timeo…

Independent GitHub snapshot · Automated classification · Original documentation governs

Aagentfront / frontmcpApache-2.0

Documentation de la Skill

GitHub

name: create-tool description: | ALWAYS use this skill when the user asks to build, modify, or audit a FrontMCP tool. Covers everything inside @Tool({...}): class and function-style tools, Zod input/output schemas with derived execute() types, dependency injection (this.get / this.tryGet), error handling (this.fail, MCP error classes), throttling (rate-limit / concurrency / timeout), auth providers (single / multi / vault), availability constraints (availableWhen), elicitation (this.elicit), interactive UI widgets via @Tool({ ui }) (MCP Apps / SEP-1865 — including .tsx FileSource, CSP, window.FrontMcpBridge, host-detect resourceMode), annotations (readOnlyHint / destructiveHint / …), examples metadata, registration in @App({ tools }), and per-tool unit testing.

Does NOT cover:

  • Read-only data exposed via a URI — use create-resource
  • Conversation templates / system prompts — use create-prompt
  • Multi-tool orchestration loops — use create-agent
  • Background work / pipelines — use create-job / create-workflow
  • Server-level config (transport, sessions, auth modes) — use config / auth

Triggers: @Tool, ToolContext, tool decorator, MCP tool, snake_case tool name, inputSchema, outputSchema, ToolInputOf, ToolOutputOf, @Tool({ ui }), tool UI widget, MCP Apps widget, FileSource widget, .tsx widget, ui.csp, ui.resourceMode, window.FrontMcpBridge, tool annotations, readOnlyHint, destructiveHint, rate-limit tool, throttle tool, concurrency tool, tool timeout, this.fail, this.respond, this.fetch, this.notify, this.progress, this.elicit, ElicitationDisabledError, ToolContext.execute, this.get(TOKEN), this.tryGet, register tool in @App, tool examples metadata, availableWhen, missingAxes, tool() function builder, Tool.esm, Tool.remote, PublicMcpError, ResourceNotFoundError, MCP_ERROR_CODES, ui://widget.

when_to_use: | Trigger when creating or editing a *.tool.ts / *.tool.tsx file, adding a @Tool decorator, defining inputSchema / outputSchema for a tool, deriving execute() parameter or return types, wiring dependency injection into a tool, returning structured / media / resource content, adding a ui: block (FileSource / React / HTML / Markdown), configuring throttling, declaring auth providers, restricting platforms via availableWhen, requesting interactive input via this.elicit, adding tool annotations, or registering a tool in @App({ tools }).

paths: '/.tool.ts, **/.tool.tsx, /tools//.ts, **/apps//tools/, **/*.tool.spec.ts'

layout: component license: Apache-2.0 priority: 10 visibility: public tags: [ development, tool, create-tool, decorator, input-schema, output-schema, ToolContext, ui, mcp-apps, annotations, throttling, auth-providers, availability, elicitation, ] category: development/create bundle: [recommended, minimal, full] allowed-tools: Read Edit Write Grep Glob Bash

metadata: docs: https://frontmcp.dev/reference/sdk/tool

Create a FrontMCP Tool

Tools are the primary way to expose executable actions to AI clients in the MCP protocol. In FrontMCP, every tool is a TypeScript class that extends ToolContext, decorated with @Tool({...}), and registered on an @App (or directly on @FrontMcp for simple servers).

This skill is the single source of truth for building tools. It owns:

  • The @Tool decorator surface
  • Input / output schemas and how to derive execute() types from them
  • Dependency injection, error handling, progress / notifications
  • Throttling: rate-limit, concurrency, timeout
  • Auth providers and the credential vault
  • Platform / runtime / surface availability constraints
  • Elicitation (interactive input mid-execution)
  • Tool UI widgets — the ui: block, MCP Apps / SEP-1865, .tsx FileSource, CSP, window.FrontMcpBridge
  • Annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)
  • The examples metadata field
  • Function-style tools, remote / ESM tools
  • Registration patterns
  • Per-tool unit testing

For everything else — resources, prompts, agents, jobs, workflows, adapters, plugins, providers, channels — use the matching create-<thing> skill.

First time? Start with references/quick-start.md, then jump to the example matching your scenario via the Decision Tree below.


Inherited defaults

This skill ALWAYS applies these defaults — never opt out without an audited reason:

DefaultSourceWhat it enforces
inputSchema is a Zod raw shaperules/input-schema-is-raw-shape.mdPlain object mapping field → Zod type. Framework wraps internally. Never z.object(...) at the top level.
outputSchema is always definedrules/always-define-output-schema.mdPrevents data leaks, enables CodeCall chaining, gives compile-time type safety.
execute() types are derived from the schemasrules/derive-execute-types.mdToolInputOf<> / ToolOutputOf<> over the hoisted schemas. Schema is the single source of truth.
class MyTool extends ToolContext — no genericsrules/no-toolcontext-generics.mdTypes are auto-inferred from @Tool. Explicit generics are redundant and forbidden.
Tool names are snake_caserules/snake-case-tool-names.mdMCP protocol convention. get_weather, not getWeather.
No try/catch around execute()rules/no-try-catch-around-execute.mdThe framework's flow catches and formats errors. Wrapping defeats it.
this.fail(new McpError(…)) for business errorsrules/use-this-fail-for-business-errors.mdTriggers the error flow with proper JSON-RPC codes. Raw throw skips it.
Register tools in @App({ tools })rules/register-in-app.mdApps own modularity and lifecycle. Top-level @FrontMcp({ tools }) is the simple-server escape hatch.
.tsx widget paths use fileURLToPath(new URL('./x.tsx', import.meta.url))rules/widget-paths-anchor-with-import-meta-url.mdRelative FileSource paths resolve against process.cwd() — the workaround is mandatory (issue #444).
Leave ui.resourceMode unset by defaultrules/widget-resource-mode-host-detect.mdThe framework host-detects: Claude → 'inline', others → 'cdn' (issue #456). Set explicitly only to override.

If a request seems to conflict with an inherited default (e.g., "wrap inputSchema in z.object to use refinements", or "use try/catch to swallow upstream errors"), stop and ask — never silently override.


When to invoke this skill

Must use

  • Creating a new *.tool.ts file
  • Adding the @Tool({...}) decorator
  • Defining or changing inputSchema / outputSchema
  • Adding a ui: block to a tool (any template type)
  • Adding annotations, rateLimit, concurrency, timeout, authProviders, availableWhen, examples to a tool
  • Calling this.elicit(...) from execute()
  • Registering a tool in @App({ tools }) or @FrontMcp({ tools })
  • Writing the unit test for a tool

Recommended

  • Auditing an existing tool for the inherited defaults above
  • Picking between class-style and function-style (tool({...})(handler))
  • Choosing the right output-schema variant for the data you're returning
  • Converting a tool's auth from a single string to the full { name, scopes, required } mapping
  • Deciding whether a side-effecting tool needs destructiveHint: true

Skip when

  • You're not building a tool. Use the matching create-<thing> skill.

Decision tree

1. What kind of tool?
   ├── Tiny one-off → function-style: `tool({...})((input, ctx) => …)`
   │   See: examples/02-basic-function-tool.md
   ├── Anything with DI, lifecycle, hooks, or UI → class-style
   │   See: examples/01-basic-class-tool.md
   └── Externally hosted (npm package or remote MCP server) → Tool.esm / Tool.remote
       See: references/remote-and-esm.md

2. What does it return?
   ├── Structured JSON          → outputSchema: { field: z.string(), … }
   │                              See: examples/03-tool-with-zod-shape-output.md
   ├── A primitive (text/num)   → outputSchema: 'string' | 'number' | 'boolean' | 'date'
   │                              See: examples/05-tool-with-primitive-output.md
   ├── Media (image/audio)      → outputSchema: 'image' | 'audio'
   │                              See: examples/06-tool-with-media-output.md
   ├── A resource link          → outputSchema: 'resource' | 'resource_link'
   │                              See: examples/26-tool-with-resource-link-output.md
   └── Several content blocks   → outputSchema: ['string', 'image']
                                  See: examples/06-tool-with-media-output.md

3. Does it need shared services / config / clients?
   YES → register a @Provider; inject via this.get(TOKEN)
         See: examples/08-tool-with-provider-injection.md

4. Does it call an external HTTP API?
   YES → use this.fetch(input, init?) (context propagation)
         See: examples/11-tool-with-fetch.md

5. Does it need user credentials from an OAuth provider?
   YES → declare authProviders: ['provider'] (or full mapping)
         See: examples/13-tool-with-single-auth-provider.md, 15-tool-with-credential-vault.md

6. Is it expensive / rate-limited / slow?
   YES → add rateLimit / concurrency / timeout
         See: examples/16-tool-with-rate-limit.md, 17-tool-with-concurrency-and-timeout.md

7. Does it run for a while? Want progress?
   YES → call this.progress(n, total, msg)
         See: examples/18-tool-with-progress-and-notify.md

8. Does it need a confirmation / extra input mid-run?
   YES → this.elicit('msg', { fieldSchema })
         See: examples/19-tool-with-elicitation.md

9. Is it destructive / read-only / idempotent / open-world?
   YES → annotations: { destructiveHint, readOnlyHint, idempotentHint, openWorldHint }
         See: examples/20-tool-with-annotations.md

10. Should it only run on certain OSes / runtimes / build targets?
    YES → availableWhen: { os, runtime, deployment, provider, target, surface, env }
          See: examples/21-tool-with-availability-constraints.md

11. Should the result render as a widget in the host UI?
    YES → ui: { template, … }
          ├── Quick HTML            → ui: { template: (ctx) => ctx.helpers.html`<div>…</div>` }
          │                            See: examples/22-tool-with-ui-html-template.md
          ├── React widget (file)   → ui: { template: { file: widgetPath } }
          │                            See: examples/23-tool-with-ui-filesource-tsx.md
          ├── Calls other tools     → window.FrontMcpBridge.callTool
          │                            See: examples/24-tool-with-ui-csp-and-bridge.md
          └── Claude target         → resourceMode is auto-detected; do not set
                                       See: references/ui-widgets.md

12. Does it hand off long work to a job?
    YES → kick off a job + return a tracking handle
          See: examples/25-tool-handing-off-to-job.md

Scenario routing table

ScenarioExampleWhy
Build the simplest possible tool01-basic-class-toolFoundation — every other example builds on this shape
One-off math / formatter02-basic-function-tooltool() builder is fine for trivial pure-input tools
Return structured JSON03-tool-with-zod-shape-outputRaw Zod shape — recommended for any complex output
Output is a complex Zod schema04-tool-with-zod-schema-outputz.object() / z.array() / z.discriminatedUnion() for full Zod
Output is a primitive05-tool-with-primitive-output'string' / 'number' / 'date' literals
Output is binary / multi-content06-tool-with-media-output'image', 'audio', ['string', 'image']
Tool resolves dependencies via DI08-tool-with-provider-injectionthis.get(TOKEN) against a @Provider-registered service
Tool composes multiple services09-tool-with-multiple-providersRealistic shape — DB + cache + config in one tool
Tool calls an external HTTP API11-tool-with-fetchthis.fetch(url, init?) — context propagation, error handling
Tool calls a flaky API with retries12-tool-with-fetch-and-retriesExponential backoff, idempotency-key, retry config
Tool needs OAuth credentials13-tool-with-single-auth-providerauthProviders: ['github'] — string shorthand
Tool needs scoped / optional creds14-tool-with-multiple-auth-providersFull mapping form with required + scopes + alias
Tool reads a per-session secret15-tool-with-credential-vaultthis.authProviders.headers(...), vault patterns
Rate-limit an expensive operation16-tool-with-rate-limitrateLimit: { maxRequests, windowMs }
Cap concurrency + add a timeout17-tool-with-concurrency-and-timeoutProduction-ready throttling shape
Long-running tool with progress18-tool-with-progress-and-notifythis.progress + this.notify + this.mark
Tool that asks the user mid-run19-tool-with-elicitationthis.elicit with Zod schema
Tool with behavioral hints for the client20-tool-with-annotationsreadOnlyHint / destructiveHint / idempotentHint / openWorldHint
Tool restricted to one OS / runtime / target21-tool-with-availability-constraintsavailableWhen axes
Tool with a quick inline HTML widget22-tool-with-ui-html-templateui: { template: (ctx) => ctx.helpers.html`<div>…</div>` }
Tool with a separate .tsx widget file23-tool-with-ui-filesource-tsxFileSource + import.meta.url anchoring
Tool widget that calls other tools24-tool-with-ui-csp-and-bridgewindow.FrontMcpBridge.callTool
Tool that triggers a job + tracks it25-tool-handing-off-to-jobThin tool + heavy job — the right split
Tool that returns a resource handle26-tool-with-resource-link-outputoutputSchema: 'resource_link' — the host fetches the resource
Tool with examples metadata for discovery27-tool-with-examples-metadataexamples: [{ description, input, output? }]

Verification checklist

Before considering a tool "done":

  • Class extends ToolContext (no generics) OR uses tool() function builder
  • @Tool({ name, description, inputSchema, outputSchema }) — all four present
  • name is snake_case
  • inputSchema is a Zod raw shape (NOT wrapped in z.object)
  • outputSchema is defined (Zod shape / primitive / media / array)
  • execute() parameter and return types derived via ToolInputOf<> / ToolOutputOf<>
  • No try/catch around execute() body
  • Business errors use this.fail(new SomeMcpError(…)), not raw throw
  • Tool registered in an @App({ tools }) (or @FrontMcp({ tools }) for single-app servers)
  • If ui:: .tsx widget paths anchored via fileURLToPath(new URL(...))
  • If ui:: ui.resourceMode left unset (host-detect) unless an explicit override is intentional
  • Unit test in <name>.tool.spec.ts covering happy + at least one failure path
  • Optional: annotations, rateLimit / concurrency / timeout, authProviders, availableWhen, examples set when the tool's behavior warrants them

References (deep dives)

ReferenceCovers
quick-start.md60-second tour: minimal tool, registration, calling it from a test
decorator-options.mdEvery field on @Tool({...}) — what it does, default, when to set it
input-schema.mdRaw shape vs z.object, refinements, defaults, optional, describe
output-schema.mdAll supported output types: Zod shape, Zod schema, primitives, media, arrays
derived-types.mdToolInputOf / ToolOutputOf patterns, file layout, schema hoisting
execution-context.mdToolContext methods + properties — this.get, this.fetch, this.notify, this.context, etc.
error-handling.mdthis.fail, MCP error classes (PublicMcpError, ResourceNotFoundError), error flow, when to throw vs fail
throttling.mdrateLimit, concurrency, timeout — semantics, interaction, defaults
auth-providers.mdauthProviders string shorthand vs full mapping, scopes, alias, credential vault basics
availability.mdavailableWhen axes (os / runtime / deployment / provider / target / surface / env), missingAxes, isPlatform
elicitation.mdthis.elicit, server-level enable, ElicitationDisabledError, accept / decline / cancel
ui-widgets.md@Tool({ ui }) — template formats, servingMode, resourceMode host-detect, CSP, ignored options, MCP Apps spec
annotations.mdreadOnlyHint, destructiveHint, idempotentHint, openWorldHint, title
function-style-builder.mdtool({...})(handler) — when to pick over a class, register, ctx parameter
remote-and-esm.mdTool.esm(...) / Tool.remote(...) — load tools from npm packages or remote MCP servers
registration.md@App({ tools }) vs @FrontMcp({ tools }), multi-app composition
file-layout.mdFlat-sibling vs folder-per-tool, <name>.schema.ts / <name>.tool.ts / <name>.tool.spec.ts
testing.mdPer-tool unit tests — @frontmcp/testing, mocking DI, asserting output validation

Rules (constraints — read these once, then they're enforced)

RuleConstraint
input-schema-is-raw-shape.mdinputSchema is a raw Zod shape, never z.object(...)
always-define-output-schema.mdEvery tool defines outputSchema
derive-execute-types.mdexecute() types come from ToolInputOf / ToolOutputOf — never duplicated inline
no-toolcontext-generics.mdclass MyTool extends ToolContext — no <typeof inputSchema> generic
snake-case-tool-names.mdTool name is snake_case
no-try-catch-around-execute.mdThe framework owns error flow — don't wrap execute() body
use-this-fail-for-business-errors.mdthis.fail(new McpError(…)) — never raw throw for business errors
register-in-app.mdRegister tools in @App({ tools }) for modularity / lifecycle
widget-paths-anchor-with-import-meta-url.md.tsx widget paths via fileURLToPath(new URL(...)) — never bare relative
widget-resource-mode-host-detect.mdLeave ui.resourceMode unset — let host detect

Accessing this skill

ModeHow
FilesystemRead libs/skills/catalog/create-tool/ directly. SKILL.md is the entry point.
CLIfrontmcp skills list, frontmcp skills read create-tool, frontmcp skills read create-tool:references/<file>.md, frontmcp skills install create-tool
MCP skill://When mounted on a FrontMCP server, available at skill://create-tool/SKILL.md, skill://create-tool/references/{file}.md, etc. (SEP-2640)

Related skills

create-resource, create-prompt, create-agent, create-provider, create-job, create-workflow, create-adapter, create-plugin, decorators-guide, architecture, testing, auth

Skills enregistrées