index.ts•6.86 kB
/**
* deBridge MCP Server
*
* Model Context Protocol server for deBridge DLN cross-chain swaps.
* Provides tools for:
* - Getting cross-chain swap quotes (preview mode)
* - Listing supported blockchain networks
* - Fetching token information
* - Checking order status
*
* @see https://dln.debridge.finance/v1.0/ - deBridge DLN API Documentation
* @see https://modelcontextprotocol.io/ - Model Context Protocol Specification
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { quoteSwapTool } from "./tools/quoteSwap";
import { getSupportedChainsTool } from "./tools/getSupportedChains";
import { getTokensInfoTool } from "./tools/getTokensInfo";
import { getOrderStatusTool } from "./tools/getOrderStatus";
import { COMMON_SUPPORTED_CHAINS, formatChainsList } from "./resources/supportedChains";
const server = new McpServer(
{
name: "debridge-mcp",
version: "0.1.0",
},
{
capabilities: {
tools: {},
resources: {},
logging: {},
},
}
);
server.tool(
quoteSwapTool.name,
quoteSwapTool.description,
{
srcChainId: z
.string()
.describe("Source chain ID, e.g. '56' for BSC, '42161' for Arbitrum"),
srcToken: z
.string()
.describe("Token address on source chain (ERC20)"),
amount: z
.string()
.describe("Amount in smallest units (wei / token decimals)"),
dstChainId: z
.string()
.describe("Destination chain ID, e.g. '1' for Ethereum, '43114' for Avalanche"),
dstToken: z
.string()
.describe("Token address on destination chain (ERC20)"),
senderAddress: z
.string()
.optional()
.describe("Sender's wallet address (enables full order creation with tx data)"),
dstChainTokenOutRecipient: z
.string()
.optional()
.describe("Recipient address on destination chain (defaults to senderAddress)"),
srcChainOrderAuthorityAddress: z
.string()
.optional()
.describe("Order authority on source chain (defaults to senderAddress)"),
dstChainOrderAuthorityAddress: z
.string()
.optional()
.describe("Order authority on destination chain (defaults to dstChainTokenOutRecipient)"),
referralCode: z
.string()
.optional()
.describe("Referral code for rewards tracking"),
affiliateFeePercent: z
.number()
.optional()
.describe("Affiliate fee in basis points (e.g., 0.1 = 10 bps = 0.1%)"),
affiliateFeeRecipient: z
.string()
.optional()
.describe("Address to receive affiliate fees (required if affiliateFeePercent is set)")
},
async ({
srcChainId,
srcToken,
amount,
dstChainId,
dstToken,
senderAddress,
dstChainTokenOutRecipient,
srcChainOrderAuthorityAddress,
dstChainOrderAuthorityAddress,
referralCode,
affiliateFeePercent,
affiliateFeeRecipient
}) => {
console.error("quoteSwap tool called", {
srcChainId,
srcToken,
amount,
dstChainId,
dstToken,
senderAddress,
hasAffiliateFee: !!affiliateFeePercent
});
const result = await quoteSwapTool.handler({
srcChainId,
srcToken,
amount,
dstChainId,
dstToken,
senderAddress,
dstChainTokenOutRecipient,
srcChainOrderAuthorityAddress,
dstChainOrderAuthorityAddress,
referralCode,
affiliateFeePercent,
affiliateFeeRecipient
});
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
getSupportedChainsTool.name,
getSupportedChainsTool.description,
{},
async () => {
console.error("getSupportedChains tool called");
const result = await getSupportedChainsTool.handler();
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
getTokensInfoTool.name,
getTokensInfoTool.description,
{
chainId: z
.string()
.describe("Chain ID to get token information for (e.g., '1' for Ethereum, '56' for BSC)"),
tokenSymbol: z
.string()
.optional()
.describe("Optional: Filter by token symbol (e.g., 'USDC', 'USDT'). Case insensitive. Returns only matching tokens.")
},
async ({ chainId, tokenSymbol }) => {
console.error("getTokensInfo tool called", { chainId, tokenSymbol });
const result = await getTokensInfoTool.handler({ chainId, tokenSymbol });
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
getOrderStatusTool.name,
getOrderStatusTool.description,
{
orderId: z
.string()
.describe("The order ID to check status for (obtained from creating an order)")
},
async ({ orderId }) => {
console.error("getOrderStatus tool called", { orderId });
const result = await getOrderStatusTool.handler({ orderId });
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
// Register supported chains as a static resource
server.resource(
"supported-chains",
"debridge://supported-chains",
{
name: "Supported Chains",
description: "List of commonly supported blockchain networks with popular token addresses",
mimeType: "text/plain"
},
async () => {
const chainsList = formatChainsList();
const chainsJson = JSON.stringify(COMMON_SUPPORTED_CHAINS, null, 2);
return {
contents: [
{
uri: "debridge://supported-chains",
mimeType: "text/plain",
text: `# deBridge Supported Chains (Cached)
These are the most commonly used chains. If you need a chain not listed here, use the getSupportedChains tool to fetch the latest list from the API.
## Supported Chains:
${chainsList}
## Chain Details with Common Tokens:
${chainsJson}
## Usage Tips:
- For common chains (Ethereum, BSC, Arbitrum, etc.), use the chain IDs and token addresses directly
- Only call getSupportedChains if you need to verify a new/uncommon chain
- Token addresses listed here are the most popular versions (USDC, USDT, etc.)
`
}
]
};
}
);
process.on("SIGINT", async () => {
await server.close();
process.exit(0);
});
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("deBridge MCP Server running on stdio");
}
runServer().catch((error) => {
console.error("Fatal error running server:", error);
process.exit(1);
});