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 {}