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