Skip to main content
Glama

create_aptos_indexer

Create a new Aptos blockchain indexer project using example processors to process transactions or events.

Instructions

Creates a new Aptos indexer project based on the example processor.

Args:
    project_name: Name of the indexer project
    processor_type: Type of processor (transaction, event)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_nameYes
processor_typeNotransaction

Implementation Reference

  • The @mcp.tool()-decorated handler function that implements the core logic for creating a new Aptos indexer project. It clones a GitHub template, customizes package.json, generates processor TypeScript code based on transaction or event type, creates README and .env files, and sets up the project structure.
    @mcp.tool()
    async def create_aptos_indexer(project_name: str, processor_type: str = "transaction") -> str:
        """
        Creates a new Aptos indexer project based on the example processor.
        
        Args:
            project_name: Name of the indexer project
            processor_type: Type of processor (transaction, event)
        """
        project_name = project_name.strip().replace(" ", "-").lower()
        
        supported_types = ["transaction", "event"]
        if processor_type not in supported_types:
            return f"Unsupported processor type. Choose from: {', '.join(supported_types)}"
        
        try:
            # Create project directory
            project_dir = os.path.join(os.getcwd(), project_name)
            if os.path.exists(project_dir):
                return f"Directory {project_dir} already exists. Please choose a different name."
            
            os.makedirs(project_dir)
            
            # Clone the example repo to get the template
            temp_dir = os.path.join(tempfile.gettempdir(), "aptos-indexer-example")
            if os.path.exists(temp_dir):
                shutil.rmtree(temp_dir)
            
            clone_cmd = [
                "git", "clone", "https://github.com/aptos-labs/aptos-indexer-processor-example.git", 
                temp_dir, "--depth", "1"
            ]
            subprocess.run(clone_cmd, check=True, capture_output=True)
            
            # Copy relevant files from template
            shutil.copytree(os.path.join(temp_dir, "typescript"), project_dir, dirs_exist_ok=True)
            
            # Remove the git directory
            git_dir = os.path.join(project_dir, ".git")
            if os.path.exists(git_dir):
                shutil.rmtree(git_dir)
            
            # Customize the package.json
            package_json_path = os.path.join(project_dir, "package.json")
            with open(package_json_path, "r") as f:
                package_json = json.load(f)
            
            package_json["name"] = project_name
            package_json["description"] = f"Aptos indexer for {project_name}"
            
            with open(package_json_path, "w") as f:
                json.dump(package_json, f, indent=2)
            
            # Customize processor based on type
            processor_dir = os.path.join(project_dir, "src", "processors")
            os.makedirs(processor_dir, exist_ok=True)
            
            processor_code = ""
            if processor_type == "transaction":
                processor_code = generate_transaction_processor(project_name)
            elif processor_type == "event":
                processor_code = generate_event_processor(project_name)
            
            processor_file = os.path.join(processor_dir, f"{project_name}_processor.ts")
            with open(processor_file, "w") as f:
                f.write(processor_code)
            
            # Create README
            readme_content = f"""# {project_name} Aptos Indexer
    
    An Aptos indexer for processing {processor_type}s.
    
    ## Setup
    
    1. Install dependencies:
       ```
       npm install
       ```
    
    2. Configure connection:
       Edit the `.env` file to set your database and Aptos node URLs.
    
    3. Run the indexer:
       ```
       npm run start
       ```
    
    ## Architecture
    
    This indexer uses the Aptos Indexer Framework to process {processor_type}s from the Aptos blockchain.
    
    ## Development
    
    - `src/processors/{project_name}_processor.ts`: Contains the main processor logic
    - `src/models/`: Database models for storing indexed data
    """
    
            with open(os.path.join(project_dir, "README.md"), "w") as f:
                f.write(readme_content)
            
            # Create .env file
            env_content = """# Aptos Node URL
    APTOS_NODE_URL=https://fullnode.devnet.aptoslabs.com/v1
    
    # Database Configuration
    DB_HOST=localhost
    DB_PORT=5432
    DB_NAME=postgres
    DB_USER=postgres
    DB_PASS=postgres
    
    # Indexer Configuration
    STARTING_VERSION=0
    BATCH_SIZE=500
    """
            
            with open(os.path.join(project_dir, ".env"), "w") as f:
                f.write(env_content)
            
            return f"""
    Successfully created Aptos indexer project at {project_dir}!
    
    The project includes:
    - TypeScript boilerplate for an Aptos indexer
    - {processor_type.capitalize()} processor template
    - Database models and configurations
    - Environment setup
    
    Next steps:
    1. Navigate to the project directory: `cd {project_name}`
    2. Install dependencies: `npm install`
    3. Configure your database in .env
    4. Start developing your indexer!
    
    See the README.md file for more information.
    """
        
        except Exception as e:
            return f"Error creating indexer project: {str(e)}"
  • Helper function that generates TypeScript code for a transaction processor class used in the indexer project.
    def generate_transaction_processor(project_name: str) -> str:
        """Generate code for a transaction processor"""
        return f"""import {{
      InputModels,
      Models,
      OutputModels,
      ProcessingResult,
      Transaction,
      TransactionModel,
      TransactionProcessor,
      UserTransactionInput,
      parseTransaction,
    }} from "@aptos-labs/indexer-sdk";
    
    /**
     * {project_name.capitalize()} Transaction Processor
     * 
     * This processor handles transactions and extracts relevant information.
     */
    export class {project_name.capitalize()}TransactionProcessor extends TransactionProcessor {{
      constructor() {{
        super();
      }}
    
      /**
       * Process a batch of transactions
       */
      async process(
        transactionInputs: UserTransactionInput[],
      ): Promise<ProcessingResult> {{
        const processingResult = new ProcessingResult();
        console.log(`Processing ${{transactionInputs.length}} transactions`);
    
        for (const transactionInput of transactionInputs) {{
          const transaction = parseTransaction(transactionInput);
          
          // Process each transaction
          try {{
            await this.processTransaction(transaction, processingResult);
          }} catch (e) {{
            console.error(
              `Error processing transaction ${{transaction.version}}: ${{e}}`,
            );
          }}
        }}
    
        return processingResult;
      }}
    
      /**
       * Process a single transaction
       */
      async processTransaction(
        transaction: Transaction,
        processingResult: ProcessingResult,
      ): Promise<void> {{
        // Check if transaction is successful
        if (!transaction.success) {{
          return;
        }}
    
        // Extract basic transaction data
        const txModel = new TransactionModel();
        txModel.version = transaction.version;
        txModel.hash = transaction.hash;
        txModel.sender = transaction.sender;
        txModel.success = transaction.success;
        txModel.timestamp = new Date(Number(transaction.timestamp) / 1000);
        txModel.blockHeight = transaction.blockHeight;
        
        // Add to processing result
        processingResult.transactionModel = txModel;
    
        // Process specific entry functions
        if (transaction.payload?.type === "entry_function_payload") {{
          const entryFunctionFullStr = transaction.payload.function;
          
          // Example: Process a specific entry function
          if (entryFunctionFullStr === "0x1::coin::transfer") {{
            // Handle coin transfer function
            this.processCoinTransfer(transaction, processingResult);
          }}
          
          // TODO: Add more function handlers
        }}
      }}
    
      /**
       * Process a coin transfer transaction
       */
      private processCoinTransfer(
        transaction: Transaction,
        processingResult: ProcessingResult,
      ): void {{
        if (
          transaction.payload?.type !== "entry_function_payload" ||
          !transaction.payload.arguments
        ) {{
          return;
        }}
    
        try {{
          // Extract function arguments
          const [recipient, amount] = transaction.payload.arguments;
          
          // Create custom transaction model
          const transferModel = new Models.{project_name.capitalize()}TransferModel();
          transferModel.version = transaction.version;
          transferModel.sender = transaction.sender;
          transferModel.recipient = recipient as string;
          transferModel.amount = BigInt(amount as string);
          transferModel.timestamp = new Date(Number(transaction.timestamp) / 1000);
          
          // Add to processing result
          processingResult.models.push(transferModel);
          
          console.log(
            `Processed transfer: ${{transaction.sender}} -> ${{recipient}} (${{amount}})`,
          );
        }} catch (e) {{
          console.error(`Error processing coin transfer: ${{e}}`);
        }}
      }}
    }}
    
    // Register processor
    new {project_name.capitalize()}TransactionProcessor().start();
    """
  • Helper function that generates TypeScript code for an event processor class used in the indexer project.
    def generate_event_processor(project_name: str) -> str:
        """Generate code for an event processor"""
        return f"""import {{
      InputModels,
      Models,
      OutputModels,
      ProcessingResult,
      Event,
      EventProcessor,
      UserTransactionInput,
      parseEvent,
    }} from "@aptos-labs/indexer-sdk";
    
    /**
     * {project_name.capitalize()} Event Processor
     * 
     * This processor handles events and extracts relevant information.
     */
    export class {project_name.capitalize()}EventProcessor extends EventProcessor {{
      constructor() {{
        super();
      }}
    
      /**
       * Process a batch of events
       */
      async process(
        eventInputs: InputModels.Event[],
      ): Promise<ProcessingResult> {{
        const processingResult = new ProcessingResult();
        console.log(`Processing ${{eventInputs.length}} events`);
    
        for (const eventInput of eventInputs) {{
          const event = parseEvent(eventInput);
          
          // Process each event
          try {{
            await this.processEvent(event, processingResult);
          }} catch (e) {{
            console.error(
              `Error processing event ${{event.type}} (version: ${{event.version}}): ${{e}}`,
            );
          }}
        }}
    
        return processingResult;
      }}
    
      /**
       * Process a single event
       */
      async processEvent(
        event: Event,
        processingResult: ProcessingResult,
      ): Promise<void> {{
        // Create base event model
        const eventModel = new Models.{project_name.capitalize()}EventModel();
        eventModel.transactionVersion = event.version;
        eventModel.eventType = event.type;
        eventModel.data = event.data ? JSON.stringify(event.data) : null;
        eventModel.timestamp = new Date(Number(event.timestamp) / 1000);
        
        // Process specific event types
        if (event.type.includes("0x1::coin::DepositEvent")) {{
          await this.processDepositEvent(event, processingResult);
        }} else if (event.type.includes("0x1::coin::WithdrawEvent")) {{
          await this.processWithdrawEvent(event, processingResult);
        }}
        
        // Add base event to processing result 
        processingResult.models.push(eventModel);
      }}
    
      /**
       * Process a deposit event
       */
      private async processDepositEvent(
        event: Event,
        processingResult: ProcessingResult,
      ): Promise<void> {{
        if (!event.data) {{
          return;
        }}
    
        try {{
          // Extract event data
          const {{ amount }} = event.data;
          
          // Create deposit model
          const depositModel = new Models.{project_name.capitalize()}DepositModel();
          depositModel.transactionVersion = event.version;
          depositModel.address = event.accountAddress;
          depositModel.amount = BigInt(amount);
          depositModel.timestamp = new Date(Number(event.timestamp) / 1000);
          
          // Add to processing result
          processingResult.models.push(depositModel);
          
          console.log(
            `Processed deposit: ${{event.accountAddress}} (+${{amount}})`,
          );
        }} catch (e) {{
          console.error(`Error processing deposit event: ${{e}}`);
        }}
      }}
    
      /**
       * Process a withdraw event
       */
      private async processWithdrawEvent(
        event: Event,
        processingResult: ProcessingResult,
      ): Promise<void> {{
        if (!event.data) {{
          return;
        }}
    
        try {{
          // Extract event data
          const {{ amount }} = event.data;
          
          // Create withdraw model
          const withdrawModel = new Models.{project_name.capitalize()}WithdrawModel();
          withdrawModel.transactionVersion = event.version;
          withdrawModel.address = event.accountAddress;
          withdrawModel.amount = BigInt(amount);
          withdrawModel.timestamp = new Date(Number(event.timestamp) / 1000);
          
          // Add to processing result
          processingResult.models.push(withdrawModel);
          
          console.log(
            `Processed withdraw: ${{event.accountAddress}} (-${{amount}})`,
          );
        }} catch (e) {{
          console.error(`Error processing withdraw event: ${{e}}`);
        }}
      }}
    }}
    
    // Register processor
    new {project_name.capitalize()}EventProcessor().start();
    """
  • The @mcp.tool() decorator registers the create_aptos_indexer function as an MCP tool.
    @mcp.tool()
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. While 'Creates' implies a write operation, it doesn't specify permissions required, whether the creation is reversible, what happens on failure, or any rate limits. The mention of 'based on the example processor' adds some context but falls short of describing key behavioral traits like side effects or error handling.

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

Conciseness4/5

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

The description is appropriately sized with two sentences: one stating the purpose and another listing parameters. It's front-loaded with the main action, and each sentence adds value. There's no redundant information, though it could be slightly more structured (e.g., bullet points for parameters).

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

Completeness2/5

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

Given no annotations, 0% schema description coverage, and no output schema, the description is incomplete. It covers basic purpose and parameters but lacks details on behavioral traits, error cases, return values, and differentiation from siblings. For a creation tool with two parameters, this leaves significant gaps for an agent to use it effectively.

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 0%, so the description must compensate. It lists both parameters ('project_name' and 'processor_type') and provides brief meanings, which adds value beyond the bare schema. However, it doesn't explain constraints (e.g., format for 'project_name', valid values for 'processor_type' beyond 'transaction' and 'event'), leaving gaps in parameter understanding.

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

Purpose4/5

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

The description clearly states the action ('Creates a new Aptos indexer project') and specifies the resource ('based on the example processor'), which provides a specific verb+resource combination. However, it doesn't differentiate from sibling tools like 'create_aptos_project' or 'aptos_abi_generate', leaving some ambiguity about when to use this specific tool versus alternatives.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. With sibling tools like 'create_aptos_project' and 'aptos_abi_generate' available, there's no indication of context, prerequisites, or exclusions. The agent must infer usage from the tool name alone, which is insufficient for clear decision-making.

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/Tlazypanda/aptos-mcp-server'

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