Skip to main content
Glama
server.ts6.42 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { CdpClient } from "@coinbase/cdp-sdk"; import express from "express"; import cors from "cors"; import dotenv from "dotenv"; import { z } from "zod"; import { BASE_CONTRACTS, getContract } from "./data/contracts.js"; import { QUERY_TEMPLATES } from "./data/queryTemplates.js"; import { runSqlQuery, getTokenAge } from "./helpers/sqlQuery.js"; import { resolveName, getNameForAddress, getNamesForAddresses } from "./helpers/ensLookup.js"; import { getContractData, getContractByAddress } from "./helpers/contractLookup.js"; import { getSchemaData, getTemplateData, getCapabilities, getBestPractices } from "./helpers/metadata.js"; import { getTokenPrice, getMultipleTokenPrices } from "./helpers/pricing.js"; import { registerTools } from "./tools/index.js"; dotenv.config(); const PORT = parseInt(process.env.PORT || "4000"); // initialize CDP wallet (only if payments enabled) let wallet: any = null; const ENABLE_PAYMENTS = process.env.ENABLE_PAYMENTS === 'true'; if (ENABLE_PAYMENTS) { try { if (process.env.CDP_WALLET_SECRET) { const cdp = new CdpClient(); wallet = await cdp.evm.getOrCreateAccount({ name: "baseql-mcp-wallet" }); console.log(`BaseQL MCP wallet: ${wallet.address} (payments enabled)`); } else { console.log(`⚠️ ENABLE_PAYMENTS=true but no CDP_WALLET_SECRET - cannot receive payments`); } } catch (error) { console.log(`⚠️ wallet creation failed:`, error instanceof Error ? error.message : error); } } else { console.log(`💡 payments disabled (set ENABLE_PAYMENTS=true to monetize)`); } // create MCP server const mcpServer = new McpServer({ name: "baseql-mcp", version: "1.0.0", }); // register all MCP tools registerTools(mcpServer); // HTTP API for testing const app = express(); app.use(cors()); app.use(express.json()); // GET / - server info app.get('/', (req, res) => { res.json({ name: "BaseQL MCP Server", version: "1.0.0", description: "MCP server for Base SQL API context", wallet: wallet.address, endpoints: { "GET /tools": "List available tools", "POST /call": "Call a tool" } }); }); // MCP-over-HTTP endpoint (for ChatGPT) app.post('/', async (req, res) => { // set headers for MCP if (!req.headers.accept) { req.headers.accept = 'application/json, text/event-stream'; } // create transport for this request const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true }); res.on('close', () => { transport.close(); }); await mcpServer.connect(transport); await transport.handleRequest(req, res, req.body); }); // GET /tools - list all tools (for testing) app.get('/tools', async (req, res) => { const tools = [ { name: "get_schema", description: "get Base SQL tables" }, { name: "get_contract", description: "get contract address", params: ["symbol"] }, { name: "get_token_age", description: "🚨 CALL FIRST for holder queries! Returns safe time window", params: ["token_address"] }, { name: "get_sql_best_practices", description: "get SQL best practices" }, { name: "get_query_template", description: "get SQL template", params: ["templateKey"] }, { name: "resolve_name", description: "resolve ENS/Basename to address (forward lookup)", params: ["name"] }, { name: "get_name_for_address", description: "address to .eth name (.eth only, NOT Basenames)", params: ["address"] }, { name: "get_names_for_addresses", description: "batch reverse lookup (.eth only, NOT Basenames)", params: ["addresses[]"] }, { name: "run_sql_query", description: "execute SQL query", params: ["sql"] }, { name: "get_token_price", description: "get CEX price from Coinbase Exchange", params: ["symbol"] }, { name: "get_multiple_token_prices", description: "batch get CEX prices", params: ["symbols[]"] } ]; res.json({ tools }); }); // POST /call - call a tool app.post('/call', async (req, res) => { const { tool, params } = req.body; if (!tool) { return res.status(400).json({ error: "missing 'tool' parameter" }); } try { let result; switch(tool) { case "get_schema": result = await getSchemaData(); break; case "get_schema": result = await getSchemaData(); break; case "get_contract": result = await getContractData(params?.symbol); break; case "get_contract_by_address": result = await getContractByAddress(params?.address); break; case "get_query_template": result = await getTemplateData(params?.templateKey); break; case "get_capabilities": result = await getCapabilities(); break; case "get_sql_best_practices": result = await getBestPractices(); break; case "get_token_age": result = await getTokenAge(params?.token_address); break; case "run_sql_query": result = await runSqlQuery(params?.sql); break; case "resolve_name": result = await resolveName(params?.name); break; case "get_name_for_address": result = await getNameForAddress(params?.address); break; case "get_names_for_addresses": result = await getNamesForAddresses(params?.addresses); break; case "get_token_price": result = await getTokenPrice(params?.symbol); break; case "get_multiple_token_prices": result = await getMultipleTokenPrices(params?.symbols); break; case "get_sql_best_practices": result = await getBestPractices(); break; default: return res.status(404).json({ error: `unknown tool: ${tool}` }); } res.json(result); } catch (error) { res.status(500).json({ error: error instanceof Error ? error.message : "tool execution failed" }); } }); // start HTTP server app.listen(PORT, () => { console.log(`\nBaseQL MCP HTTP API: http://localhost:${PORT}`); console.log(`try: curl http://localhost:${PORT}/tools`); }); console.log("BaseQL MCP ready!");

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jnix2007/baseql-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server