Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

<div align="left">

<a href="https://akash.network/" target="_blank">
Expand All @@ -10,8 +9,9 @@
**Akash MCP Server** is a TypeScript implementation of a Model Context Protocol (MCP) server for interacting with the Akash Network.

[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/akashnet_)](https://x.com/akashnet_ "Follow Akash Network on X")
[![Discord](https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat)](https://discord.gg/akash "Join Akash Discord")
[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/akashnet_)](https://x.com/akashnet_ 'Follow Akash Network on X')
[![Discord](https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat)](https://discord.gg/akash 'Join Akash Discord')

</div>

## Note
Expand Down Expand Up @@ -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

Expand Down
9 changes: 8 additions & 1 deletion src/AkashMCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/tools/create-deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const parameters = z.object({
export const CreateDeploymentTool: ToolDefinition<typeof parameters> = {
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,
Expand Down
1 change: 1 addition & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
2 changes: 1 addition & 1 deletion src/tools/send-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const SendManifestTool: ToolDefinition<typeof parameters> = {
},
};

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');
}
Expand Down
77 changes: 77 additions & 0 deletions src/tools/update-deployment.ts
Original file line number Diff line number Diff line change
@@ -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<typeof parameters> = {
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<typeof parameters>, 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',
});
}
},
};
31 changes: 31 additions & 0 deletions src/utils/query-lease.ts
Original file line number Diff line number Diff line change
@@ -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;
}
24 changes: 24 additions & 0 deletions src/utils/query-leases.ts
Original file line number Diff line number Diff line change
@@ -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;
}