Skip to main content

Basic Usage

import { Skill, SkillContext } from '@frontmcp/sdk';

@Skill({
  name: 'code-review',
  description: 'Complete code review workflow',
  instructions: `
# Code Review Workflow

1. Fetch the pull request details
2. Review the code changes
3. Check for common issues
4. Post review comments
  `,
  tools: ['github_get_pr', 'github_post_comment'],
})
class CodeReviewSkill extends SkillContext {}
The class body is optional. When you use @Skill, the runtime loads instructions (and resources) from the decorator metadata via SkillInstance, so loadInstructions() and build() on your class are never invoked — you only need to override them if you construct a SkillContext subclass manually outside the decorator pipeline. See Advanced: overriding loadInstructions / build.

Advanced: overriding loadInstructions / build

You only need to override these methods when you bypass the @Skill decorator and want to drive loading yourself. Otherwise, leave the body empty — the runtime does the work for you.
class CodeReviewSkill extends SkillContext {
  override async loadInstructions() {
    return this.metadata.instructions as string;
  }

  override async build() {
    return {
      id: this.skillId,
      name: this.metadata.name,
      description: this.metadata.description,
      instructions: await this.loadInstructions(),
      tools: this.getToolRefs(),
    };
  }
}

Signature

function Skill(providedMetadata: SkillMetadata): ClassDecorator

Configuration Options

Required Properties

PropertyTypeConstraintsDescription
namestringkebab-case, 1-64 chars, no --Unique skill identifier
descriptionstring1-1024 chars, non-emptySkill description
instructionsstring | { file: string } | { url: string }Skill instructions

Optional Properties

PropertyTypeDescription
toolsSkillToolInput[]Tools used by the skill
idstringStable identifier (defaults to name)
parametersSkillParameter[]Input parameters
examplesSkillExample[]Usage examples
tagsstring[]Categorization tags
prioritynumberSearch ranking weight (default: 0)
hideFromDiscoverybooleanHide from search results (default: false)
visibility'mcp' | 'http' | 'both'Discovery visibility (default: 'both')
toolValidation'strict' | 'warn' | 'ignore'Tool reference validation mode (default: 'warn')

Agent Skills Spec Properties

These properties align with the Anthropic Agent Skills specification:
PropertyTypeDescription
licensestringLicense name or reference (e.g. 'MIT', 'Apache-2.0')
compatibilitystringEnvironment requirements (max 500 chars)
specMetadataRecord<string, string>Arbitrary key-value metadata (maps to spec metadata)
allowedToolsstringSpace-delimited pre-approved tools (maps to spec allowed-tools)
resourcesSkillResourcesBundled resource directories (scripts, references, examples, assets)

Instruction Sources

Inline String

@Skill({
  name: 'my-skill',
  description: 'My skill',
  instructions: '# Instructions\n\n1. Step one\n2. Step two',
  tools: [],
})

File Reference

@Skill({
  name: 'my-skill',
  description: 'My skill',
  instructions: { file: './skills/my-skill.md' },
  tools: [],
})
File path resolution. Relative paths in instructions: { file: '…' }, resources.references, and resources.examples resolve against the directory of the source file that declared the @Skill class — not process.cwd(). The directory is captured at decoration time by walking the call stack, and the same rule applies to the inline skill() helper. For bundled CLIs the framework additionally falls back to the build-time _skills/manifest.json so paths keep resolving after frontmcp build.

URL Reference

@Skill({
  name: 'my-skill',
  description: 'My skill',
  instructions: { url: 'https://example.com/skills/my-skill.md' },
  tools: [],
})

Tool References

By Name

tools: ['tool_name', 'another_tool']

By Class

tools: [MyToolClass, AnotherToolClass]

With Purpose

tools: [
  { name: 'github_get_pr', purpose: 'Fetch PR details', required: true },
  { name: 'github_comment', purpose: 'Post review feedback', required: false },
]

With Class and Purpose

tools: [
  { class: GitHubGetPRTool, purpose: 'Fetch PR details' },
]

Parameters

Define input parameters for skills:
@Skill({
  name: 'deploy',
  description: 'Deploy application',
  instructions: '...',
  tools: ['deploy_app'],
  parameters: [
    {
      name: 'environment',
      description: 'Target environment',
      required: true,
      type: 'string',
    },
    {
      name: 'version',
      description: 'Version to deploy',
      required: false,
      type: 'string',
      default: 'latest',
    },
  ],
})

Examples

Provide usage examples:
@Skill({
  name: 'data-analysis',
  description: 'Analyze data sets',
  instructions: '...',
  tools: ['query_database', 'generate_chart'],
  examples: [
    {
      scenario: 'Analyze monthly sales',
      parameters: { table: 'sales', period: 'monthly' },
      expectedOutcome: 'Sales trends chart and summary report',
    },
  ],
})

Function-Based Alternative

import { skill } from '@frontmcp/sdk';

const codeReviewSkill = skill({
  name: 'code-review',
  description: 'Code review workflow',
  instructions: { file: './code-review.md' },
  tools: ['github_get_pr', 'github_comment'],
  tags: ['github', 'review'],
});

Skill Content Output

Skills build to SkillContent:
interface SkillContent {
  id: string;
  name: string;
  description: string;
  instructions: string;
  tools: Array<{
    name: string;
    purpose?: string;
    required?: boolean;
  }>;
  parameters?: SkillParameter[];
  examples?: SkillExample[];

  // Agent Skills spec fields
  license?: string;
  compatibility?: string;
  specMetadata?: Record<string, string>;
  allowedTools?: string;
  resources?: SkillResources;
}

interface SkillResources {
  scripts?: string;
  references?: string;
  examples?: string;
  assets?: string;
}

Skill Validation

Skills are validated on server startup. Validation strictness is configured per skill via the toolValidation field on @Skill:
@Skill({
  name: 'review-pr',
  description: 'Review a pull request',
  tools: ['list_files', 'read_file', 'comment_on_pr'],
  toolValidation: 'strict', // 'strict' | 'warn' (default) | 'ignore'
})
class ReviewPrSkill extends SkillContext {}
  • strict: Fail if skill references missing tools
  • warn (default): Log warnings but continue
  • ignore: Skip tool validation

Skill Sessions

Skills can be loaded into sessions for focused tool access:
// Client-side
const client = await connect(config);

// Search for skills
const results = await client.searchSkills('code review');

// Load skill into session
await client.loadSkills(['code-review'], {
  activateSession: true,
  policyMode: 'strict', // Only allow skill's tools
});

// Now tool calls are restricted to skill's tool allowlist

Full Example

import { Skill, SkillContext, Tool, ToolContext, App, FrontMcp } from '@frontmcp/sdk';
import { z } from '@frontmcp/sdk';

// Tools
@Tool({
  name: 'jira_get_issue',
  inputSchema: { issueKey: z.string() },
})
class JiraGetIssueTool extends ToolContext {
  async execute(input) {
    return { key: input.issueKey, summary: 'Issue summary' };
  }
}

@Tool({
  name: 'jira_update_status',
  inputSchema: { issueKey: z.string(), status: z.string() },
})
class JiraUpdateStatusTool extends ToolContext {
  async execute(input) {
    return { success: true };
  }
}

@Tool({
  name: 'slack_notify',
  inputSchema: { channel: z.string(), message: z.string() },
})
class SlackNotifyTool extends ToolContext {
  async execute(input) {
    return { sent: true };
  }
}

// Skill
@Skill({
  name: 'sprint-planning',
  description: 'Assist with Agile sprint planning',
  instructions: `
# Sprint Planning Workflow

## Overview
Help the team plan their next sprint by reviewing backlog items and updating statuses.

## Steps

1. **Review Backlog**
   - Use \`jira_get_issue\` to fetch backlog items
   - Analyze priority and estimates

2. **Assign to Sprint**
   - Use \`jira_update_status\` to move items to sprint
   - Verify capacity constraints

3. **Notify Team**
   - Use \`slack_notify\` to inform the team
   - Share sprint goals and assignments

## Best Practices
- Keep sprint scope realistic
- Balance workload across team members
- Leave buffer for unexpected work
  `,
  tools: [
    { name: 'jira_get_issue', purpose: 'Fetch issue details from backlog', required: true },
    { name: 'jira_update_status', purpose: 'Move issues to sprint', required: true },
    { name: 'slack_notify', purpose: 'Notify team of sprint plan', required: false },
  ],
  parameters: [
    { name: 'sprintName', description: 'Name of the sprint', required: true, type: 'string' },
    { name: 'capacity', description: 'Team capacity in story points', required: false, type: 'number', default: 40 },
  ],
  examples: [
    {
      scenario: 'Plan a two-week sprint',
      parameters: { sprintName: 'Sprint 23', capacity: 40 },
      expectedOutcome: 'Sprint backlog populated with balanced workload',
    },
  ],
  tags: ['agile', 'jira', 'planning'],
  priority: 10,
})
class SprintPlanningSkill extends SkillContext {
  async loadInstructions() {
    return this.metadata.instructions as string;
  }

  async build() {
    return {
      id: this.skillId,
      name: this.metadata.name,
      description: this.metadata.description,
      instructions: await this.loadInstructions(),
      tools: this.getToolRefs().map(ref => ({
        name: ref.name,
        purpose: ref.purpose,
        required: ref.required !== false,
      })),
      parameters: this.metadata.parameters,
      examples: this.metadata.examples,
    };
  }
}

@App({
  name: 'project-management',
  tools: [JiraGetIssueTool, JiraUpdateStatusTool, SlackNotifyTool],
  skills: [SprintPlanningSkill],
})
class ProjectManagementApp {}

@FrontMcp({
  info: { name: 'PM Assistant', version: '1.0.0' },
  apps: [ProjectManagementApp],
  skillsConfig: {
    enabled: true,
  },
})
export default class PMAssistantServer {}

SKILL.md Files

Load skills from SKILL.md files with YAML frontmatter (per Agent Skills spec):
---
name: review-pr
description: Review a GitHub pull request
license: MIT
compatibility: Requires git CLI
tags:
  - github
  - code-review
metadata:
  author: platform-team
  version: "1.0"
allowed-tools: Read Edit Bash(git diff)
---
# PR Review Instructions

1. Fetch the PR details using github_get_pr
2. Review each changed file
3. Add review comments
4. Submit the review

Loading SKILL.md Files

import { loadSkillMdFile, parseSkillMdFrontmatter } from '@frontmcp/sdk';

// High-level: read + parse in one call
const metadata = await loadSkillMdFile('./skills/review-pr/SKILL.md');

// Low-level: parse content you already have
const { frontmatter, body } = parseSkillMdFrontmatter(rawContent);

Skill Directories

Load entire skill directories with the skillDir() helper:
import { skillDir } from '@frontmcp/sdk';

const reviewSkill = await skillDir('./skills/review-pr');
// Reads SKILL.md, auto-detects scripts/, references/, assets/

@App({
  name: 'my-app',
  skills: [reviewSkill],
})
class MyApp {}
Expected directory structure:
skills/review-pr/
  SKILL.md             # Required
  scripts/             # Optional: automation scripts
  references/          # Optional: reference documents
  assets/              # Optional: images, templates

Agent Skills Spec Example

A fully spec-compliant skill:
@Skill({
  name: 'security-audit',
  description: 'Perform a security audit on the codebase',
  instructions: { file: './skills/security-audit/SKILL.md' },
  tools: [
    { name: 'code_search', purpose: 'Search for vulnerability patterns', required: true },
    { name: 'file_read', purpose: 'Read source files', required: true },
    { name: 'create_report', purpose: 'Generate audit report' },
  ],
  tags: ['security', 'audit', 'compliance'],
  license: 'Apache-2.0',
  compatibility: 'Requires Node.js 24+ and access to source repository',
  specMetadata: {
    author: 'security-team',
    version: '3.0.0',
    category: 'security',
  },
  allowedTools: 'Read Grep Glob',
  resources: {
    scripts: './skills/security-audit/scripts',
    references: './skills/security-audit/references',
  },
})
class SecurityAuditSkill extends SkillContext {}

SkillContext

Context class details

SkillRegistry

Skill registry API

@Tool

Define tools

Skills Overview

Skills documentation