Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/mcp/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { registerAllTaskTools } from "./tasks";
import { registerAllImageTools } from "./images";
import { registerAllCatalogTools } from "./catalogs";
import { registerAllSora2Tools } from "./sora2";
import { registerAllSpotifyTools } from "./spotify";
import { registerContactTeamTool } from "./registerContactTeamTool";

/**
Expand All @@ -20,5 +21,6 @@ export const registerAllTools = (server: McpServer): void => {
registerAllImageTools(server);
registerAllCatalogTools(server);
registerAllSora2Tools(server);
registerAllSpotifyTools(server);
registerContactTeamTool(server);
};
11 changes: 11 additions & 0 deletions lib/mcp/tools/spotify/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerGetSpotifySearchTool } from "./registerGetSpotifySearchTool";

/**
* Registers all Spotify-related MCP tools on the server.
*
* @param server - The MCP server instance to register tools on.
*/
export const registerAllSpotifyTools = (server: McpServer): void => {
registerGetSpotifySearchTool(server);
};
118 changes: 118 additions & 0 deletions lib/mcp/tools/spotify/registerGetSpotifySearchTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import generateAccessToken from "@/lib/spotify/generateAccessToken";
import getSearch from "@/lib/spotify/getSearch";

// Supported Spotify search types
const SPOTIFY_TYPES = [
"album",
"artist",
"playlist",
"track",
"show",
"episode",
"audiobook",
] as const;

// Zod schema for the MCP tool - matches the original tool interface
const getSpotifySearchSchema = z.object({
name: z.string().min(1, "Search query is required"),
type: z.array(z.enum(SPOTIFY_TYPES)).min(1, "At least one type is required"),
limit: z.number().min(1).max(50).optional().default(5),
});

type GetSpotifySearchArgs = z.infer<typeof getSpotifySearchSchema>;

/**
* Registers the "get_spotify_search" tool on the MCP server.
* Search for Spotify items (artist, album, track, playlist, etc.) by name.
* Returns results for each requested type.
*
* @param server - The MCP server instance to register the tool on.
*/
export function registerGetSpotifySearchTool(server: McpServer): void {
server.registerTool(
"get_spotify_search",
{
description:
"Search for Spotify items (artist, album, track, playlist, etc.) by name. Returns results for each requested type.",
inputSchema: getSpotifySearchSchema,
},
async (args: GetSpotifySearchArgs) => {
try {
// Generate Spotify access token
const tokenResult = await generateAccessToken();

if (!tokenResult || tokenResult.error || !tokenResult.access_token) {
return {
content: [
{
type: "text",
text: JSON.stringify({
success: false,
message: "Failed to generate Spotify access token",
}),
},
],
};
}

// Convert type array to comma-separated string for API
const typeString = args.type.join(",");

// Call Spotify search API
const { data, error } = await getSearch({
q: args.name,
type: typeString,
limit: args.limit,
accessToken: tokenResult.access_token,
});

if (error || !data) {
return {
content: [
{
type: "text",
text: JSON.stringify({
success: false,
message: error?.message || "Failed to search Spotify",
}),
},
],
};
}

// Filter results to only include requested types (matching original tool behavior)
const result: Record<string, unknown> = { success: true };
for (const t of args.type) {
const key = `${t}s`;
if (data[key]) {
result[key] = data[key];
}
}

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
} catch (error) {
console.error("Error searching Spotify:", error);
return {
content: [
{
type: "text",
text: JSON.stringify({
success: false,
message: error instanceof Error ? error.message : "Failed to search Spotify",
}),
},
],
};
}
},
);
}