http-server.tsā¢7.12 kB
#!/usr/bin/env node
/**
* HTTP wrapper for Aptos MCP Server
* This enables the MCP server to work with Smithery's HTTP transport
*/
import express from 'express';
import cors from 'cors';
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// Import configuration and validation
import { validateEnvironment } from "./config.js";
// Import all tool handlers
import { CREATE_ACCOUNT, createAccountHandler } from "./tools/account/createAccount.js";
import { GET_ACCOUNT_INFO, getAccountInfoHandler } from "./tools/account/getAccountInfo.js";
import { FUND_ACCOUNT, fundAccountHandler } from "./tools/account/fundAccount.js";
import { GET_APT_BALANCE, getAptBalanceHandler } from "./tools/native/getBalance.js";
import { TRANSFER_APT, transferAptHandler } from "./tools/native/transferApt.js";
import { GET_COIN_BALANCE, getCoinBalanceHandler } from "./tools/coin/getCoinBalance.js";
import { TRANSFER_COIN, transferCoinHandler } from "./tools/coin/transferCoin.js";
import { GET_TRANSACTION_STATUS, getTransactionStatusHandler } from "./tools/transaction/getTransactionStatus.js";
import { GET_ACCOUNT_TRANSACTIONS, getAccountTransactionsHandler } from "./tools/transaction/getAccountTransactions.js";
const app = express();
const port = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
// Parse configuration from query parameters
function parseConfig(query: any) {
const config: any = {};
// Parse dot-notation query parameters
for (const [key, value] of Object.entries(query)) {
if (key.startsWith('aptosMcp')) {
const configKey = key.charAt(0).toLowerCase() + key.slice(1);
config[configKey] = value;
}
}
return config;
}
// Set environment variables from config
function setEnvironmentFromConfig(config: any) {
if (config.aptosMcpPrivateKey) {
process.env.APTOS_MCP_PRIVATE_KEY = config.aptosMcpPrivateKey;
}
if (config.aptosMcpNetwork) {
process.env.APTOS_MCP_NETWORK = config.aptosMcpNetwork;
}
if (config.aptosMcpNodeUrl) {
process.env.APTOS_MCP_NODE_URL = config.aptosMcpNodeUrl;
}
if (config.aptosMcpFaucetUrl) {
process.env.APTOS_MCP_FAUCET_URL = config.aptosMcpFaucetUrl;
}
}
// Create MCP server instance
const mcpServer = new Server(
{
name: "aptos/blockchain-mcp",
version: "0.1.0",
},
{
capabilities: {
tools: {},
},
}
);
// Register all available tools
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
CREATE_ACCOUNT,
GET_ACCOUNT_INFO,
FUND_ACCOUNT,
GET_APT_BALANCE,
TRANSFER_APT,
GET_COIN_BALANCE,
TRANSFER_COIN,
GET_TRANSACTION_STATUS,
GET_ACCOUNT_TRANSACTIONS,
],
}));
// Handle tool calls
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const { name, arguments: args } = request.params;
switch (name) {
case "create_account":
return await createAccountHandler(args);
case "get_account_info":
return await getAccountInfoHandler(args);
case "fund_account":
return await fundAccountHandler(args);
case "get_apt_balance":
return await getAptBalanceHandler(args);
case "transfer_apt":
return await transferAptHandler(args);
case "get_coin_balance":
return await getCoinBalanceHandler(args);
case "transfer_coin":
return await transferCoinHandler(args);
case "get_transaction_status":
return await getTransactionStatusHandler(args);
case "get_account_transactions":
return await getAccountTransactionsHandler(args);
default:
return {
content: [{ type: "text", text: `Unknown tool: ${name}` }],
isError: true,
};
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
// HTTP endpoints for MCP
app.all('/mcp', async (req, res) => {
try {
// Parse configuration from query parameters
const config = parseConfig(req.query);
// Set environment variables from config
setEnvironmentFromConfig(config);
// Handle different HTTP methods
if (req.method === 'GET') {
// Return server info for GET requests
res.json({
name: "aptos/blockchain-mcp",
version: "0.1.0",
description: "MCP server for Aptos blockchain operations",
tools: [
"create_account",
"get_account_info",
"fund_account",
"get_apt_balance",
"transfer_apt",
"get_coin_balance",
"transfer_coin",
"get_transaction_status",
"get_account_transactions"
]
});
} else if (req.method === 'POST') {
// Handle MCP requests
const mcpRequest = req.body;
if (mcpRequest.method === 'tools/list') {
// Return tools list without requiring configuration (lazy loading)
const response = await mcpServer.request(
{ method: 'tools/list', params: {} },
ListToolsRequestSchema
);
res.json(response);
} else if (mcpRequest.method === 'tools/call') {
// For tool calls, validate environment first
try {
validateEnvironment();
} catch (error) {
return res.status(400).json({
jsonrpc: "2.0",
id: mcpRequest.id,
error: {
code: -32602,
message: `Configuration required: ${error instanceof Error ? error.message : String(error)}`
}
});
}
const response = await mcpServer.request(mcpRequest, CallToolRequestSchema);
res.json(response);
} else {
res.status(400).json({
error: `Unsupported method: ${mcpRequest.method}`
});
}
} else if (req.method === 'DELETE') {
// Handle cleanup if needed
res.json({ message: "Cleanup completed" });
} else {
res.status(405).json({ error: "Method not allowed" });
}
} catch (error) {
console.error('Error handling MCP request:', error);
res.status(500).json({
error: error instanceof Error ? error.message : String(error)
});
}
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
service: 'aptos-mcp'
});
});
// Root endpoint
app.get('/', (req, res) => {
res.json({
name: "Aptos Blockchain MCP Server",
version: "0.1.0",
description: "MCP server for Aptos blockchain operations",
endpoints: {
mcp: "/mcp",
health: "/health"
}
});
});
// Start server
app.listen(port, () => {
console.log(`Aptos MCP HTTP Server running on port ${port}`);
console.log(`Health check: http://localhost:${port}/health`);
console.log(`MCP endpoint: http://localhost:${port}/mcp`);
});
export default app;