From 1ff34408cbb1aa9505eefde6e7cb41909ba4fd9b Mon Sep 17 00:00:00 2001
From: zJ_ <19760191+zJuuu@users.noreply.github.com>
Date: Wed, 30 Apr 2025 14:26:00 +0200
Subject: [PATCH] feat: add UpdateDeploymentTool and related query utilities
for managing deployments
---
README.md | 9 ++--
src/AkashMCP.ts | 9 +++-
src/index.ts | 1 -
src/tools/create-deployment.ts | 2 +-
src/tools/index.ts | 1 +
src/tools/send-manifest.ts | 2 +-
src/tools/update-deployment.ts | 77 ++++++++++++++++++++++++++++++++++
src/utils/query-lease.ts | 31 ++++++++++++++
src/utils/query-leases.ts | 24 +++++++++++
9 files changed, 148 insertions(+), 8 deletions(-)
create mode 100644 src/tools/update-deployment.ts
create mode 100644 src/utils/query-lease.ts
create mode 100644 src/utils/query-leases.ts
diff --git a/README.md b/README.md
index 76d1e9e..96447ce 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-
## Note
@@ -109,12 +109,13 @@ The server provides the following tools for AI agents:
- **GetAccountAddrTool**: Retrieve your Akash account address
- **GetBidsTool**: Get bids for deployments
-- **CreateDeploymentTool**: Create a new deployment on the Akash Network
+- **CreateDeploymentTool**: Create a new deployment on Akash Network
- **GetSDLsTool**: Get a list of available SDLs (from awesome-akash repository)
- **GetSDLTool**: Get a specific SDL by name
- **SendManifestTool**: Send a manifest to a provider
- **CreateLeaseTool**: Create a lease with a provider
- **GetServicesTool**: Get information about active services
+- **UpdateDeploymentTool**: Update a deployment on Akash Network
## Development
diff --git a/src/AkashMCP.ts b/src/AkashMCP.ts
index 230cf7b..df052ab 100644
--- a/src/AkashMCP.ts
+++ b/src/AkashMCP.ts
@@ -12,6 +12,7 @@ import {
CreateLeaseTool,
GetServicesTool,
CreateDeploymentTool,
+ UpdateDeploymentTool,
} from './tools/index.js';
import type { ToolContext } from './types/index.js';
import type { CertificatePem } from '@akashnetwork/akashjs/build/certificates/certificate-manager/CertificateManager.js';
@@ -114,8 +115,14 @@ class AkashMCP extends McpServer {
GetServicesTool.parameters.shape,
async (args, extra) => GetServicesTool.handler(args, this.getToolContext())
);
- }
+ this.tool(
+ UpdateDeploymentTool.name,
+ UpdateDeploymentTool.description,
+ UpdateDeploymentTool.parameters.shape,
+ async (args, extra) => UpdateDeploymentTool.handler(args, this.getToolContext())
+ );
+ }
public isInitialized(): boolean {
return this.wallet !== null && this.client !== null && this.certificate !== null;
}
diff --git a/src/index.ts b/src/index.ts
index 47ae656..2497fdc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,5 @@
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import AkashMCP from './AkashMCP.js';
-import { GetAccountAddrTool } from './tools/get-account-addr.js';
async function main() {
const server = new AkashMCP();
diff --git a/src/tools/create-deployment.ts b/src/tools/create-deployment.ts
index af82f12..1aecadb 100644
--- a/src/tools/create-deployment.ts
+++ b/src/tools/create-deployment.ts
@@ -14,7 +14,7 @@ const parameters = z.object({
export const CreateDeploymentTool: ToolDefinition = {
name: 'create-deployment',
description:
- 'Create a new deployment on Akash Network using the provided SDL (Service Definition Language) string, deposit amount and currency.' +
+ 'Create a new deployment on Akash Network using the provided SDL (Service Definition Language) string, deposit amount and currency.' +
'The deposit amount is the amount of tokens to deposit into the deployment.' +
'Minimum deposit amount is 500000 uakt.',
parameters,
diff --git a/src/tools/index.ts b/src/tools/index.ts
index ba2dd41..3fe016e 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -6,3 +6,4 @@ export { GetSDLsTool } from './get-sdls.js';
export { GetBidsTool } from './get-bids.js';
export { CreateLeaseTool } from './create-lease.js';
export { GetAccountAddrTool } from './get-account-addr.js';
+export { UpdateDeploymentTool } from './update-deployment.js';
diff --git a/src/tools/send-manifest.ts b/src/tools/send-manifest.ts
index a8ff52c..22b2e48 100644
--- a/src/tools/send-manifest.ts
+++ b/src/tools/send-manifest.ts
@@ -50,7 +50,7 @@ export const SendManifestTool: ToolDefinition = {
},
};
-async function sendManifest(sdl: SDL, lease: CustomLease, certificate: CertificatePem) {
+export async function sendManifest(sdl: SDL, lease: CustomLease, certificate: CertificatePem) {
if (!lease.id) {
throw new Error('Lease ID is undefined');
}
diff --git a/src/tools/update-deployment.ts b/src/tools/update-deployment.ts
new file mode 100644
index 0000000..f048b6f
--- /dev/null
+++ b/src/tools/update-deployment.ts
@@ -0,0 +1,77 @@
+import { z } from 'zod';
+import type { ToolDefinition, ToolContext } from '../types/index.js';
+import { MsgUpdateDeployment } from '@akashnetwork/akash-api/akash/deployment/v1beta3';
+import { SDL } from '@akashnetwork/akashjs/build/sdl/SDL/SDL.js';
+import { createOutput } from '../utils/create-output.js';
+import { getTypeUrl } from '@akashnetwork/akashjs/build/stargate/index.js';
+import { sendManifest } from './send-manifest.js';
+import { queryLeases } from '../utils/query-leases.js';
+const parameters = z.object({
+ rawSDL: z.string().min(1),
+ provider: z.string().min(1),
+ dseq: z.number().min(1),
+});
+
+export const UpdateDeploymentTool: ToolDefinition = {
+ name: 'update-deployment',
+ description:
+ 'Update a deployment on Akash Network using the provided SDL (Service Definition Language) string. This tool also sends the manifest to the provider.' +
+ 'The dseq is the deployment sequence number.' +
+ 'The provider is the provider of the lease.',
+ parameters,
+ handler: async (params: z.infer, context: ToolContext) => {
+ const { rawSDL, provider } = params;
+ const { wallet, client, certificate } = context;
+
+ try {
+ // Parse SDL directly from the string
+ const sdl = SDL.fromString(rawSDL, 'beta3');
+ const accounts = await wallet.getAccounts();
+
+ if (!accounts || accounts.length === 0) {
+ return createOutput({ error: 'No accounts found in wallet' });
+ }
+
+ const leases = await queryLeases(accounts[0].address, params.dseq, provider);
+
+ if (leases.leases.length === 0) {
+ return createOutput({ error: 'No leases found for deployment' });
+ }
+
+ const lease = leases.leases[0];
+
+ const msg = {
+ typeUrl: getTypeUrl(MsgUpdateDeployment),
+ value: MsgUpdateDeployment.fromPartial({
+ id: {
+ owner: accounts[0].address,
+ dseq: params.dseq,
+ },
+ version: await sdl.manifestVersion(),
+ }),
+ };
+
+ const tx = await client.signAndBroadcast(accounts[0].address, [msg], 'auto');
+
+ const leaseId = {
+ id: {
+ owner: lease.lease?.leaseId?.owner ?? '',
+ dseq: lease.lease?.leaseId?.dseq.toNumber() ?? 0,
+ gseq: lease.lease?.leaseId?.gseq ?? 0,
+ oseq: lease.lease?.leaseId?.oseq ?? 0,
+ provider: lease.lease?.leaseId?.provider ?? '',
+ },
+ };
+
+ // Send manifest to provider
+ await sendManifest(sdl, leaseId, certificate);
+
+ return createOutput(tx.rawLog);
+ } catch (error: any) {
+ console.error('Error updating deployment:', error);
+ return createOutput({
+ error: error.message || 'Unknown error updating deployment',
+ });
+ }
+ },
+};
diff --git a/src/utils/query-lease.ts b/src/utils/query-lease.ts
new file mode 100644
index 0000000..94b0a4f
--- /dev/null
+++ b/src/utils/query-lease.ts
@@ -0,0 +1,31 @@
+import {
+ QueryLeaseRequest,
+ QueryClientImpl as QueryMarketClient,
+} from '@akashnetwork/akash-api/akash/market/v1beta4';
+import { getRpc } from '@akashnetwork/akashjs/build/rpc/index.js';
+import { SERVER_CONFIG } from '../config.js';
+
+export async function queryLease(
+ owner: string,
+ dseq: number,
+ gseq: number,
+ oseq: number,
+ provider: string
+) {
+ const rpc = await getRpc(SERVER_CONFIG.rpcEndpoint);
+ const marketClient = new QueryMarketClient(rpc);
+
+ const request = QueryLeaseRequest.fromPartial({
+ id: {
+ owner,
+ dseq,
+ gseq,
+ oseq,
+ provider,
+ },
+ });
+
+ const lease = await marketClient.Lease(request);
+
+ return lease;
+}
diff --git a/src/utils/query-leases.ts b/src/utils/query-leases.ts
new file mode 100644
index 0000000..bcbac3d
--- /dev/null
+++ b/src/utils/query-leases.ts
@@ -0,0 +1,24 @@
+import {
+ QueryLeaseRequest,
+ QueryLeasesRequest,
+ QueryClientImpl as QueryMarketClient,
+} from '@akashnetwork/akash-api/akash/market/v1beta4';
+import { getRpc } from '@akashnetwork/akashjs/build/rpc/index.js';
+import { SERVER_CONFIG } from '../config.js';
+
+export async function queryLeases(owner: string, dseq: number, provider: string) {
+ const rpc = await getRpc(SERVER_CONFIG.rpcEndpoint);
+ const marketClient = new QueryMarketClient(rpc);
+
+ const request = QueryLeasesRequest.fromPartial({
+ filters: {
+ owner,
+ dseq,
+ provider,
+ },
+ });
+
+ const leases = await marketClient.Leases(request);
+
+ return leases;
+}