diff --git a/README.md b/README.md index 3e04997..4f7d819 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This server provides a bridge between AI agents and the Akash Network, allowing - **Certificate Management**: Manages Akash certificates - **Tools for Akash Interaction**: - Account address retrieval - - Deployment creation and management + - Deployment creation, querying, updating, and termination - SDL (Stack Definition Language) operations - Bid management - Lease creation @@ -111,6 +111,8 @@ The server provides the following tools for AI agents: - **GetBalancesTool**: Get the AKT (uakt) and other balances for a given Akash account address - **GetBidsTool**: Get bids for deployments - **CreateDeploymentTool**: Create a new deployment on Akash Network +- **GetDeploymentTool**: Get deployment details including status, groups, and escrow account +- **CloseDeploymentTool**: Close/terminate a deployment on Akash Network - **AddFundsTool**: Deposit additional AKT (uakt) into a deployment escrow account - **GetSDLsTool**: Get a list of available SDLs (from awesome-akash repository) - **GetSDLTool**: Get a specific SDL by name @@ -189,6 +191,79 @@ Response: "...transaction raw log or error message..." ``` +### GetDeploymentTool + +**Description:** + +Get deployment details from Akash Network including status, groups, and escrow account. + +**Input Schema:** + +```json +{ + "dseq": 123456 // Deployment sequence number (integer, required) +} +``` + +**Example Usage:** + +Request: + +```json +{ + "dseq": 123456 +} +``` + +Response: + +```json +{ + "deployment": { + "deploymentId": { "owner": "akash1...", "dseq": "123456" }, + "state": "active", + "version": "...", + "createdAt": "..." + }, + "groups": [...], + "escrowAccount": { + "balance": { "denom": "uakt", "amount": "..." }, + "state": "open", + // ...other escrow details + } +} +``` + +### CloseDeploymentTool + +**Description:** + +Close a deployment on Akash Network. This terminates the deployment, closes associated leases, and refunds remaining escrow funds. + +**Input Schema:** + +```json +{ + "dseq": 123456 // Deployment sequence number (integer, required) +} +``` + +**Example Usage:** + +Request: + +```json +{ + "dseq": 123456 +} +``` + +Response: + +```json +"...transaction raw log confirming deployment closure..." +``` + ## Development ### Linting and Formatting diff --git a/src/AkashMCP.ts b/src/AkashMCP.ts index 60e8e91..057fb7c 100644 --- a/src/AkashMCP.ts +++ b/src/AkashMCP.ts @@ -15,6 +15,8 @@ import { UpdateDeploymentTool, AddFundsTool, GetBalancesTool, + CloseDeploymentTool, + GetDeploymentTool, } from './tools/index.js'; import type { ToolContext } from './types/index.js'; import type { CertificatePem } from '@akashnetwork/akashjs/build/certificates/certificate-manager/CertificateManager.js'; @@ -138,6 +140,20 @@ class AkashMCP extends McpServer { GetBalancesTool.parameters.shape, async (args, extra) => GetBalancesTool.handler(args, this.getToolContext()) ); + + this.tool( + CloseDeploymentTool.name, + CloseDeploymentTool.description, + CloseDeploymentTool.parameters.shape, + async (args, extra) => CloseDeploymentTool.handler(args, this.getToolContext()) + ); + + this.tool( + GetDeploymentTool.name, + GetDeploymentTool.description, + GetDeploymentTool.parameters.shape, + async (args, extra) => GetDeploymentTool.handler(args, this.getToolContext()) + ); } public isInitialized(): boolean { return this.wallet !== null && this.client !== null && this.certificate !== null; diff --git a/src/tools/close-deployment.ts b/src/tools/close-deployment.ts new file mode 100644 index 0000000..250ef03 --- /dev/null +++ b/src/tools/close-deployment.ts @@ -0,0 +1,48 @@ +import { z } from 'zod'; +import type { ToolDefinition, ToolContext } from '../types/index.js'; +import { MsgCloseDeployment } from '@akashnetwork/akash-api/akash/deployment/v1beta3'; +import { createOutput } from '../utils/create-output.js'; +import { getTypeUrl } from '@akashnetwork/akashjs/build/stargate/index.js'; + +const parameters = z.object({ + dseq: z.number().min(1), +}); + +export const CloseDeploymentTool: ToolDefinition = { + name: 'close-deployment', + description: + 'Close a deployment on Akash Network. ' + + 'The dseq is the deployment sequence number.', + parameters, + handler: async (params: z.infer, context: ToolContext) => { + const { dseq } = params; + const { wallet, client } = context; + + try { + const accounts = await wallet.getAccounts(); + + if (!accounts || accounts.length === 0) { + return createOutput({ error: 'No accounts found in wallet' }); + } + + const msg = { + typeUrl: getTypeUrl(MsgCloseDeployment), + value: MsgCloseDeployment.fromPartial({ + id: { + owner: accounts[0].address, + dseq: dseq, + }, + }), + }; + + const tx = await client.signAndBroadcast(accounts[0].address, [msg], 'auto'); + + return createOutput(tx.rawLog); + } catch (error: any) { + console.error('Error closing deployment:', error); + return createOutput({ + error: error.message || 'Unknown error closing deployment', + }); + } + }, +}; \ No newline at end of file diff --git a/src/tools/get-deployment.ts b/src/tools/get-deployment.ts new file mode 100644 index 0000000..e7accf6 --- /dev/null +++ b/src/tools/get-deployment.ts @@ -0,0 +1,51 @@ +import { z } from 'zod'; +import type { ToolDefinition, ToolContext } from '../types/index.js'; +import { createOutput } from '../utils/create-output.js'; +import { getRpc } from '@akashnetwork/akashjs/build/rpc/index.js'; +import { SERVER_CONFIG } from '../config.js'; +import { QueryClientImpl, QueryDeploymentRequest } from '@akashnetwork/akash-api/akash/deployment/v1beta3'; + +const parameters = z.object({ + dseq: z.number().min(1), +}); + +export const GetDeploymentTool: ToolDefinition = { + name: 'get-deployment', + description: + 'Get deployment details from Akash Network including status, groups, and escrow account. ' + + 'The dseq is the deployment sequence number.', + parameters, + handler: async (params: z.infer, context: ToolContext) => { + const { dseq } = params; + const { wallet } = context; + + try { + const accounts = await wallet.getAccounts(); + if (!accounts || accounts.length === 0) { + return createOutput({ error: 'No accounts found in wallet' }); + } + + const rpc = await getRpc(SERVER_CONFIG.rpcEndpoint); + const deploymentClient = new QueryClientImpl(rpc); + const queryReq = QueryDeploymentRequest.fromPartial({ + id: { owner: accounts[0].address, dseq }, + }); + const deploymentRes = await deploymentClient.Deployment(queryReq); + + if (!deploymentRes.deployment) { + return createOutput({ error: `Deployment ${dseq} not found for owner ${accounts[0].address}` }); + } + + return createOutput({ + deployment: deploymentRes.deployment, + groups: deploymentRes.groups, + escrowAccount: deploymentRes.escrowAccount, + }); + } catch (error: any) { + console.error('Error getting deployment:', error); + return createOutput({ + error: error.message || 'Unknown error getting deployment', + }); + } + }, +}; \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts index 7eead3f..82406ce 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -9,3 +9,5 @@ export { GetAccountAddrTool } from './get-account-addr.js'; export { UpdateDeploymentTool } from './update-deployment.js'; export { AddFundsTool } from './add-funds.js'; export { GetBalancesTool } from './get-balances.js'; +export { CloseDeploymentTool } from './close-deployment.js'; +export { GetDeploymentTool } from './get-deployment.js';