Base MCP Server
Official
by base
- src
import { Coinbase } from "@coinbase/coinbase-sdk";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { version } from "./version.js";
import * as dotenv from "dotenv";
import {
AgentKit,
basenameActionProvider,
cdpWalletActionProvider,
CdpWalletProvider,
morphoActionProvider,
walletActionProvider,
} from "@coinbase/agentkit";
import { getMcpTools } from "@coinbase/agentkit-model-context-protocol";
import { mnemonicToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { createWalletClient, http, publicActions } from "viem";
import { baseMcpTools, toolToHandler } from "./tools/index.js";
async function main() {
dotenv.config();
const apiKeyName = process.env.COINBASE_API_KEY_NAME;
const privateKey = process.env.COINBASE_API_PRIVATE_KEY;
const seedPhrase = process.env.SEED_PHRASE;
if (!apiKeyName || !privateKey || !seedPhrase) {
console.error(
"Please set COINBASE_API_KEY_NAME, COINBASE_API_PRIVATE_KEY, and SEED_PHRASE environment variables",
);
process.exit(1);
}
const viemClient = createWalletClient({
account: mnemonicToAccount(seedPhrase),
chain: base,
transport: http(),
}).extend(publicActions);
const cdpWalletProvider = await CdpWalletProvider.configureWithWallet({
mnemonicPhrase: seedPhrase,
apiKeyName,
apiKeyPrivateKey: privateKey,
networkId: "base-mainnet",
});
const agentKit = await AgentKit.from({
cdpApiKeyName: apiKeyName,
cdpApiKeyPrivateKey: privateKey,
walletProvider: cdpWalletProvider,
actionProviders: [
basenameActionProvider(),
morphoActionProvider(),
walletActionProvider(),
cdpWalletActionProvider({
apiKeyName,
apiKeyPrivateKey: privateKey,
}),
],
});
const { tools, toolHandler } = await getMcpTools(agentKit);
const server = new Server(
{
name: "Base MCP Server",
version,
},
{
capabilities: {
tools: {},
},
},
);
Coinbase.configure({ apiKeyName, privateKey });
server.setRequestHandler(ListToolsRequestSchema, async () => {
console.error("Received ListToolsRequest");
return {
tools: [...baseMcpTools, ...tools],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// Check if the tool is Base MCP tool
const isBaseMcpTool = baseMcpTools.some(
(tool) => tool.name === request.params.name,
);
if (isBaseMcpTool) {
const tool = toolToHandler[request.params.name];
if (!tool) {
throw new Error(`Tool ${request.params.name} not found`);
}
const result = await tool(viemClient, request.params.arguments);
return {
content: [
{
type: "text",
text: JSON.stringify(result),
},
],
};
}
return toolHandler(request.params.name, request.params.arguments);
} catch (error) {
throw new Error(`Tool ${request.params.name} failed: ${error}`);
}
});
const transport = new StdioServerTransport();
console.error("Connecting server to transport...");
await server.connect(transport);
console.error("Base MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});