Skip to main content
Glama

deploy-chain

Deploy a new blockchain to the Hyperlane network by specifying chain details like name, ID, RPC URL, and token information for cross-chain connectivity.

Instructions

Deploys a new chain to the Hyperlane network.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNameYesName of the chain to deploy
chainIdYesChain ID of the chain to deploy
rpcUrlYesRPC URL for the chain
tokenSymbolYesNative token symbol
tokenNameYesNative token name
isTestnetNoWhether this is a testnet chain

Implementation Reference

  • Main handler for 'deploy-chain' tool: loads existing config or creates new chain config, deploys core contracts using runCoreDeploy, generates metadata and agent configs.
    async ({ chainName, chainId, rpcUrl, tokenSymbol, tokenName, isTestnet }) => { const existingConfig = await loadChainDeployConfig(chainName); if (existingConfig) { server.server.sendLoggingMessage({ level: 'info', data: `Chain deployment config already exists for ${chainName}. Using existing config.`, }); return { content: [ { type: 'text', text: `Chain config already exists. Skipping config creation.\n${JSON.stringify( existingConfig, null, 2 )}`, }, ], }; } server.server.sendLoggingMessage({ level: 'info', data: `Deploying chain ${chainName} with ID ${chainId}...`, }); // Step 1: Create Chain Config + Save const chainConfig = { chainName, chainId, rpcUrl, tokenSymbol, tokenName, isTestnet, }; await createChainConfig({ config: chainConfig, registry, }); server.server.sendLoggingMessage({ level: 'info', data: `Chain config created successfully: ${JSON.stringify( chainConfig, null, 2 )}`, }); // Step 2: Deploy Core Contracts const deployConfig = { config: chainConfig, registry }; // server.server.sendLoggingMessage({ // level: 'info', // data: `this is the deploy config: ${JSON.stringify(deployConfig, null, 2)}`, // }); const deployedAddress = await runCoreDeploy(deployConfig); server.server.sendLoggingMessage({ level: 'info', data: `Core contracts deployed successfully for ${chainName}. Deployed address: ${JSON.stringify( deployedAddress, null, 2 )}`, }); // Step 3: Create Agent Configs const metadata = { [chainName]: { name: chainName, displayName: chainName, chainId, domainId: chainId, protocol: ProtocolType.Ethereum, rpcUrls: [{ http: rpcUrl }], isTestnet, }, } as ChainMap<ChainMetadata>; server.server.sendLoggingMessage({ level: 'info', data: `Create metadata for ${chainName}: ${JSON.stringify( metadata, null, 2 )}`, }); const multiProvider = new MultiProvider(metadata, { signers: { [signer.address]: signer, }, }); const outPath = path.join(mcpDir, 'agents'); await createAgentConfigs(registry, multiProvider, outPath, chainName); server.server.sendLoggingMessage({ level: 'info', data: `✅ Chain deployment and agent config creation complete for ${chainName}`, }); return { content: [ { type: 'text', text: `✅ Successfully deployed ${chainName} and generated agent config.\n\nSaved config: ${JSON.stringify( chainConfig, null, 2 )}`, }, ], }; }
  • Zod schema defining input parameters for the 'deploy-chain' tool.
    chainName: z.string().describe('Name of the chain to deploy'), chainId: z.number().describe('Chain ID of the chain to deploy'), rpcUrl: z.string().url().describe('RPC URL for the chain'), tokenSymbol: z.string().describe('Native token symbol'), tokenName: z.string().describe('Native token name'), isTestnet: z .boolean() .default(false) .describe('Whether this is a testnet chain'), },
  • src/index.ts:572-704 (registration)
    Registration of the 'deploy-chain' tool on the MCP server with name, description, input schema, and handler function.
    'deploy-chain', 'Deploys a new chain to the Hyperlane network.', { chainName: z.string().describe('Name of the chain to deploy'), chainId: z.number().describe('Chain ID of the chain to deploy'), rpcUrl: z.string().url().describe('RPC URL for the chain'), tokenSymbol: z.string().describe('Native token symbol'), tokenName: z.string().describe('Native token name'), isTestnet: z .boolean() .default(false) .describe('Whether this is a testnet chain'), }, async ({ chainName, chainId, rpcUrl, tokenSymbol, tokenName, isTestnet }) => { const existingConfig = await loadChainDeployConfig(chainName); if (existingConfig) { server.server.sendLoggingMessage({ level: 'info', data: `Chain deployment config already exists for ${chainName}. Using existing config.`, }); return { content: [ { type: 'text', text: `Chain config already exists. Skipping config creation.\n${JSON.stringify( existingConfig, null, 2 )}`, }, ], }; } server.server.sendLoggingMessage({ level: 'info', data: `Deploying chain ${chainName} with ID ${chainId}...`, }); // Step 1: Create Chain Config + Save const chainConfig = { chainName, chainId, rpcUrl, tokenSymbol, tokenName, isTestnet, }; await createChainConfig({ config: chainConfig, registry, }); server.server.sendLoggingMessage({ level: 'info', data: `Chain config created successfully: ${JSON.stringify( chainConfig, null, 2 )}`, }); // Step 2: Deploy Core Contracts const deployConfig = { config: chainConfig, registry }; // server.server.sendLoggingMessage({ // level: 'info', // data: `this is the deploy config: ${JSON.stringify(deployConfig, null, 2)}`, // }); const deployedAddress = await runCoreDeploy(deployConfig); server.server.sendLoggingMessage({ level: 'info', data: `Core contracts deployed successfully for ${chainName}. Deployed address: ${JSON.stringify( deployedAddress, null, 2 )}`, }); // Step 3: Create Agent Configs const metadata = { [chainName]: { name: chainName, displayName: chainName, chainId, domainId: chainId, protocol: ProtocolType.Ethereum, rpcUrls: [{ http: rpcUrl }], isTestnet, }, } as ChainMap<ChainMetadata>; server.server.sendLoggingMessage({ level: 'info', data: `Create metadata for ${chainName}: ${JSON.stringify( metadata, null, 2 )}`, }); const multiProvider = new MultiProvider(metadata, { signers: { [signer.address]: signer, }, }); const outPath = path.join(mcpDir, 'agents'); await createAgentConfigs(registry, multiProvider, outPath, chainName); server.server.sendLoggingMessage({ level: 'info', data: `✅ Chain deployment and agent config creation complete for ${chainName}`, }); return { content: [ { type: 'text', text: `✅ Successfully deployed ${chainName} and generated agent config.\n\nSaved config: ${JSON.stringify( chainConfig, null, 2 )}`, }, ], }; } );
  • Core helper function that performs the actual deployment of Hyperlane core contracts to the specified chain, including setup, pre-checks, module creation, deployment, and registry update.
    export async function runCoreDeploy( config: CoreDeployConfig ): Promise<Record<string, string>> { if (!process.env.PRIVATE_KEY) { throw new Error('PRIVATE_KEY environment variable is required'); } const signer = privateKeyToSigner(process.env.PRIVATE_KEY); const chain = config.config.chainName; const metadata: ChainMetadata = { name: chain, displayName: chain, chainId: config.config.chainId, domainId: Number(config.config.chainId), //@ts-ignore protocol: ProtocolType.Ethereum, rpcUrls: [ { http: config.config.rpcUrl, }, ], isTestnet: config.config.isTestnet, }; const multiProvider = new MultiProvider( { [chain]: metadata, }, { signers: { [chain]: signer, }, } ); const userAddress = signer.address; logger.info(`Preparing to deploy core contracts to ${chain}`); const initialBalances = await prepareDeploy({ userAddress, chains: [chain], multiProvider, }); logger.info(`Initial balances: ${initialBalances}`); await runDeployPlanStep(config.registry, chain, multiProvider); logger.info(`Predepoly checks complete`); const coreConfig = await InitializeDeployment(); writeYamlOrJson( path.join( process.env.CACHE_DIR || process.env.HOME!, '.hyperlane-mcp', 'chains', `${chain}-core-config.yaml` ), coreConfig, 'yaml' ); logger.info(`Core config: ${JSON.stringify(coreConfig, null, 2)}`); logger.info(`Creating core module...`); let evmCoreModule: EvmCoreModule; try { evmCoreModule = await EvmCoreModule.create({ chain, config: coreConfig, multiProvider, // contractVerifier, }); // logger.info( // `Core module created: ${JSON.stringify(evmCoreModule, null, 2)}` // ); } catch (e) { logger.error(`Error in creating core module: ${e}`); logger.error( `Error in creating core module: ${JSON.stringify(e, null, 2)}` ); throw new Error(`Error in creating core module: ${e}`); } logger.info(`Core module created: ${JSON.stringify(evmCoreModule, null, 2)}`); logger.info(`Deploying core contracts to ${chain}`); await completeDeploy(multiProvider, initialBalances, userAddress, [chain]); const deployedAddresses = evmCoreModule.serialize(); logger.info( `Deployed addresses: ${JSON.stringify(deployedAddresses, null, 2)}` ); config.registry.updateChain({ chainName: chain, addresses: deployedAddresses, }); return deployedAddresses; // Return the deployed addresses as the function output }
  • Helper function to create and register chain metadata in the registry.
    export async function createChainConfig( options: ChainConfigOptions ): Promise<void> { const provider = new ethers.providers.JsonRpcProvider(options.config.rpcUrl); const metadata: ChainMetadata = { name: options.config.chainName, displayName: options.config.chainName, chainId: options.config.chainId, domainId: Number(options.config.chainId), //@ts-ignore protocol: ProtocolType.Ethereum, rpcUrls: [ { http: options.config.rpcUrl, }, ], isTestnet: options.config.isTestnet, }; await addNativeTokenConfig(metadata, { tokenSymbol: options.config.tokenSymbol, tokenName: options.config.tokenName, }); logger.info(`Chain metadata: ${metadata}`); const parseResult = ChainMetadataSchema.safeParse(metadata); logger.info(`Chain metadata: ${parseResult}`); if (parseResult.success) { const metadataYaml = yamlStringify(metadata, { indent: 2, sortMapEntries: true, }); await options.registry.addChain({ chainName: metadata.name, metadata }); logger.info(`Chain metadata created: ${metadataYaml}`); } else { console.error(parseResult.error); // FIX: Properly format the error message using template literals throw new Error( `Error in creating chain metadata: ${JSON.stringify(metadata)}: ${ parseResult.error }` ); } }

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/Suryansh-23/hyperlane-mcp'

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