index.ts•9.76 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';
import { MusicDatabase } from './music-database.js';
import { PlaylistManager } from './playlist-manager.js';
class MusicMCPServer {
private server: Server;
private musicDb: MusicDatabase;
private playlistManager: PlaylistManager;
constructor() {
this.server = new Server(
{
name: 'music-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.musicDb = new MusicDatabase();
this.playlistManager = new PlaylistManager();
this.setupToolHandlers();
}
private setupToolHandlers() {
// 列出所有可用工具
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'search_music',
description: '搜索音乐,支持按歌曲名、艺术家、专辑搜索',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索关键词',
},
type: {
type: 'string',
enum: ['song', 'artist', 'album', 'all'],
description: '搜索类型',
default: 'all',
},
limit: {
type: 'number',
description: '返回结果数量限制',
default: 10,
},
},
required: ['query'],
},
},
{
name: 'get_song_info',
description: '获取歌曲详细信息',
inputSchema: {
type: 'object',
properties: {
songId: {
type: 'string',
description: '歌曲ID',
},
},
required: ['songId'],
},
},
{
name: 'create_playlist',
description: '创建新的播放列表',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: '播放列表名称',
},
description: {
type: 'string',
description: '播放列表描述',
},
},
required: ['name'],
},
},
{
name: 'add_to_playlist',
description: '将歌曲添加到播放列表',
inputSchema: {
type: 'object',
properties: {
playlistId: {
type: 'string',
description: '播放列表ID',
},
songId: {
type: 'string',
description: '歌曲ID',
},
},
required: ['playlistId', 'songId'],
},
},
{
name: 'get_playlist',
description: '获取播放列表信息',
inputSchema: {
type: 'object',
properties: {
playlistId: {
type: 'string',
description: '播放列表ID',
},
},
required: ['playlistId'],
},
},
{
name: 'list_playlists',
description: '列出所有播放列表',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'get_recommendations',
description: '根据用户喜好获取音乐推荐',
inputSchema: {
type: 'object',
properties: {
genre: {
type: 'string',
description: '音乐风格',
},
mood: {
type: 'string',
description: '心情/氛围',
},
limit: {
type: 'number',
description: '推荐数量',
default: 10,
},
},
},
},
],
};
});
// 处理工具调用
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'search_music':
return await this.handleSearchMusic(args);
case 'get_song_info':
return await this.handleGetSongInfo(args);
case 'create_playlist':
return await this.handleCreatePlaylist(args);
case 'add_to_playlist':
return await this.handleAddToPlaylist(args);
case 'get_playlist':
return await this.handleGetPlaylist(args);
case 'list_playlists':
return await this.handleListPlaylists(args);
case 'get_recommendations':
return await this.handleGetRecommendations(args);
default:
throw new Error(`未知的工具: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: `错误: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
}
private async handleSearchMusic(args: any) {
const { query, type = 'all', limit = 10 } = args;
const results = await this.musicDb.search(query, type, limit);
return {
content: [
{
type: 'text',
text: `搜索结果 "${query}":\n\n${results.map(song =>
`🎵 ${song.title}\n👤 艺术家: ${song.artist}\n💿 专辑: ${song.album}\n⏱️ 时长: ${song.duration}\n🆔 ID: ${song.id}\n`
).join('\n')}`,
},
],
};
}
private async handleGetSongInfo(args: any) {
const { songId } = args;
const song = await this.musicDb.getSongById(songId);
if (!song) {
throw new Error(`未找到ID为 ${songId} 的歌曲`);
}
return {
content: [
{
type: 'text',
text: `🎵 歌曲信息:\n\n标题: ${song.title}\n艺术家: ${song.artist}\n专辑: ${song.album}\n发行年份: ${song.year}\n时长: ${song.duration}\n风格: ${song.genre}\n播放次数: ${song.playCount}\n评分: ${song.rating}/5`,
},
],
};
}
private async handleCreatePlaylist(args: any) {
const { name, description } = args;
const playlist = await this.playlistManager.createPlaylist(name, description);
return {
content: [
{
type: 'text',
text: `✅ 播放列表创建成功!\n\n名称: ${playlist.name}\n描述: ${playlist.description || '无'}\nID: ${playlist.id}\n创建时间: ${playlist.createdAt}`,
},
],
};
}
private async handleAddToPlaylist(args: any) {
const { playlistId, songId } = args;
await this.playlistManager.addSongToPlaylist(playlistId, songId);
const song = await this.musicDb.getSongById(songId);
return {
content: [
{
type: 'text',
text: `✅ 歌曲已添加到播放列表!\n\n歌曲: ${song?.title} - ${song?.artist}`,
},
],
};
}
private async handleGetPlaylist(args: any) {
const { playlistId } = args;
const playlist = await this.playlistManager.getPlaylist(playlistId);
if (!playlist) {
throw new Error(`未找到ID为 ${playlistId} 的播放列表`);
}
const songs = await Promise.all(
playlist.songIds.map(id => this.musicDb.getSongById(id))
);
return {
content: [
{
type: 'text',
text: `🎵 播放列表: ${playlist.name}\n\n描述: ${playlist.description || '无'}\n歌曲数量: ${playlist.songIds.length}\n创建时间: ${playlist.createdAt}\n\n歌曲列表:\n${songs.map((song, index) =>
`${index + 1}. ${song?.title} - ${song?.artist}`
).join('\n')}`,
},
],
};
}
private async handleListPlaylists(args: any) {
const playlists = await this.playlistManager.getAllPlaylists();
return {
content: [
{
type: 'text',
text: `📋 所有播放列表:\n\n${playlists.map(playlist =>
`🎵 ${playlist.name}\n📝 ${playlist.description || '无描述'}\n🎶 ${playlist.songIds.length} 首歌曲\n🆔 ID: ${playlist.id}\n`
).join('\n')}`,
},
],
};
}
private async handleGetRecommendations(args: any) {
const { genre, mood, limit = 10 } = args;
const recommendations = await this.musicDb.getRecommendations(genre, mood, limit);
return {
content: [
{
type: 'text',
text: `🎯 音乐推荐${genre ? ` (${genre})` : ''}${mood ? ` - ${mood}心情` : ''}:\n\n${recommendations.map(song =>
`🎵 ${song.title}\n👤 ${song.artist}\n💿 ${song.album}\n⭐ ${song.rating}/5\n🆔 ${song.id}\n`
).join('\n')}`,
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('音乐 MCP 服务器已启动');
}
}
const server = new MusicMCPServer();
server.run().catch(console.error);