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 {
  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(),
    };
  }
}

Signature

function Skill(providedMetadata: SkillMetadata): ClassDecorator

Configuration Options

Required Properties

PropertyTypeConstraintsDescription
namestringkebab-case, 1-64 chars, no --Unique skill identifier
descriptionstring1-1024 chars, no XML tagsSkill 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, 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: [],
})

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;
  assets?: string;
}

Skill Validation

Skills are validated on server startup:
@FrontMcp({
  info: { name: 'Server', version: '1.0.0' },
  apps: [MyApp],
  skillsConfig: {
    enabled: true,
    validation: 'strict', // 'strict' | 'warn' | 'ignore'
  },
})
  • strict: Fail if skill references missing tools
  • warn: Log warnings but continue
  • ignore: Skip 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 'zod';

// 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,
    validation: 'strict',
  },
})
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 18+ 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