Skip to main content
Glama
brianellin

Bluesky MCP Server

by brianellin

get-liked-posts

Retrieve a list of posts liked by the authenticated user, with a customizable limit of 1 to 100 posts, using the Bluesky MCP Server's API.

Instructions

Get a list of posts that the authenticated user has liked

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of liked posts to fetch (1-100)

Implementation Reference

  • src/index.ts:502-582 (registration)
    Registers the 'get-liked-posts' MCP tool with schema and inline handler function that fetches user's liked posts via Bluesky API.
    server.tool( "get-liked-posts", "Get a list of posts that the authenticated user has liked", { limit: z.number().min(1).max(100).default(50).describe("Maximum number of liked posts to fetch (1-100)"), }, async ({ limit }) => { if (!agent) { return mcpErrorResponse("Not logged in. Please check your environment variables."); } const currentAgent = agent; // Assign to non-null variable to satisfy TypeScript try { // We can only get likes for the authenticated user if (!currentAgent.session?.handle) { return mcpErrorResponse("Not properly authenticated. Please check your credentials."); } const authenticatedUser = currentAgent.session.handle; // Now fetch the authenticated user's likes with pagination const MAX_BATCH_SIZE = 100; // Maximum number of likes per API call const MAX_BATCHES = 5; // Maximum number of API calls to make (100 x 5 = 500) let allLikes: any[] = []; let nextCursor: string | undefined = undefined; let batchCount = 0; // Loop to fetch likes with pagination while (batchCount < MAX_BATCHES && allLikes.length < limit) { // Calculate how many likes to fetch in this batch const batchLimit = Math.min(MAX_BATCH_SIZE, limit - allLikes.length); // Make the API call with cursor if we have one const response = await currentAgent.app.bsky.feed.getActorLikes({ actor: authenticatedUser, limit: batchLimit, cursor: nextCursor || undefined }); if (!response.success) { // If we've already fetched some likes, return those if (allLikes.length > 0) { break; } return mcpErrorResponse(`Failed to fetch your likes.`); } const { feed, cursor } = response.data; // Add the fetched likes to our collection allLikes = allLikes.concat(feed); // Update cursor for the next batch nextCursor = cursor; batchCount++; // If no cursor returned or we've reached our limit, stop paginating if (!cursor || allLikes.length >= limit) { break; } } if (allLikes.length === 0) { return mcpSuccessResponse(`You haven't liked any posts.`); } // Format the likes list using preprocessPosts const formattedLikes = preprocessPosts(allLikes); // Create a summary const summaryText = formatSummaryText(allLikes.length, "liked posts"); return mcpSuccessResponse(`${summaryText}\n\n${formattedLikes}`); } catch (error) { return mcpErrorResponse(`Error fetching likes: ${error instanceof Error ? error.message : String(error)}`); } } );
  • Handler function implements the core logic: authenticates, paginates getActorLikes API calls for the user's likes, preprocesses posts for display, and returns formatted summary.
    async ({ limit }) => { if (!agent) { return mcpErrorResponse("Not logged in. Please check your environment variables."); } const currentAgent = agent; // Assign to non-null variable to satisfy TypeScript try { // We can only get likes for the authenticated user if (!currentAgent.session?.handle) { return mcpErrorResponse("Not properly authenticated. Please check your credentials."); } const authenticatedUser = currentAgent.session.handle; // Now fetch the authenticated user's likes with pagination const MAX_BATCH_SIZE = 100; // Maximum number of likes per API call const MAX_BATCHES = 5; // Maximum number of API calls to make (100 x 5 = 500) let allLikes: any[] = []; let nextCursor: string | undefined = undefined; let batchCount = 0; // Loop to fetch likes with pagination while (batchCount < MAX_BATCHES && allLikes.length < limit) { // Calculate how many likes to fetch in this batch const batchLimit = Math.min(MAX_BATCH_SIZE, limit - allLikes.length); // Make the API call with cursor if we have one const response = await currentAgent.app.bsky.feed.getActorLikes({ actor: authenticatedUser, limit: batchLimit, cursor: nextCursor || undefined }); if (!response.success) { // If we've already fetched some likes, return those if (allLikes.length > 0) { break; } return mcpErrorResponse(`Failed to fetch your likes.`); } const { feed, cursor } = response.data; // Add the fetched likes to our collection allLikes = allLikes.concat(feed); // Update cursor for the next batch nextCursor = cursor; batchCount++; // If no cursor returned or we've reached our limit, stop paginating if (!cursor || allLikes.length >= limit) { break; } } if (allLikes.length === 0) { return mcpSuccessResponse(`You haven't liked any posts.`); } // Format the likes list using preprocessPosts const formattedLikes = preprocessPosts(allLikes); // Create a summary const summaryText = formatSummaryText(allLikes.length, "liked posts"); return mcpSuccessResponse(`${summaryText}\n\n${formattedLikes}`); } catch (error) { return mcpErrorResponse(`Error fetching likes: ${error instanceof Error ? error.message : String(error)}`); } } );
  • Zod schema for tool input parameters defining the 'limit' for number of liked posts.
    { limit: z.number().min(1).max(100).default(50).describe("Maximum number of liked posts to fetch (1-100)"), },
  • Uses preprocessPosts helper from llm-preprocessor.ts to format the fetched liked posts for output.
    const formattedLikes = preprocessPosts(allLikes);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/brianellin/bsky-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server