Skip to main content
Glama

create_gas_station

Create a new Aptos gas station project for fee sponsorship by specifying a project name to enable transaction cost coverage on the blockchain.

Instructions

Creates a new Aptos gas station (fee sponsorship) project.

Args:
    project_name: Name of the gas station project

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_nameYes

Implementation Reference

  • The main handler function for the 'create_gas_station' MCP tool. It creates a complete Aptos gas station project structure including server and client TypeScript code, package.json, tsconfig.json, .env, and README.md files by calling helper functions to generate the code templates.
    @mcp.tool()
    async def create_gas_station(project_name: str) -> str:
        """
        Creates a new Aptos gas station (fee sponsorship) project.
        
        Args:
            project_name: Name of the gas station project
        """
        project_name = project_name.strip().replace(" ", "-").lower()
        
        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)
            
            # Create server directory
            server_dir = os.path.join(project_dir, "server")
            os.makedirs(server_dir, exist_ok=True)
            
            # Create client directory
            client_dir = os.path.join(project_dir, "client")
            os.makedirs(client_dir, exist_ok=True)
            
            # Generate server files
            server_ts_path = os.path.join(server_dir, "server.ts")
            with open(server_ts_path, "w") as f:
                f.write(generate_gas_station_server())
            
            # Generate client files
            client_ts_path = os.path.join(client_dir, "client.ts")
            with open(client_ts_path, "w") as f:
                f.write(generate_gas_station_client())
            
            # Create package.json for server
            server_package_json = {
                "name": f"{project_name}-server",
                "version": "1.0.0",
                "description": "Aptos Gas Station Server for fee sponsorship",
                "main": "server.ts",
                "scripts": {
                    "build": "tsc",
                    "start": "ts-node server.ts"
                },
                "dependencies": {
                    "@aptos-labs/ts-sdk": "^1.2.0",
                    "express": "^4.18.2",
                    "dotenv": "^16.3.1"
                },
                "devDependencies": {
                    "@types/express": "^4.17.17",
                    "ts-node": "^10.9.1",
                    "typescript": "^5.1.6"
                }
            }
            
            with open(os.path.join(server_dir, "package.json"), "w") as f:
                json.dump(server_package_json, f, indent=2)
            
            # Create package.json for client
            client_package_json = {
                "name": f"{project_name}-client",
                "version": "1.0.0",
                "description": "Aptos Gas Station Client Example",
                "main": "client.ts",
                "scripts": {
                    "build": "tsc",
                    "start": "ts-node client.ts"
                },
                "dependencies": {
                    "@aptos-labs/ts-sdk": "^1.2.0",
                    "axios": "^1.4.0"
                },
                "devDependencies": {
                    "ts-node": "^10.9.1",
                    "typescript": "^5.1.6"
                }
            }
            
            with open(os.path.join(client_dir, "package.json"), "w") as f:
                json.dump(client_package_json, f, indent=2)
            
            # Create tsconfig.json files
            tsconfig = {
                "compilerOptions": {
                    "target": "es2020",
                    "module": "commonjs",
                    "esModuleInterop": True,
                    "forceConsistentCasingInFileNames": True,
                    "strict": True,
                    "skipLibCheck": True,
                    "outDir": "dist"
                }
            }
            
            with open(os.path.join(server_dir, "tsconfig.json"), "w") as f:
                json.dump(tsconfig, f, indent=2)
            
            with open(os.path.join(client_dir, "tsconfig.json"), "w") as f:
                json.dump(tsconfig, f, indent=2)
            
            # Create .env file for server
            env_content = """# Aptos Network: DEVNET, TESTNET, MAINNET
    APTOS_NETWORK=DEVNET
    
    # Port for the server
    PORT=3000
    
    # Optional: Fund gas account on start (true/false)
    AUTO_FUND_ACCOUNT=true
    """
            
            with open(os.path.join(server_dir, ".env"), "w") as f:
                f.write(env_content)
            
            # Create README.md
            readme_content = f"""# {project_name} - Aptos Gas Station
    
    A gas station implementation for Aptos that allows fee sponsorship (fee payer) for transactions.
    
    ## Structure
    
    - `server/`: Gas station server that acts as a fee payer
    - `client/`: Example client that uses the gas station
    
    ## Server Setup
    
    1. Navigate to the server directory:
       ```
       cd server
       ```
    
    2. Install dependencies:
       ```
       npm install
       ```
    
    3. Configure your environment:
       Edit the `.env` file to customize your setup.
    
    4. Start the server:
       ```
       npm start
       ```
    
    ## Client Example
    
    The client directory contains an example of how to use the gas station to submit transactions without paying gas fees.
    
    1. Navigate to the client directory:
       ```
       cd client
       ```
    
    2. Install dependencies:
       ```
       npm install
       ```
    
    3. Run the example:
       ```
       npm start
       ```
    
    ## How It Works
    
    1. Client builds a transaction and signs it
    2. Client sends the transaction to the gas station
    3. Gas station signs the transaction as a fee payer
    4. Gas station submits the transaction to the blockchain
    5. Original transaction executes with fees paid by the gas station
    
    ## Security Considerations
    
    - Implement proper authentication for production
    - Add rate limiting to prevent abuse
    - Monitor gas usage to control costs
    """
            
            with open(os.path.join(project_dir, "README.md"), "w") as f:
                f.write(readme_content)
            
            return f"""
    Successfully created Aptos Gas Station project at {project_dir}!
    
    The project includes:
    - Server implementation (Express.js)
    - Client example code
    - Configuration files
    
    Next steps:
    1. Navigate to the server directory: `cd {project_name}/server`
    2. Install dependencies: `npm install`
    3. Configure your environment in .env
    4. Start the server: `npm start`
    
    To try the client example:
    1. Navigate to the client directory: `cd {project_name}/client`
    2. Install dependencies: `npm install`
    3. Run the example: `npm start`
    
    See the README.md file for more information.
    """
        
        except Exception as e:
            return f"Error creating gas station project: {str(e)}"
  • The @mcp.tool() decorator registers the create_gas_station function as an MCP tool.
    @mcp.tool()
  • Helper function that generates the complete TypeScript code for the gas station Express server, including endpoints for signing and submitting sponsored transactions.
    def generate_gas_station_server() -> str:
        """Generate the server code for a gas station"""
        return """import express, { Request, Response } from 'express';
    import {
        Account, AccountAuthenticator,
        Aptos,
        AptosConfig,
        Deserializer,
        Network,
        NetworkToNetworkName,
        SimpleTransaction,
    } from '@aptos-labs/ts-sdk';
    import dotenv from 'dotenv';
    
    dotenv.config();
    
    const app = express();
    app.use(express.json());
    
    const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
    
    const APTOS_NETWORK = NetworkToNetworkName[process.env.APTOS_NETWORK || ''] || Network.DEVNET;
    
    const config = new AptosConfig({network: APTOS_NETWORK});
    const aptos = new Aptos(config);
    
    const feePayerAccount = Account.generate();
    console.log(`Gas Station Account Address: ${feePayerAccount.accountAddress.toString()}`);
    
    // Fund the feePayerAccount account
    const fundFeePayerAccount = async () => {
        console.log('=== Funding Gas Station Account ===');
        try {
            await aptos.fundAccount({
                accountAddress: feePayerAccount.accountAddress,
                amount: 100_000_000,
            });
            console.log('Gas Station Account funded successfully.');
        } catch (error) {
            console.error('Error funding Gas Station Account:', error);
            console.log('Note: Automatic funding only works on DEVNET. On other networks, manually fund this address.');
        }
    };
    
    app.post('/signAndSubmit', async (req: Request, res: Response) => {
        try {
            const {transactionBytes, senderAuthenticator} = req.body;
    
            if (!transactionBytes) {
                return res.status(400).json({error: 'transactionBytes is required'});
            }
            if (!senderAuthenticator) {
                return res.status(400).json({error: 'senderAuthenticator is required'});
            }
    
            console.log('=== Received Transaction Request ===');
    
            // Deserialize the raw transaction
            const deserializer = new Deserializer(Uint8Array.from(transactionBytes));
            const transaction = SimpleTransaction.deserialize(deserializer);
    
            console.log('=== Signing Transaction as Fee Payer ===');
    
            // Gas station signs the transaction as fee payer
            const feePayerAuthenticator = aptos.transaction.signAsFeePayer({
                signer: feePayerAccount,
                transaction,
            });
    
            const deserializedSenderAuth = AccountAuthenticator.deserialize(new Deserializer(Uint8Array.from(senderAuthenticator)));
    
            console.log('=== Submitting Sponsored Transaction ===');
            const signedTxnInput = {
                transaction,
                senderAuthenticator: deserializedSenderAuth,
                feePayerAuthenticator,
            };
            let response = await aptos.transaction.submit.simple(signedTxnInput);
            
            console.log(`Transaction submitted. Hash: ${response.hash}`);
            await aptos.waitForTransaction({transactionHash: response.hash});
            console.log('Transaction executed successfully!');
    
            return res.status(200).json({
                transactionHash: response.hash,
                message: 'Transaction sponsored and executed successfully',
                feePayerAddress: feePayerAccount.accountAddress.toString()
            });
        } catch (error) {
            console.error('Error processing transaction:', error);
            return res.status(500).json({error: String(error)});
        }
    });
    
    // Health check endpoint
    app.get('/health', (req: Request, res: Response) => {
        return res.status(200).json({
            status: 'healthy',
            network: APTOS_NETWORK,
            feePayerAddress: feePayerAccount.accountAddress.toString()
        });
    });
    
    app.listen(PORT, async () => {
        console.log(`Gas Station Server running on http://localhost:${PORT}`);
        if (process.env.AUTO_FUND_ACCOUNT === 'true') {
            await fundFeePayerAccount();
        }
    });
    """
  • Helper function that generates the TypeScript client example code demonstrating how to build, sign, and submit a transaction via the gas station for fee sponsorship.
    def generate_gas_station_client() -> str:
        """Generate the client code for a gas station"""
        return """import axios from 'axios';
    import { Account, Aptos, AptosConfig, Network, } from '@aptos-labs/ts-sdk';
    
    const GAS_STATION_URL = "http://localhost:3000";
    
    const main = async () => {
        const config = new AptosConfig({ network: Network.DEVNET });
        const aptos = new Aptos(config);
    
        console.log("=== Aptos Gas Station Client Demo ===");
        
        // Create sender and recipient accounts
        const alice = Account.generate();
        const bob = Account.generate();
    
        console.log("Alice's address:", alice.accountAddress.toString());
        console.log("Bob's address:", bob.accountAddress.toString());
    
        // Fund Alice's account (the transaction sender, but not fee payer)
        console.log("\\n=== Funding Alice's account ===");
        await aptos.fundAccount({ accountAddress: alice.accountAddress, amount: 100_000_000 });
        console.log("Alice's account funded");
    
        // Build a transaction (Alice sending APT to Bob)
        console.log("\\n=== Building transaction ===");
        const transaction = await aptos.transaction.build.simple({
            sender: alice.accountAddress,
            withFeePayer: true,  // Important: Mark that this transaction will have a fee payer
            data: {
                function: "0x1::aptos_account::transfer",
                functionArguments: [bob.accountAddress, 100],  // Sending 100 octas to Bob
            },
        });
        
        console.log("Transaction built successfully");
    
        // Alice signs the transaction (but doesn't pay for gas)
        console.log("\\n=== Alice signing transaction ===");
        const senderAuthenticator = aptos.transaction.sign({ signer: alice, transaction });
        console.log("Transaction signed by Alice");
    
        // Send the transaction to the gas station for fee sponsorship
        console.log("\\n=== Sending to Gas Station for sponsorship ===");
        try {
            const response = await axios.post(
                `${GAS_STATION_URL}/signAndSubmit`,
                {
                    transactionBytes: Array.from(transaction.bcsToBytes()),
                    senderAuthenticator: Array.from(senderAuthenticator.bcsToBytes()),
                },
                {
                    headers: {
                        "Content-Type": "application/json",
                    },
                }
            );
    
            const { transactionHash, feePayerAddress } = response.data;
    
            console.log("Transaction sponsored by:", feePayerAddress);
            console.log("Transaction submitted. Hash:", transactionHash);
            
            // Wait for transaction to be executed
            console.log("\\n=== Waiting for transaction execution ===");
            const executedTx = await aptos.waitForTransaction({ transactionHash });
            console.log("Transaction executed successfully!");
            
            // Verify Bob received the funds
            console.log("\\n=== Checking Bob's balance ===");
            const bobBalance = await aptos.getAccountAPTAmount({ accountAddress: bob.accountAddress });
            console.log("Bob's balance:", bobBalance, "octas");
            
        } catch (error) {
            console.error("Error:", error.response?.data || error.message);
        }
    };
    
    main();
    """
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. It states the tool creates a new project, implying a mutation operation, but lacks details on permissions, side effects, error handling, or response format. For a creation tool with zero annotation coverage, this leaves significant gaps in understanding its behavior and implications.

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 concise and well-structured, with a clear purpose statement followed by a brief parameter explanation in two sentences. It avoids unnecessary details and is front-loaded with the main action. Minor improvements could include integrating the parameter info more seamlessly, but overall it is efficient and readable.

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

Completeness3/5

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

Given the tool's complexity (a creation operation with one parameter), lack of annotations, and no output schema, the description is minimally adequate. It covers the basic purpose and parameter semantics but misses behavioral details, usage guidelines, and output information. This leaves users with incomplete context for effective tool invocation.

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

Parameters4/5

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

The description adds meaningful context for the single parameter 'project_name' by explaining it as the 'Name of the gas station project'. With schema description coverage at 0% (the schema only provides a title 'Project Name'), this compensates well by clarifying the parameter's role. However, it does not detail constraints like length or format, keeping it from a perfect score.

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 tool's purpose: 'Creates a new Aptos gas station (fee sponsorship) project.' It specifies the verb ('creates') and resource ('gas station project'), with additional clarifying context ('fee sponsorship'). However, it does not explicitly differentiate from sibling tools like 'create_aptos_project' or 'create_aptos_indexer', which also involve creation operations in the Aptos ecosystem, leaving some ambiguity about when to use this specific tool.

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. It does not mention prerequisites, exclusions, or compare it to sibling tools such as 'create_aptos_project' or 'create_aptos_indexer'. Without this context, users must infer usage based on the tool name and description 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