Skip to main content
Glama
bh-rat

context-awesome

by bh-rat

Get Awesome List Items

get_awesome_items

Retrieve curated resources from awesome lists with token control and filtering options. Use after discovering sections or with explicit repository/ID input.

Instructions

Retrieves items from a specific awesome list or section with token limiting. You must call 'find_awesome_section' first to discover available sections, UNLESS the user explicitly provides a githubRepo or listId.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
listIdNoUUID of the list (from find_awesome_section results)
githubRepoNoGitHub repo path (e.g., 'sindresorhus/awesome') from find_awesome_section results
sectionNoCategory/section name to filter
subcategoryNoSubcategory to filter
tokensNoMaximum number of tokens to return (default: 10000). Higher values provide more items but consume more tokens.
offsetNoPagination offset for retrieving more items

Implementation Reference

  • The MCP tool handler that processes input parameters, fetches items via API client, formats them into markdown with metadata, handles pagination and token limits, and returns structured content or error messages.
    async ({ listId, githubRepo, section, subcategory, tokens = DEFAULT_MINIMUM_TOKENS, offset = 0 }) => {
      if (!listId && !githubRepo) {
        return {
          content: [
            {
              type: "text",
              text: "Either listId or githubRepo must be provided. Use 'find_awesome_section' first to discover available lists and sections.",
            },
          ],
        };
      }
    
      try {
        const response = await apiClient.getItems({
          listId,
          githubRepo,
          section,
          subcategory,
          tokens,
          offset,
        });
        
        if (!response.items || response.items.length === 0) {
          return {
            content: [
              {
                type: "text",
                text: "No items found for the specified criteria. Try adjusting your filters or use find_awesome_section to discover available sections.",
              },
            ],
          };
        }
    
        const { metadata, items, tokenUsage } = response;
        
        const header =
          `# ${metadata.list.name}` +
          (metadata.section ? ` - ${metadata.section}` : '') +
          (metadata.subcategory ? ` > ${metadata.subcategory}` : '') +
          '\n\n';
    
        const listDescription = metadata.list.description
          ? `> ${metadata.list.description}\n\n`
          : '';
    
        const formattedItems = items
          .map((item, index) => {
            let itemText = `## ${index + 1}. ${item.name}\n\n`;
            
            if (item.description) {
              itemText += `${item.description}\n\n`;
            }
            
            itemText += `**URL**: ${item.url}\n`;
            
            if (item.githubRepo) {
              itemText += `**GitHub**: https://github.com/${item.githubRepo}\n`;
            }
            
            if (item.githubStars) {
              itemText += `**Stars**: ${item.githubStars.toLocaleString()}\n`;
            }
            
            if (item.tags && item.tags.length > 0) {
              itemText += `**Tags**: ${item.tags.join(', ')}\n`;
            }
            
            return itemText;
          })
          .join('\n---\n\n');
    
        const footer =
          `\n---\n\n` +
          `## Metadata\n\n` +
          `- **Token usage**: ${tokenUsage.used.toLocaleString()}/${tokenUsage.limit.toLocaleString()}` +
          (tokenUsage.truncated ? ' (truncated)' : '') +
          '\n' +
          `- **Items displayed**: ${items.length} of ${metadata.totalItems}\n` +
          (metadata.hasMore
            ? `- **Next page**: Use \`offset: ${metadata.offset + items.length}\` to get more items\n`
            : '');
    
        return {
          content: [
            {
              type: "text",
              text: header + listDescription + formattedItems + footer,
            },
          ],
        };
      } catch (error: any) {
        const apiError = error as APIError;
        return {
          content: [
            {
              type: "text",
              text: apiError.message || "Failed to retrieve items. Please check your parameters and try again.",
            },
          ],
        };
      }
    }
  • Zod schema for input validation of the tool parameters including listId, githubRepo, section, subcategory, tokens (with preprocessing and transformation), and offset.
    inputSchema: {
      listId: z
        .string()
        .optional()
        .describe("UUID of the list (from find_awesome_section results)"),
      githubRepo: z
        .string()
        .optional()
        .describe("GitHub repo path (e.g., 'sindresorhus/awesome') from find_awesome_section results"),
      section: z
        .string()
        .optional()
        .describe("Category/section name to filter"),
      subcategory: z
        .string()
        .optional()
        .describe("Subcategory to filter"),
      tokens: z
        .preprocess((val) => (typeof val === "string" ? Number(val) : val), z.number())
        .transform((val) => (val < DEFAULT_MINIMUM_TOKENS ? DEFAULT_MINIMUM_TOKENS : val))
        .optional()
        .describe(
          `Maximum number of tokens to return (default: ${DEFAULT_MINIMUM_TOKENS}). Higher values provide more items but consume more tokens.`
        ),
      offset: z
        .number()
        .min(0)
        .optional()
        .default(0)
        .describe("Pagination offset for retrieving more items"),
    },
  • src/index.ts:241-382 (registration)
    Registration of the get_awesome_items tool with the MCP server, including name, title, description, input schema, and handler reference.
    // Register get_awesome_items tool
    server.registerTool(
      "get_awesome_items",
      {
        title: "Get Awesome List Items",
        description:
          "Retrieves items from a specific awesome list or section with token limiting. You must call 'find_awesome_section' first to discover available sections, UNLESS the user explicitly provides a githubRepo or listId.",
        inputSchema: {
          listId: z
            .string()
            .optional()
            .describe("UUID of the list (from find_awesome_section results)"),
          githubRepo: z
            .string()
            .optional()
            .describe("GitHub repo path (e.g., 'sindresorhus/awesome') from find_awesome_section results"),
          section: z
            .string()
            .optional()
            .describe("Category/section name to filter"),
          subcategory: z
            .string()
            .optional()
            .describe("Subcategory to filter"),
          tokens: z
            .preprocess((val) => (typeof val === "string" ? Number(val) : val), z.number())
            .transform((val) => (val < DEFAULT_MINIMUM_TOKENS ? DEFAULT_MINIMUM_TOKENS : val))
            .optional()
            .describe(
              `Maximum number of tokens to return (default: ${DEFAULT_MINIMUM_TOKENS}). Higher values provide more items but consume more tokens.`
            ),
          offset: z
            .number()
            .min(0)
            .optional()
            .default(0)
            .describe("Pagination offset for retrieving more items"),
        },
      },
      async ({ listId, githubRepo, section, subcategory, tokens = DEFAULT_MINIMUM_TOKENS, offset = 0 }) => {
        if (!listId && !githubRepo) {
          return {
            content: [
              {
                type: "text",
                text: "Either listId or githubRepo must be provided. Use 'find_awesome_section' first to discover available lists and sections.",
              },
            ],
          };
        }
    
        try {
          const response = await apiClient.getItems({
            listId,
            githubRepo,
            section,
            subcategory,
            tokens,
            offset,
          });
          
          if (!response.items || response.items.length === 0) {
            return {
              content: [
                {
                  type: "text",
                  text: "No items found for the specified criteria. Try adjusting your filters or use find_awesome_section to discover available sections.",
                },
              ],
            };
          }
    
          const { metadata, items, tokenUsage } = response;
          
          const header =
            `# ${metadata.list.name}` +
            (metadata.section ? ` - ${metadata.section}` : '') +
            (metadata.subcategory ? ` > ${metadata.subcategory}` : '') +
            '\n\n';
    
          const listDescription = metadata.list.description
            ? `> ${metadata.list.description}\n\n`
            : '';
    
          const formattedItems = items
            .map((item, index) => {
              let itemText = `## ${index + 1}. ${item.name}\n\n`;
              
              if (item.description) {
                itemText += `${item.description}\n\n`;
              }
              
              itemText += `**URL**: ${item.url}\n`;
              
              if (item.githubRepo) {
                itemText += `**GitHub**: https://github.com/${item.githubRepo}\n`;
              }
              
              if (item.githubStars) {
                itemText += `**Stars**: ${item.githubStars.toLocaleString()}\n`;
              }
              
              if (item.tags && item.tags.length > 0) {
                itemText += `**Tags**: ${item.tags.join(', ')}\n`;
              }
              
              return itemText;
            })
            .join('\n---\n\n');
    
          const footer =
            `\n---\n\n` +
            `## Metadata\n\n` +
            `- **Token usage**: ${tokenUsage.used.toLocaleString()}/${tokenUsage.limit.toLocaleString()}` +
            (tokenUsage.truncated ? ' (truncated)' : '') +
            '\n' +
            `- **Items displayed**: ${items.length} of ${metadata.totalItems}\n` +
            (metadata.hasMore
              ? `- **Next page**: Use \`offset: ${metadata.offset + items.length}\` to get more items\n`
              : '');
    
          return {
            content: [
              {
                type: "text",
                text: header + listDescription + formattedItems + footer,
              },
            ],
          };
        } catch (error: any) {
          const apiError = error as APIError;
          return {
            content: [
              {
                type: "text",
                text: apiError.message || "Failed to retrieve items. Please check your parameters and try again.",
              },
            ],
          };
        }
      }
    );
  • Helper method in API client that performs HTTP GET to /api/get-items, normalizes response data, estimates and enforces token limits by truncating items, and structures the output for the tool handler.
    async getItems(params: GetItemsParams): Promise<GetItemsResponse> {
      this.log('Getting items with params:', params);
      
      if (!params.listId && !params.githubRepo) {
        const error: APIError = {
          code: 'INVALID_PARAMS',
          message: 'Either listId or githubRepo must be provided',
        };
        throw error;
      }
    
      const response = await this.request<any>('/api/get-items', {
        listId: params.listId,
        githubRepo: params.githubRepo,
        section: params.section,
        subcategory: params.subcategory,
        limit: params.tokens ? Math.floor(params.tokens / 50) : undefined,
        offset: params.offset,
      });
    
      const items = response.items || response.data || [];
      const metadata = response.metadata || response.meta || {};
      
      const tokenCount = this.estimateTokens(items);
      const tokenLimit = params.tokens || 10000;
      const truncated = tokenCount > tokenLimit;
      
      const truncatedItems = truncated 
        ? this.truncateToTokenLimit(items, tokenLimit)
        : items;
    
      return {
        items: truncatedItems.map((item: any) => ({
          id: item.id || item._id || '',
          name: item.name || item.title || '',
          description: item.description || '',
          url: item.url || item.link || '',
          githubStars: item.stars || item.githubStars || item.github_stars,
          githubRepo: item.repo || item.githubRepo || item.github_repo,
          tags: item.tags || [],
          lastUpdated: item.lastUpdated || item.updated_at || item.last_updated,
        })),
        metadata: {
          list: {
            id: metadata.listId || metadata.list_id || params.listId || '',
            name: metadata.listName || metadata.list_name || '',
            githubRepo: metadata.githubRepo || metadata.github_repo || params.githubRepo || '',
            description: metadata.description || '',
            totalItems: metadata.totalItems || metadata.total_items || items.length,
          },
          section: metadata.section || params.section,
          subcategory: metadata.subcategory || params.subcategory,
          totalItems: metadata.totalItems || metadata.total_items || items.length,
          offset: metadata.offset || params.offset || 0,
          hasMore: metadata.hasMore || metadata.has_more || false,
        },
        tokenUsage: {
          used: this.estimateTokens(truncatedItems),
          limit: tokenLimit,
          truncated,
        },
      };
    }
  • TypeScript interfaces defining input (GetItemsParams) and output (GetItemsResponse) structures used by the API client for type safety.
    export interface GetItemsParams {
      listId?: string;
      githubRepo?: string;
      section?: string;
      subcategory?: string;
      tokens?: number;
      offset?: number;
    }
    
    export interface AwesomeItem {
      id: string;
      name: string;
      description: string;
      url: string;
      githubStars?: number;
      githubRepo?: string;
      tags?: string[];
      lastUpdated?: string;
    }
    
    export interface ListMetadata {
      id: string;
      name: string;
      githubRepo: string;
      description?: string;
      totalItems: number;
    }
    
    export interface GetItemsResponse {
      items: AwesomeItem[];
      metadata: {
        list: ListMetadata;
        section?: string;
        subcategory?: string;
        totalItems: number;
        offset: number;
        hasMore: boolean;
      };
      tokenUsage: {
        used: number;
        limit: number;
        truncated: boolean;
      };
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key behaviors: the token limiting mechanism ('with token limiting'), the dependency on another tool ('call 'find_awesome_section' first'), and the conditional logic for parameters. However, it doesn't mention error handling, rate limits, or authentication needs, which are common gaps for retrieval tools.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise with two sentences that each serve distinct purposes: the first states the core functionality with a key constraint, and the second provides essential usage guidance. There is no wasted language, and information is front-loaded effectively.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (6 parameters, dependency on another tool) and lack of annotations/output schema, the description does well by covering purpose, usage guidelines, and key behavioral aspects. However, it doesn't describe the return format (e.g., structure of items, pagination details), which would be helpful since there's no output schema, leaving some gaps in completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 6 parameters thoroughly. The description adds minimal parameter semantics beyond the schema, only implying that 'githubRepo' and 'listId' come from 'find_awesome_section' results. This meets the baseline of 3 when schema coverage is high, but doesn't provide significant additional value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'retrieves' and the resource 'items from a specific awesome list or section', specifying the action and target. It distinguishes from the sibling tool 'find_awesome_section' by indicating this tool is for retrieving items after sections are identified, establishing a clear functional relationship.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool: 'You must call 'find_awesome_section' first to discover available sections, UNLESS the user explicitly provides a githubRepo or listId.' This provides clear prerequisites and alternatives, directly addressing the sibling tool relationship and user input scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/bh-rat/context-awesome'

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