feat: mcp prompts

This commit is contained in:
2026-03-18 12:13:15 +08:00
parent 62aff91a86
commit 4f9d295bd5
5 changed files with 754 additions and 3 deletions
+115 -3
View File
@@ -289,13 +289,125 @@ label,name,type,cost,description
- 其他列:由 frontmatter 中的 `fields` 定义 - 其他列:由 frontmatter 中的 `fields` 定义
- `body`: 卡牌 body 内容(可选,支持 `{{字段名}}` 语法) - `body`: 卡牌 body 内容(可选,支持 `{{字段名}}` 语法)
## MCP Prompts
MCP 服务器提供以下 Prompts,用于引导用户完成卡牌设计工作流:
### `design-card-game` - 设计卡牌游戏
引导用户设计新的卡牌游戏系统,定义卡牌模板和字段结构。
**参数:**
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `deck_name` | string | ✗ | 卡牌组名称 |
| `output_dir` | string | ✗ | 输出目录(相对路径) |
| `game_theme` | string | ✗ | 游戏主题/类型(如:奇幻、科幻、恐怖等) |
**使用示例:**
```json
{
"name": "design-card-game",
"arguments": {
"deck_name": "魔法物品",
"output_dir": "./content",
"game_theme": "奇幻"
}
}
```
**返回内容:**
Prompt 会返回一个对话式的引导流程,帮助 AI 助手了解:
1. 卡牌类型(角色卡、物品卡、法术卡等)
2. 核心机制(费用系统、稀有度、阵营等)
3. 卡牌信息字段
并提供常见配置的示例参考。
---
### `populate-deck` - 填充卡牌内容
为已有的卡牌组生成和填充卡牌内容。
**参数:**
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `csv_file` | string | ✗ | CSV 文件路径 |
| `card_count` | number | ✗ | 要生成的卡牌数量 |
| `theme` | string | ✗ | 卡牌主题/描述 |
**使用示例:**
```json
{
"name": "populate-deck",
"arguments": {
"csv_file": "./content/magic-items.csv",
"card_count": 20,
"theme": "火焰主题法术"
}
}
```
**返回内容:**
Prompt 会引导 AI 助手:
1. 读取现有卡牌模板结构
2. 选择生成方式(随机/主题化/手动/扩展现有)
3. 生成符合主题的卡牌内容
---
### `setup-deck-display` - 配置卡牌显示
引导用户配置卡牌的显示参数(尺寸、布局、样式等)。
**参数:**
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `csv_file` | string | ✗ | CSV 文件路径 |
| `usage` | string | ✗ | 卡牌用途(如:桌面游戏、印刷、在线预览等) |
**使用示例:**
```json
{
"name": "setup-deck-display",
"arguments": {
"csv_file": "./content/magic-items.csv",
"usage": "桌面游戏"
}
}
```
**返回内容:**
Prompt 会引导 AI 助手配置:
1. 卡牌尺寸(桥牌尺寸、标准尺寸、塔罗尺寸等)
2. 网格布局(每张 A4 纸的排列)
3. 出血边距、内边距
4. 卡牌形状
5. 图层配置(自动排版文字)
---
## 工作流示例 ## 工作流示例
### 创建新卡牌组 ### 创建新卡牌组
1. **定义模板**:调用 `deck_frontmatter_write` 创建 CSV 和 frontmatter 1. **设计模板**:调用 `design-card-game` Prompt 引导设计字段结构
2. **创建预览**:调用 `deck_ensure_preview` 创建 Markdown 预览文件 2. **定义模板**:调用 `deck_frontmatter_write` 创建 CSV 和 frontmatter
3. **添加卡牌**:调用 `deck_card_crud`action=create)添加卡牌 3. **创建预览**:调用 `deck_ensure_preview` 创建 Markdown 预览文件
4. **填充内容**:调用 `populate-deck` Prompt 引导生成卡牌内容
5. **添加卡牌**:调用 `deck_card_crud`action=create)添加卡牌
6. **配置显示**:调用 `setup-deck-display` Prompt 配置显示参数
7. **保存配置**:调用 `deck_frontmatter_write` 更新 deck 配置
### 修改现有卡牌组 ### 修改现有卡牌组
+70
View File
@@ -4,6 +4,21 @@ import { readFrontmatter, type ReadFrontmatterParams, type DeckFrontmatter } fro
import { writeFrontmatter, type WriteFrontmatterParams } from '../tools/frontmatter/write-frontmatter.js'; import { writeFrontmatter, type WriteFrontmatterParams } from '../tools/frontmatter/write-frontmatter.js';
import { cardCrud, type CardCrudParams, type CardData } from '../tools/card/card-crud.js'; import { cardCrud, type CardCrudParams, type CardData } from '../tools/card/card-crud.js';
import { ensureDeckPreview, type EnsureDeckPreviewParams } from '../tools/ensure-deck-preview.js'; import { ensureDeckPreview, type EnsureDeckPreviewParams } from '../tools/ensure-deck-preview.js';
import {
designCardGame,
getDesignCardGamePrompt,
type DesignCardGameOptions
} from '../prompts/design-card-game.js';
import {
populateDeck,
getPopulateDeckPrompt,
type PopulateDeckOptions
} from '../prompts/populate-deck.js';
import {
setupDeckDisplay,
getSetupDeckDisplayPrompt,
type SetupDeckDisplayOptions
} from '../prompts/setup-deck-display.js';
/** /**
* MCP 服务器命令 * MCP 服务器命令
@@ -54,6 +69,8 @@ async function mcpServeAction(host: string, options: MCPOptions) {
const { const {
CallToolRequestSchema, CallToolRequestSchema,
ListToolsRequestSchema, ListToolsRequestSchema,
ListPromptsRequestSchema,
GetPromptRequestSchema,
} = await import('@modelcontextprotocol/sdk/types.js'); } = await import('@modelcontextprotocol/sdk/types.js');
const server = new Server( const server = new Server(
@@ -64,6 +81,7 @@ async function mcpServeAction(host: string, options: MCPOptions) {
{ {
capabilities: { capabilities: {
tools: {}, tools: {},
prompts: {},
}, },
} }
); );
@@ -304,6 +322,17 @@ async function mcpServeAction(host: string, options: MCPOptions) {
}; };
}); });
// 处理 Prompts 列表请求
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
getDesignCardGamePrompt(),
getPopulateDeckPrompt(),
getSetupDeckDisplayPrompt(),
],
};
});
// 处理工具调用请求 // 处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => { server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params; const { name, arguments: args } = request.params;
@@ -446,6 +475,47 @@ async function mcpServeAction(host: string, options: MCPOptions) {
} }
}); });
// 处理 Prompts 获取请求
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'design-card-game': {
const options = args as unknown as DesignCardGameOptions;
const result = designCardGame(options);
return {
description: '引导用户设计新的卡牌游戏系统,定义卡牌模板和字段结构',
messages: result.messages,
};
}
case 'populate-deck': {
const options = args as unknown as PopulateDeckOptions;
const result = populateDeck(options);
return {
description: '为已有的卡牌组生成和填充卡牌内容',
messages: result.messages,
};
}
case 'setup-deck-display': {
const options = args as unknown as SetupDeckDisplayOptions;
const result = setupDeckDisplay(options);
return {
description: '引导用户配置卡牌的显示参数(尺寸、布局、样式等)',
messages: result.messages,
};
}
default:
throw new Error(`未知 prompt${name}`);
}
} catch (error) {
throw error;
}
});
// 启动服务器 // 启动服务器
if (host === 'stdio') { if (host === 'stdio') {
const transport = new StdioServerTransport(); const transport = new StdioServerTransport();
+187
View File
@@ -0,0 +1,187 @@
/**
* design-card-game Prompt
*
* 引导用户设计新的卡牌游戏系统,定义卡牌模板和字段结构
*/
export interface DesignCardGameOptions {
/**
* 卡牌组名称
*/
deck_name?: string;
/**
* 输出目录
*/
output_dir?: string;
/**
* 游戏类型/主题
*/
game_theme?: string;
}
export interface DesignCardGameResult {
messages: PromptMessage[];
}
export interface PromptMessage {
role: 'user' | 'assistant';
content: TextContent | ImageContent | AudioContent | ResourceContent;
}
export interface TextContent {
type: 'text';
text: string;
}
export interface ImageContent {
type: 'image';
data: string;
mimeType: string;
}
export interface AudioContent {
type: 'audio';
data: string;
mimeType: string;
}
export interface ResourceContent {
type: 'resource';
resource: {
uri: string;
mimeType: string;
text?: string;
blob?: string;
};
}
/**
* 生成 design-card-game prompt 的消息
*/
export function designCardGame(options?: DesignCardGameOptions): DesignCardGameResult {
const deckName = options?.deck_name || '未命名卡牌组';
const outputDir = options?.output_dir || './content';
const gameTheme = options?.game_theme || '通用';
const messages: PromptMessage[] = [
{
role: 'user',
content: {
type: 'text',
text: `我想设计一个"${gameTheme}"主题的卡牌游戏,卡牌组名称为"${deckName}",输出目录为"${outputDir}"。请帮我设计卡牌的字段结构。`
}
},
{
role: 'assistant',
content: {
type: 'text',
text: `好的!我来帮你设计"${deckName}"卡牌组的字段结构。
首先,让我了解一些基本信息:
## 1. 卡牌类型
这个卡牌游戏主要包含什么类型的卡牌?(可多选)
- [ ] 角色卡(Characters)- 代表游戏中的人物或生物
- [ ] 物品卡(Items)- 装备、道具、消耗品等
- [ ] 法术/技能卡(Spells/Abilities- 魔法、技能、动作等
- [ ] 地点卡(Locations)- 场景、区域、地图等
- [ ] 事件卡(Events)- 随机事件、剧情触发等
- [ ] 其他:_______
## 2. 核心机制
卡牌游戏的核心机制是什么?
- 是否有费用/资源系统?(如:法力值、行动点等)
- 是否有稀有度系统?(如:普通、稀有、史诗、传说)
- 是否有阵营/派系系统?
- 是否有等级/强度系统?
## 3. 卡牌信息
每张卡牌通常需要展示哪些信息?
- 卡牌名称(必填)
- 卡牌描述/效果(必填)
- 插画/图片(可选)
- 其他属性:_______
请告诉我你的选择,我会为你生成合适的字段结构。
---
**示例参考:**
如果你想要快速开始,可以参考以下常见配置:
### 魔法物品卡牌组
\`\`\`json
{
"fields": [
{"name": "name", "description": "物品名称"},
{"name": "type", "description": "物品类型", "examples": ["武器", "防具", "饰品", "消耗品"]},
{"name": "rarity", "description": "稀有度", "examples": ["普通", "稀有", "史诗", "传说"]},
{"name": "cost", "description": "价格/费用"},
{"name": "effect", "description": "效果描述"}
]
}
\`\`\`
### NPC 角色卡牌组
\`\`\`json
{
"fields": [
{"name": "name", "description": "角色名称"},
{"name": "class", "description": "职业", "examples": ["战士", "法师", "盗贼", "牧师"]},
{"name": "level", "description": "等级"},
{"name": "background", "description": "背景故事"},
{"name": "ability", "description": "特殊能力"}
]
}
\`\`\`
### 塔罗牌组
\`\`\`json
{
"fields": [
{"name": "name", "description": "牌名"},
{"name": "number", "description": "编号"},
{"name": "element", "description": "元素", "examples": ["火", "水", "风", "土"]},
{"name": "meaning", "description": "含义"},
{"name": "reversed", "description": "逆位含义"}
]
}
\`\`\``
}
}
];
return { messages };
}
/**
* 获取 prompt 的元数据
*/
export function getDesignCardGamePrompt() {
return {
name: 'design-card-game',
title: '设计卡牌游戏',
description: '引导用户设计新的卡牌游戏系统,定义卡牌模板和字段结构',
arguments: [
{
name: 'deck_name',
description: '卡牌组名称',
required: false
},
{
name: 'output_dir',
description: '输出目录(相对路径)',
required: false
},
{
name: 'game_theme',
description: '游戏主题/类型(如:奇幻、科幻、恐怖等)',
required: false
}
]
};
}
+187
View File
@@ -0,0 +1,187 @@
/**
* populate-deck Prompt
*
* 引导用户为已有的卡牌组填充卡牌内容
*/
export interface PopulateDeckOptions {
/**
* CSV 文件路径
*/
csv_file?: string;
/**
* 要生成的卡牌数量
*/
card_count?: number;
/**
* 卡牌主题/描述
*/
theme?: string;
}
export interface PopulateDeckResult {
messages: PromptMessage[];
}
export interface PromptMessage {
role: 'user' | 'assistant';
content: TextContent | ImageContent | AudioContent | ResourceContent;
}
export interface TextContent {
type: 'text';
text: string;
}
export interface ImageContent {
type: 'image';
data: string;
mimeType: string;
}
export interface AudioContent {
type: 'audio';
data: string;
mimeType: string;
}
export interface ResourceContent {
type: 'resource';
resource: {
uri: string;
mimeType: string;
text?: string;
blob?: string;
};
}
/**
* 生成 populate-deck prompt 的消息
*/
export function populateDeck(options?: PopulateDeckOptions): PopulateDeckResult {
const csvFile = options?.csv_file || './content/deck.csv';
const cardCount = options?.card_count || 10;
const theme = options?.theme || '通用';
const messages: PromptMessage[] = [
{
role: 'user',
content: {
type: 'text',
text: `我想为卡牌组"${csvFile}"生成${cardCount}张卡牌,主题是"${theme}"。请帮我填充卡牌内容。`
}
},
{
role: 'assistant',
content: {
type: 'text',
text: `好的!我来帮你为"${csvFile}"生成${cardCount}张"${theme}"主题的卡牌。
首先,让我读取现有的卡牌模板结构...
---
**步骤 1:读取卡牌模板**
在开始生成卡牌之前,我需要了解卡牌组的字段结构。请确认以下信息:
## 卡牌字段
根据 CSV 文件的 frontmatter 定义,卡牌包含以下字段:
(这里会显示从 CSV 文件中读取的字段定义)
## 生成方式
你希望如何生成卡牌内容?
### 选项 A:完全随机生成
- 我会根据字段的 examples 随机组合生成卡牌
- 适合快速填充大量卡牌
### 选项 B:主题化生成
- 告诉我具体的主题(如:"森林生物"、"火焰法术"、"古代神器"等)
- 我会生成符合主题的连贯卡牌
### 选项 C:手动指定
- 你提供每张卡牌的具体内容
- 我帮你格式化并添加到 CSV 中
### 选项 D:基于现有卡牌扩展
- 如果已有部分卡牌,可以基于它们生成相似的卡牌
- 保持风格一致性
---
**示例输出:**
假设你的卡牌组有以下字段:name, type, cost, effect
生成 3 张"森林生物"主题的卡牌可能如下:
\`\`\`json
[
{
"label": "1",
"name": "荆棘狼",
"type": "生物",
"cost": "3",
"effect": "当荆棘狼进入战场时,对目标对手造成 1 点伤害"
},
{
"label": "2",
"name": "树精长老",
"type": "生物",
"cost": "5",
"effect": "树精长老具有 +0/+3 和'横置:回复 1 点生命值'"
},
{
"label": "3",
"name": "森林之灵",
"type": "生物",
"cost": "2",
"effect": "飞行,当森林之灵离场时,将一个 1/1 的孢子衍生物放入战场"
}
]
\`\`\`
---
请告诉我:
1. 你选择的生成方式(A/B/C/D)
2. 如果是选项 B,请提供具体主题
3. 是否有特殊要求(如:费用曲线、类型分布等)`
}
}
];
return { messages };
}
/**
* 获取 prompt 的元数据
*/
export function getPopulateDeckPrompt() {
return {
name: 'populate-deck',
title: '填充卡牌内容',
description: '为已有的卡牌组生成和填充卡牌内容',
arguments: [
{
name: 'csv_file',
description: 'CSV 文件路径',
required: false
},
{
name: 'card_count',
description: '要生成的卡牌数量',
required: false
},
{
name: 'theme',
description: '卡牌主题/描述',
required: false
}
]
};
}
+195
View File
@@ -0,0 +1,195 @@
/**
* setup-deck-display Prompt
*
* 引导用户配置卡牌的显示参数(尺寸、布局、样式等)
*/
export interface SetupDeckDisplayOptions {
/**
* CSV 文件路径
*/
csv_file?: string;
/**
* 卡牌用途
*/
usage?: string;
}
export interface SetupDeckDisplayResult {
messages: PromptMessage[];
}
export interface PromptMessage {
role: 'user' | 'assistant';
content: TextContent | ImageContent | AudioContent | ResourceContent;
}
export interface TextContent {
type: 'text';
text: string;
}
export interface ImageContent {
type: 'image';
data: string;
mimeType: string;
}
export interface AudioContent {
type: 'audio';
data: string;
mimeType: string;
}
export interface ResourceContent {
type: 'resource';
resource: {
uri: string;
mimeType: string;
text?: string;
blob?: string;
};
}
/**
* 生成 setup-deck-display prompt 的消息
*/
export function setupDeckDisplay(options?: SetupDeckDisplayOptions): SetupDeckDisplayResult {
const csvFile = options?.csv_file || './content/deck.csv';
const usage = options?.usage || '桌面游戏';
const messages: PromptMessage[] = [
{
role: 'user',
content: {
type: 'text',
text: `我想配置"${csvFile}"卡牌组的显示参数,主要用于"${usage}"。请帮我设置合适的尺寸和布局。`
}
},
{
role: 'assistant',
content: {
type: 'text',
text: `好的!我来帮你配置"${csvFile}"卡牌组的显示参数。
## 卡牌尺寸选择
首先,选择卡牌的标准尺寸:
### 常见卡牌尺寸
| 尺寸名称 | 规格 (mm) | 用途 |
|---------|----------|------|
| 桥牌尺寸 | 57x89 | 传统扑克牌、桌游手牌 |
| 标准尺寸 | 63x88 | 万智牌、游戏王等集换式卡牌 |
| 迷你尺寸 | 44x68 | 小型道具卡、资源标记 |
| 方形尺寸 | 57x57 | 特殊机制卡 |
| 塔罗尺寸 | 70x120 | 塔罗牌、神谕卡 |
| 自定义 | 输入尺寸 | 特殊需求 |
---
## 网格布局
选择打印时的网格布局(每张 A4 纸的排列):
| 卡牌尺寸 | 推荐布局 | 每张 A4 数量 |
|---------|---------|-------------|
| 57x89 | 5 列 x 6 行 | 30 张 |
| 63x88 | 5 列 x 5 行 | 25 张 |
| 44x68 | 6 列 x 8 行 | 48 张 |
| 57x57 | 6 列 x 6 行 | 36 张 |
| 70x120 | 3 列 x 4 行 | 12 张 |
---
## 高级选项
### 出血边距 (Bleed)
- 标准:1mm(推荐)
- 无出血:0mm
- 大出血:2-3mm(专业印刷)
### 内边距 (Padding)
- 标准:2mm(推荐)
- 紧凑:1mm
- 宽松:3-4mm
### 卡牌形状
- rectangle(矩形)- 默认
- circle(圆形)
- hex(六边形)
- diamond(菱形)
---
## 图层配置(可选)
如果你需要在卡牌上自动排版文字,可以配置图层:
格式:\`字段名:起始行 - 结束行,字体大小\`
示例:
\`\`\`
layers="name:1-2,14 type:3-3,10 effect:4-8,9"
\`\`\`
这会将:
- name 字段放在第 1-2 行,14 号字体
- type 字段放在第 3 行,10 号字体
- effect 字段放在第 4-8 行,9 号字体
---
**请告诉我:**
1. 选择的卡牌尺寸(或自定义尺寸)
2. 选择的网格布局
3. 是否需要调整出血/内边距
4. 是否需要配置自动排版图层
---
**示例配置:**
\`\`\`json
{
"deck": {
"size": "63x88",
"grid": "5x5",
"bleed": 1,
"padding": 2,
"shape": "rectangle",
"layers": "name:1-2,14 type:3-3,10 effect:4-8,9"
}
}
\`\`\``
}
}
];
return { messages };
}
/**
* 获取 prompt 的元数据
*/
export function getSetupDeckDisplayPrompt() {
return {
name: 'setup-deck-display',
title: '配置卡牌显示',
description: '引导用户配置卡牌的显示参数(尺寸、布局、样式等)',
arguments: [
{
name: 'csv_file',
description: 'CSV 文件路径',
required: false
},
{
name: 'usage',
description: '卡牌用途(如:桌面游戏、印刷、在线预览等)',
required: false
}
]
};
}