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
22 changes: 22 additions & 0 deletions lib/mcp/getCallToolResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { TextContent } from "@modelcontextprotocol/sdk/types.js";

export type CallToolResult = {
content: TextContent[];
};

/**
* Creates the base structure for an MCP tool result.
*
* @param text - The text content to include in the response
* @returns An MCP tool response structure
*/
export function getCallToolResult(text: string): CallToolResult {
return {
content: [
{
type: "text" as const,
text,
},
],
};
}
16 changes: 16 additions & 0 deletions lib/mcp/getToolResultError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CallToolResult, getCallToolResult } from "./getCallToolResult";

/**
* Creates a standardized error response for MCP tools.
*
* @param message - The error message to return
* @returns An MCP tool response with error content
*/
export function getToolResultError(message: string): CallToolResult {
return getCallToolResult(
JSON.stringify({
success: false,
message,
}),
);
}
11 changes: 11 additions & 0 deletions lib/mcp/getToolResultSuccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CallToolResult, getCallToolResult } from "./getCallToolResult";

/**
* Creates a standardized success response for MCP tools.
*
* @param data - The data to return
* @returns An MCP tool response with success content
*/
export function getToolResultSuccess(data: unknown): CallToolResult {
return getCallToolResult(JSON.stringify(data));
}
10 changes: 2 additions & 8 deletions lib/mcp/tools/catalogs/registerGetCatalogSongsTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getCatalogSongsQuerySchema,
type GetCatalogSongsQuery,
} from "@/lib/catalog/validateGetCatalogSongsQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "select_catalog_songs" tool on the MCP server.
Expand Down Expand Up @@ -41,14 +42,7 @@ export function registerGetCatalogSongsTool(server: McpServer): void {
criteria: args.criteria,
});

return {
content: [
{
type: "text",
text: JSON.stringify(response),
},
],
};
return getToolResultSuccess(response);
},
);
}
11 changes: 2 additions & 9 deletions lib/mcp/tools/catalogs/registerGetCatalogsTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type GetCatalogsQuery,
} from "@/lib/catalog/validateGetCatalogsQuery";
import { selectAccountCatalogs } from "@/lib/supabase/account_catalogs/selectAccountCatalogs";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";
/**
* Registers the "select_catalogs" tool on the MCP server.
* Retrieves catalogs associated with the current account for ANY music recommendation request.
Expand All @@ -28,15 +29,7 @@ export function registerGetCatalogsTool(server: McpServer): void {
},
async (args: GetCatalogsQuery) => {
const data = await selectAccountCatalogs({ accountIds: [args.account_id] });

return {
content: [
{
type: "text",
text: JSON.stringify(data),
},
],
};
return getToolResultSuccess(data);
},
);
}
11 changes: 2 additions & 9 deletions lib/mcp/tools/catalogs/registerInsertCatalogSongsTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
insertCatalogSongsQuerySchema,
type InsertCatalogSongsQuery,
} from "@/lib/catalog/validateInsertCatalogSongsQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "insert_catalog_songs" tool on the MCP server.
Expand Down Expand Up @@ -33,15 +34,7 @@ export function registerInsertCatalogSongsTool(server: McpServer): void {
},
async (args: InsertCatalogSongsQuery) => {
const response = await insertCatalogSongsFunction(args.songs);

return {
content: [
{
type: "text",
text: JSON.stringify(response),
},
],
};
return getToolResultSuccess(response);
},
);
}
13 changes: 4 additions & 9 deletions lib/mcp/tools/images/registerEditImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
type GenerateAndProcessImageResult,
} from "@/lib/image/generateAndProcessImage";
import { editImageQuerySchema, type EditImageQuery } from "@/lib/image/validateEditImageQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";
import { CallToolResult } from "@/lib/mcp/getCallToolResult";

/**
* Registers the "edit_image" tool on the MCP server.
Expand All @@ -18,7 +20,7 @@ export function registerEditImageTool(server: McpServer): void {
inputSchema: editImageQuerySchema,
description: "Edit existing images.",
},
async (args: EditImageQuery): Promise<{ content: Array<{ type: "text"; text: string }> }> => {
async (args: EditImageQuery): Promise<CallToolResult> => {
const result: GenerateAndProcessImageResult = await generateAndProcessImage(
args.prompt,
args.account_id,
Expand All @@ -30,14 +32,7 @@ export function registerEditImageTool(server: McpServer): void {
],
);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}
10 changes: 2 additions & 8 deletions lib/mcp/tools/images/registerGenerateImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
generateImageQuerySchema,
type GenerateImageQuery,
} from "@/lib/image/validateGenerateImageQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "generate_image" tool on the MCP server.
Expand All @@ -27,14 +28,7 @@ export function registerGenerateImageTool(server: McpServer): void {
args.account_id,
);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}
12 changes: 2 additions & 10 deletions lib/mcp/tools/registerContactTeamTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
contactTeamQuerySchema,
type ContactTeamQuery,
} from "@/lib/contact/validateContactTeamQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "contact_team" tool on the MCP server.
Expand All @@ -21,16 +22,7 @@ export function registerContactTeamTool(server: McpServer): void {
},
async (args: ContactTeamQuery) => {
const result = await contactTeam(args);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}

3 changes: 2 additions & 1 deletion lib/mcp/tools/registerGetArtistSocialsTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ArtistSocialsQuery,
artistSocialsQuerySchema,
} from "@/lib/artist/validateArtistSocialsQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "get_artist_socials" tool on the MCP server.
Expand All @@ -21,7 +22,7 @@ export function registerGetArtistSocialsTool(server: McpServer): void {
},
async (args: ArtistSocialsQuery) => {
const result = await getArtistSocials(args);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
return getToolResultSuccess(result);
},
);
}
3 changes: 2 additions & 1 deletion lib/mcp/tools/registerGetLocalTimeTool.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { getLocalTime } from "@/lib/time/getLocalTime";
import { GetLocalTimeQuery, getLocalTimeQuerySchema } from "@/lib/time/validateGetLocalTimeQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "get_local_time" tool on the MCP server.
Expand All @@ -18,7 +19,7 @@ export function registerGetLocalTimeTool(server: McpServer): void {
},
async (args: GetLocalTimeQuery) => {
const result = await getLocalTime(args);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
return getToolResultSuccess(result);
},
);
}
11 changes: 2 additions & 9 deletions lib/mcp/tools/sora2/registerGenerateVideoTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
generateVideoQuerySchema,
type GenerateVideoQuery,
} from "@/lib/video/validateGenerateVideoQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "generate_sora_2_video" tool on the MCP server.
Expand All @@ -28,15 +29,7 @@ export function registerGenerateVideoTool(server: McpServer): void {
},
async (args: GenerateVideoQuery) => {
const result = await generateVideoFunction(args);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}
11 changes: 2 additions & 9 deletions lib/mcp/tools/sora2/registerRetrieveVideoContentTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
retrieveVideoQuerySchema,
type RetrieveVideoQuery,
} from "@/lib/video/validateRetrieveVideoQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "retrieve_sora_2_video_content" tool on the MCP server.
Expand Down Expand Up @@ -31,15 +32,7 @@ export function registerRetrieveVideoContentTool(server: McpServer): void {
},
async (args: RetrieveVideoQuery) => {
const result = await retrieveVideoContentFunction(args);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}
11 changes: 2 additions & 9 deletions lib/mcp/tools/sora2/registerRetrieveVideoTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
retrieveVideoQuerySchema,
type RetrieveVideoQuery,
} from "@/lib/video/validateRetrieveVideoQuery";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

/**
* Registers the "retrieve_sora_2_video" tool on the MCP server.
Expand All @@ -30,15 +31,7 @@ export function registerRetrieveVideoTool(server: McpServer): void {
},
async (args: RetrieveVideoQuery) => {
const result = await retrieveVideoFunction(args);

return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
return getToolResultSuccess(result);
},
);
}
2 changes: 2 additions & 0 deletions lib/mcp/tools/spotify/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerGetSpotifySearchTool } from "./registerGetSpotifySearchTool";
import { registerGetSpotifyArtistTopTracksTool } from "./registerGetSpotifyArtistTopTracksTool";
import { registerGetSpotifyArtistAlbumsTool } from "./registerGetSpotifyArtistAlbumsTool";
import { registerGetSpotifyAlbumTool } from "./registerGetSpotifyAlbumTool";

/**
* Registers all Spotify-related MCP tools on the server.
Expand All @@ -12,4 +13,5 @@ export const registerAllSpotifyTools = (server: McpServer): void => {
registerGetSpotifySearchTool(server);
registerGetSpotifyArtistTopTracksTool(server);
registerGetSpotifyArtistAlbumsTool(server);
registerGetSpotifyAlbumTool(server);
};
61 changes: 61 additions & 0 deletions lib/mcp/tools/spotify/registerGetSpotifyAlbumTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import generateAccessToken from "@/lib/spotify/generateAccessToken";
import getAlbum from "@/lib/spotify/getAlbum";
import { getToolResultError } from "@/lib/mcp/getToolResultError";
import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess";

// Zod schema for the MCP tool - matches the original tool interface
const getSpotifyAlbumSchema = z.object({
id: z.string().min(1, "Album ID is required"),
market: z.string().length(2).optional().describe("ISO 3166-1 alpha-2 country code"),
});

type GetSpotifyAlbumArgs = z.infer<typeof getSpotifyAlbumSchema>;

/**
* Registers the "get_spotify_album" tool on the MCP server.
* Retrieve Spotify catalog information for a single album.
* You should call get_spotify_artist_albums or get_spotify_search first in order to get an album ID to use in the tool call.
*
* @param server - The MCP server instance to register the tool on.
*/
export function registerGetSpotifyAlbumTool(server: McpServer): void {
server.registerTool(
"get_spotify_album",
{
description:
"Retrieve Spotify catalog information for a single album. You should call get_spotify_artist_albums or get_spotify_search first in order to get an album ID to use in the tool call.",
inputSchema: getSpotifyAlbumSchema,
},
async (args: GetSpotifyAlbumArgs) => {
try {
// Generate Spotify access token
const tokenResult = await generateAccessToken();

if (!tokenResult || tokenResult.error || !tokenResult.access_token) {
return getToolResultError("Failed to generate Spotify access token");
}

// Call Spotify API to get album
const { album, error } = await getAlbum({
id: args.id,
market: args.market,
accessToken: tokenResult.access_token,
});

if (error || !album) {
return getToolResultError(error?.message || "Failed to fetch Spotify album");
}

// Return the album data directly
return getToolResultSuccess(album);
} catch (error) {
console.error("Error fetching Spotify album:", error);
return getToolResultError(
error instanceof Error ? error.message : "Failed to fetch Spotify album",
);
}
},
);
}
Loading