#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
CallToolResult,
} from "@modelcontextprotocol/sdk/types.js";
import { SpotifyClient } from "./spotify-client.js";
import dotenv from "dotenv";
dotenv.config();
const server = new Server(
{
name: "spotify-api-mcp",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
const spotifyClient = new SpotifyClient();
const TOOLS: Tool[] = [
{
name: "spotify_search",
description: "Search for tracks, artists, albums, or playlists on Spotify",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search query",
},
type: {
type: "string",
enum: ["track", "artist", "album", "playlist"],
description: "Type of content to search for",
},
limit: {
type: "number",
description: "Maximum number of results (1-50)",
minimum: 1,
maximum: 50,
default: 10,
},
},
required: ["query", "type"],
},
},
{
name: "spotify_authenticate",
description: "Authenticate with Spotify using OAuth 2.0",
inputSchema: {
type: "object",
properties: {
client_id: {
type: "string",
description: "Spotify client ID",
},
client_secret: {
type: "string",
description: "Spotify client secret",
},
},
required: ["client_id", "client_secret"],
},
},
{
name: "spotify_get_user_profile",
description: "Get the current user's profile information",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "spotify_create_playlist",
description: "Create a new playlist for the authenticated user",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "Name of the playlist",
},
description: {
type: "string",
description: "Description of the playlist",
},
public: {
type: "boolean",
description: "Whether the playlist should be public",
default: false,
},
},
required: ["name"],
},
},
{
name: "spotify_add_tracks_to_playlist",
description: "Add tracks to a playlist",
inputSchema: {
type: "object",
properties: {
playlist_id: {
type: "string",
description: "ID of the playlist",
},
track_uris: {
type: "array",
items: {
type: "string",
},
description: "Array of Spotify track URIs to add",
},
},
required: ["playlist_id", "track_uris"],
},
},
{
name: "spotify_get_user_playlists",
description: "Get the current user's playlists",
inputSchema: {
type: "object",
properties: {
limit: {
type: "number",
description: "Maximum number of playlists to return (1-50)",
minimum: 1,
maximum: 50,
default: 20,
},
},
},
},
];
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: TOOLS,
};
});
server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "spotify_search":
return await spotifyClient.search(args?.query as string, args?.type as string, args?.limit as number);
case "spotify_authenticate":
const clientId = args?.client_id as string || process.env.SPOTIFY_CLIENT_ID;
const clientSecret = args?.client_secret as string || process.env.SPOTIFY_CLIENT_SECRET;
if (!clientId || !clientSecret) {
throw new Error("Spotify credentials not found. Please provide client_id and client_secret, or set SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET environment variables.");
}
return await spotifyClient.authenticate(clientId, clientSecret);
case "spotify_get_user_profile":
return await spotifyClient.getUserProfile();
case "spotify_create_playlist":
return await spotifyClient.createPlaylist(args?.name as string, args?.description as string, args?.public as boolean);
case "spotify_add_tracks_to_playlist":
return await spotifyClient.addTracksToPlaylist(args?.playlist_id as string, args?.track_uris as string[]);
case "spotify_get_user_playlists":
return await spotifyClient.getUserPlaylists(args?.limit as number);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text" as const,
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((error) => {
console.error("Server error:", error);
process.exit(1);
});