Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Daten und Forschung · 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

Skill-Dokumentation

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

Gespeicherte Skills