Skip to main content
Glama

VictoriaMetrics-mcp-server

index.js8.99 kB
#!/usr/bin/env node 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 fetch from "node-fetch"; const VM_URL = process.env.VM_URL; const VM_SELECT_URL = process.env.VM_SELECT_URL const VM_INSERT_URL = process.env.VM_INSERT_URL const VM_DATA_WRITE_TOOL = { name: "vm_data_write", description: "Write data to the VM database", inputSchema: { type: "object", properties: { metric: { type: "object", description: "tag of metric", }, values: { type: "array", description: "Array of metric values", items: { "type": "number" }, }, timestamps: { type: "array", description: "Array of metric timestamps", items: { "type": "number" }, } }, required: ["metric", "values", "timestamps"], } }; const VM_PROMETHEUS_WRITE_TOOL = { name: "vm_prometheus_write", description: "mport Prometheus exposition format data into VictoriaMetrics", inputSchema: { type: "object", properties: { data: { type: "string", description: "Metrics data in Prometheus exposition format", }, }, required: ["data"], } }; const VM_QUERY_RANGE_TOOL = { name: "vm_query_range", description: "Query time series over a time range", inputSchema: { type: "object", properties: { query: { type: "string", description: "PromQL expression", }, start: { type: "number", description: "Start timestamp in Unix seconds", }, end: { type: "number", description: "End timestamp in Unix seconds", }, step: { type: "string", description: "Query resolution step width", } }, required: ["query"], } }; const VM_QUERY_TOOL = { name: "vm_query", description: "Query current value of a time series", inputSchema: { type: "object", properties: { query: { type: "string", description: "PromQL expression to evaluate", }, time: { type: "number", description: "Evaluation timestamp in Unix seconds (optional)", } }, required: ["query"], } }; const VM_LABELS_TOOL = { name: "vm_labels", description: "Get all unique label names", inputSchema: { type: "object", properties: {}, required: [], } }; const VM_LABEL_VALUES_TOOL = { name: "vm_label_values", description: "Get all unique values for a specific label", inputSchema: { type: "object", properties: { label: { type: "string", description: "Label name to retrieve values for", } }, required: ["label"], } }; const VM_TOOLS = [ VM_DATA_WRITE_TOOL, VM_QUERY_RANGE_TOOL, VM_QUERY_TOOL, VM_LABELS_TOOL, VM_LABEL_VALUES_TOOL, VM_PROMETHEUS_WRITE_TOOL ]; async function vmDataQuery(query, step) { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_SELECT_URL } const url = new URL(urlStr + "/api/v1/query"); url.searchParams.append("query", query); const response = await fetch(url.toString()); const data = await response.json(); if (data.status === "success") { return { content: [{ type: "text", text: JSON.stringify(data.data), }], isError: false }; } else { return { content: [{ type: "text", text: "range query fail:" + await response.text(), }], isError: true }; } } async function vmDataRangeQuery(query, start, end, step) { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_SELECT_URL } const url = new URL(urlStr + "/api/v1/query_range"); url.searchParams.append("query", query); url.searchParams.append("start", start ?? ""); url.searchParams.append("end", end ?? ""); url.searchParams.append("step", step ?? ""); const response = await fetch(url.toString()); const data = await response.json(); if (data.status === "success") { return { content: [{ type: "text", text: JSON.stringify(data.data), }], isError: false }; } else { return { content: [{ type: "text", text: "range query fail:" + await response.text(), }], isError: true }; } } async function vmMetricsDataWrite(metric, values, timestamps) { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_INSERT_URL } const url = new URL(urlStr + "/api/v1/import"); const data = { "metric": metric, "values": values, "timestamps": timestamps }; const response = await fetch(url.toString(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const status = response.status; if (status === 204) { return { content: [{ type: "text", text: response.text(), }], isError: false }; } else { return { content: [{ type: "text", text: response.text(), }], isError: true }; } } async function vmPrometheusWrite(data) { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_INSERT_URL } const url = new URL(urlStr + "/api/v1/import/prometheus"); const response = await fetch(url.toString(), { method: 'POST', headers: { 'Content-Type': 'text/plain' }, body: data }); const status = response.status; if (status === 204) { return { content: [{ type: "text", text: response.text(), }], isError: false }; } else { return { content: [{ type: "text", text: response.text(), }], isError: true }; } } async function vmLabels() { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_SELECT_URL } const url = new URL(urlStr + "/api/v1/labels"); const response = await fetch(url.toString()); const data = await response.json(); if (data.status === "success") { return { content: [{ type: "text", text: JSON.stringify(data.data), }], isError: false }; } else { return { content: [{ type: "text", text: "range query fail:" + await response.text(), }], isError: true }; } } async function vmLabelValues(label) { let urlStr = VM_URL if (urlStr === "") { urlStr = VM_SELECT_URL } const url = new URL(urlStr + "/api/v1/label/"+ label +"/values"); const response = await fetch(url.toString()); const data = await response.json(); if (data.status === "success") { return { content: [{ type: "text", text: JSON.stringify(data.data), }], isError: false }; } else { return { content: [{ type: "text", text: "range query fail:" + await response.text(), }], isError: true }; } } // Server setup const server = new Server({ name: "mcp-server/victoria-metrics", version: "0.1.0", }, { capabilities: { tools: {}, }, }); // Set up request handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: VM_TOOLS, })); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { switch (request.params.name) { case "vm_data_write": { const {metric, values, timestamps} = request.params.arguments; return await vmMetricsDataWrite(metric, values, timestamps); } case "vm_query_range": { const {query, start, end, step} = request.params.arguments; return await vmDataRangeQuery(query, start, end, step); } case "vm_query": { const {query, start, end, step} = request.params.arguments; return await vmDataQuery(query, start, end, step); } case "vm_labels": { return await vmLabels(); } case "vm_label_values": { const {label} = request.params.arguments; return await vmLabelValues(label); } case "vm_prometheus_write": { const {data} = request.params.arguments; return await vmPrometheusWrite(data); } default: return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true }; } } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }); async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("VictoriaMetrics MCP Server running on stdio"); } runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); });

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/yincongcyincong/VictoriaMetrics-mcp-server'

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