Skip to main content
Glama
stampchain-io

Stampchain MCP Server

Official

search_tokens

Find SRC-20 tokens by ticker, deployer, holders, or mint percentage to identify Bitcoin Stamps assets matching specific criteria.

Instructions

Search for SRC-20 tokens with various filtering criteria

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryNoSearch query for token ticker
deployerNoFilter by deployer address
min_holdersNoMinimum number of holders
min_percent_mintedNoMinimum percent minted
sort_byNoSort field (Note: only deploy_timestamp is supported by the API)deploy_timestamp
sort_orderNoSort orderDESC
pageNoPage number
page_sizeNoItems per page

Implementation Reference

  • Core handler function that executes the search_tokens tool: validates input, builds API query params, calls stampchain API searchTokens, processes and formats results as text table and metadata JSON.
    public async execute(params: SearchTokensParams, context?: ToolContext): Promise<ToolResponse> {
      try {
        context?.logger?.info('Executing search_tokens tool', { params });
    
        // Validate parameters
        const validatedParams = this.validateParams(params);
    
        // Build query parameters
        const queryParams = {
          query: validatedParams.query,
          deployer: validatedParams.deployer,
          sort_by: validatedParams.sort_by,
          sort_order: validatedParams.sort_order,
          page: validatedParams.page,
          page_size: validatedParams.page_size,
        };
    
        // Remove undefined values
        Object.keys(queryParams).forEach((key) => {
          if (queryParams[key as keyof typeof queryParams] === undefined) {
            delete queryParams[key as keyof typeof queryParams];
          }
        });
    
        // Search tokens
        const searchResponse = await this.apiClient.searchTokens(queryParams);
    
        if (!searchResponse || searchResponse.length === 0) {
          return textResponse('No tokens found matching the search criteria');
        }
    
        // Note: searchTokens returns TokenResponse[] directly
        const tokens = searchResponse;
    
        // Note: Client-side filtering for unsupported API fields
        let filteredTokens = tokens;
        if (
          validatedParams.min_holders !== undefined ||
          validatedParams.min_percent_minted !== undefined
        ) {
          // These fields are not available in the current API response
          // Filtering will be skipped and a note will be added to the output
          filteredTokens = tokens;
        }
    
        // Create summary
        const lines = [`Found ${filteredTokens.length} tokens`];
        lines.push('---');
    
        // Create table view
        const tokenTable = createTable(filteredTokens, [
          { key: 'tick', label: 'Ticker' },
          { key: 'max', label: 'Max Supply' },
          { key: 'lim', label: 'Mint Limit' },
          { key: 'deci', label: 'Decimals' },
          {
            key: 'creator',
            label: 'Creator',
            format: (v: unknown) => (typeof v === 'string' ? v.substring(0, 8) + '...' : String(v)),
          },
        ]);
    
        lines.push(tokenTable);
    
        // Add detailed view for top tokens
        lines.push('\n\nDetailed View (Top 5):');
        lines.push('---');
    
        filteredTokens.slice(0, 5).forEach((token, index) => {
          lines.push(`\n${index + 1}. ${token.tick}`);
          lines.push(`   Protocol: ${token.p} | Operation: ${token.op}`);
          lines.push(`   Max Supply: ${token.max}`);
          if (token.lim) {
            lines.push(`   Mint Limit: ${token.lim}`);
          }
          if (token.deci !== undefined) {
            lines.push(`   Decimals: ${token.deci}`);
          }
          lines.push(`   Creator: ${token.creator}`);
          lines.push(`   Block Index: ${token.block_index}`);
          lines.push(`   Block Time: ${new Date(token.block_time).toLocaleString()}`);
          if (token.creator_name) {
            lines.push(`   Creator Name: ${token.creator_name}`);
          }
          if (token.destination_name) {
            lines.push(`   Destination: ${token.destination_name}`);
          }
        });
    
        // Include metadata
        const metadata = {
          results_count: filteredTokens.length,
          query_params: queryParams,
          note: 'Pagination and holder/minting statistics are not available in the current API response',
          additional_filters: {
            min_holders: validatedParams.min_holders,
            min_percent_minted: validatedParams.min_percent_minted,
          },
        };
    
        // Add note about unsupported filters
        if (
          validatedParams.min_holders !== undefined ||
          validatedParams.min_percent_minted !== undefined
        ) {
          lines.push(
            '\n⚠️  Note: Holder and minting percentage filters are not supported by the current API and have been ignored.'
          );
        }
    
        return multiResponse(
          { type: 'text', text: lines.join('\n') },
          { type: 'text', text: `\n\nSearch Metadata:\n${JSON.stringify(metadata, null, 2)}` }
        );
      } catch (error) {
        context?.logger?.error('Error executing search_tokens tool', { error });
    
        if (error instanceof ValidationError) {
          throw error;
        }
    
        throw new ToolExecutionError('Failed to search tokens', this.name, error);
      }
    }
  • Zod schema defining the input parameters and validation for the search_tokens tool.
    export const SearchTokensParamsSchema = z.object({
      query: z.string().optional().describe('Search query for token ticker'),
      deployer: z.string().optional().describe('Filter by deployer address'),
      min_holders: z.number().int().nonnegative().optional().describe('Minimum number of holders'),
      min_percent_minted: z.number().min(0).max(100).optional().describe('Minimum percent minted'),
      sort_by: z
        .enum(['deploy_timestamp', 'holders', 'percent_minted'])
        .optional()
        .default('deploy_timestamp')
        .describe('Sort field'),
      sort_order: z.enum(['ASC', 'DESC']).optional().default('DESC').describe('Sort order'),
      page: z.number().int().positive().optional().default(1).describe('Page number'),
      page_size: z.number().int().positive().max(100).optional().default(20).describe('Items per page'),
    });
  • Registration of SearchTokensTool class and factory function to instantiate search_tokens tool with API client.
    export const tokenTools = {
      get_token_info: GetTokenInfoTool,
      search_tokens: SearchTokensTool,
    };
    
    /**
     * Factory function to create all token tool instances
     */
    export function createTokenTools(apiClient?: StampchainClient) {
      return {
        get_token_info: new GetTokenInfoTool(apiClient),
        search_tokens: new SearchTokensTool(apiClient),
      };
    }
  • Central factory function that creates all tools including search_tokens via createTokenTools and aggregates them.
    export function createAllTools(apiClient?: StampchainClient): Record<string, ITool> {
      const client = apiClient || new StampchainClient();
    
      const stamps = createStampTools(client);
      const collections = createCollectionTools(client);
      const tokens = createTokenTools(client);
      const analysis = createStampAnalysisTools(client);
    
      return {
        ...stamps,
        ...collections,
        ...tokens,
        ...analysis,
      };
    }
  • Underlying API client method called by the tool handler to perform the actual token search via Stampchain API.
     * Search SRC-20 tokens with query parameters
     */
    async searchTokens(params: TokenQueryParams = {}): Promise<TokenResponse[]> {
      const response = await this.client.get<TokenListResponse>('/src20', { params });
      return response.data.data;
    }

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/stampchain-io/stampchain-mcp'

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