@aj-2000-test/goodlogs-mcp 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +46 -0
- package/package.json +27 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {z}from'zod';var g={eu:"https://goodlogs-api-eu.yellowmeadow-422296f6.japaneast.azurecontainerapps.io",ap:"https://goodlogs-api-ap.delightfulsand-90b72c09.southeastasia.azurecontainerapps.io"};function m(t,o){if(o)return o;let r=t.split("_");if(r.length>=4&&r[0]==="gl"){let s=r[2];if(g[s])return g[s]}return g.eu}var a=process.env.GOODLOGS_API_KEY??"",c=m(a,process.env.GOODLOGS_API_URL||void 0);function p(){if(a)return `Bearer ${a}`;throw new Error("Set GOODLOGS_API_KEY environment variable (create one at Dashboard \u2192 API Keys)")}async function l(t,o){let r=await fetch(`${c}${t}`,{method:o?"POST":"GET",headers:{"Content-Type":"application/json",Authorization:p(),"X-GoodLogs-SDK":"mcp/0.1.0"},body:o?JSON.stringify(o):void 0});if(!r.ok){let s=await r.text().catch(()=>"");throw new Error(`API error ${r.status}: ${s}`)}return r.json()}var n=new McpServer({name:"goodlogs",version:"0.1.0"});n.tool("query",`Query logs or events from GoodLogs. Two modes: search (individual rows) or aggregate (group by + metrics).
|
|
3
|
+
|
|
4
|
+
SEARCH examples:
|
|
5
|
+
- Recent errors: {"table":"logs","severity":"error","limit":10}
|
|
6
|
+
- Search by text: {"table":"logs","query":"payment","hours":6}
|
|
7
|
+
- Filter by metadata: {"table":"logs","metadata_filters":{"orderId":"ord_123"}}
|
|
8
|
+
- Filter by context: {"table":"logs","context_filters":{"service":"billing"}}
|
|
9
|
+
- Search events: {"table":"events","event_name":"purchase","limit":5}
|
|
10
|
+
- Filter by user: {"table":"events","distinct_id":"user_42"}
|
|
11
|
+
- Filter by properties: {"table":"events","properties_filters":{"plan":"pro"}}
|
|
12
|
+
|
|
13
|
+
AGGREGATE examples:
|
|
14
|
+
- Count by severity: {"table":"logs","mode":"aggregate","group_by":"severity"}
|
|
15
|
+
- Error messages ranked: {"table":"logs","mode":"aggregate","group_by":"message","severity":"error","limit":5}
|
|
16
|
+
- Errors per hour: {"table":"logs","mode":"aggregate","group_by":"hour","severity":"error","hours":24}
|
|
17
|
+
- Events per day: {"table":"events","mode":"aggregate","group_by":"day"}
|
|
18
|
+
- Top event names: {"table":"events","mode":"aggregate","group_by":"event_name","limit":10}
|
|
19
|
+
- Unique users: {"table":"events","mode":"aggregate","group_by":"event_name","metric":"dcount"}
|
|
20
|
+
- Sum revenue: {"table":"events","mode":"aggregate","group_by":"day","metric":"sum","metric_field":"properties.amount"}
|
|
21
|
+
- Avg response time: {"table":"logs","mode":"aggregate","group_by":"hour","metric":"avg","metric_field":"metadata.duration_ms"}
|
|
22
|
+
- Max latency by endpoint: {"table":"logs","mode":"aggregate","group_by":"code_location","metric":"max","metric_field":"metadata.duration_ms"}
|
|
23
|
+
- Min price: {"table":"events","mode":"aggregate","group_by":"event_name","metric":"min","metric_field":"properties.price"}
|
|
24
|
+
|
|
25
|
+
IMPORTANT \u2014 metric_field column reference:
|
|
26
|
+
- logs table JSONB columns: metadata, context \u2192 use "metadata.KEY" or "context.KEY"
|
|
27
|
+
- events table JSONB column: properties \u2192 use "properties.KEY"
|
|
28
|
+
- WRONG: {"table":"events","metric_field":"$value_ms"} \u2014 missing prefix
|
|
29
|
+
- RIGHT: {"table":"events","metric_field":"properties.$value_ms"}
|
|
30
|
+
- WRONG: {"table":"events","metric_field":"metadata.duration_ms"} \u2014 events don't have metadata
|
|
31
|
+
- RIGHT: {"table":"logs","metric_field":"metadata.duration_ms"}`,{table:z.enum(["logs","events"]).describe("Which table to query"),mode:z.enum(["search","aggregate"]).optional().describe("search=rows, aggregate=group by"),query:z.string().optional().describe("Text search on message (logs) or event_name (events)"),severity:z.enum(["debug","info","warn","error","fatal"]).optional(),code_location:z.string().optional().describe("Filter logs by code location"),metadata_filters:z.record(z.string(),z.string()).optional().describe("Filter logs metadata JSONB"),context_filters:z.record(z.string(),z.string()).optional().describe("Filter logs context JSONB"),event_name:z.string().optional().describe("Filter events by name"),distinct_id:z.string().optional().describe("Filter events by user ID"),properties_filters:z.record(z.string(),z.string()).optional().describe("Filter events properties JSONB"),group_by:z.enum(["severity","message","code_location","event_name","distinct_id","hour","day"]).optional(),metric:z.enum(["count","dcount","sum","avg","mean","min","max"]).optional(),metric_field:z.string().optional().describe("JSONB path for sum/avg/mean/min/max, e.g. metadata.duration_ms or properties.amount"),order:z.enum(["asc","desc"]).optional(),hours:z.number().optional().describe("Time range in hours (default 24)"),limit:z.number().optional().describe("Max results (default 20)")},async t=>{let o=await l("/v1/query",t);return {content:[{type:"text",text:JSON.stringify(o,null,2)}]}});n.tool("get_field_keys",`Discover available field keys and sample values in your GoodLogs data.
|
|
32
|
+
|
|
33
|
+
Sources:
|
|
34
|
+
- logs_metadata: business fields in log metadata
|
|
35
|
+
- logs_context: infrastructure fields in log context
|
|
36
|
+
- events_properties: fields in event properties
|
|
37
|
+
- event_names: distinct event names with counts
|
|
38
|
+
- logs_severities: severity levels with counts`,{source:z.enum(["logs_metadata","logs_context","events_properties","event_names","logs_severities"]).describe("Which field to discover keys for")},async t=>{let o=await l("/v1/query",_(t.source));return {content:[{type:"text",text:JSON.stringify(o,null,2)}]}});function _(t){switch(t){case "event_names":return {table:"events",mode:"aggregate",group_by:"event_name",limit:50};case "logs_severities":return {table:"logs",mode:"aggregate",group_by:"severity"};default:return {table:t.startsWith("events")?"events":"logs",limit:50}}}n.tool("get_alerts",`Get alert rules, their current status (ok/triggered), and recent incident timeline.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
- All alerts: {}
|
|
42
|
+
- Only firing: {"status": "triggered"}
|
|
43
|
+
- Error alerts in last 6h: {"metric": "error_count", "hours": 6}
|
|
44
|
+
- Rules only (no timeline): {"include_timeline": false}`,{status:z.enum(["ok","triggered","all"]).optional().describe("Filter by status (default: all)"),metric:z.enum(["error_count","event_count","log_volume"]).optional().describe("Filter by metric type"),hours:z.number().optional().describe("Timeline lookback in hours (default: 24)"),include_timeline:z.boolean().optional().describe("Include trigger/resolve events (default: true)")},async t=>{let r=await l("/v1/alerts");t.status&&t.status!=="all"&&(r=r.filter(i=>i.status===t.status)),t.metric&&(r=r.filter(i=>i.metric===t.metric));let s=[];return t.include_timeline!==false&&(s=await l("/v1/alerts/timeline").catch(()=>[])),{content:[{type:"text",text:JSON.stringify({alert_rules:r,total:r.length,triggered:r.filter(i=>i.status==="triggered").length,timeline:s},null,2)}]}});n.tool("get_project_info",`Get project details, organization info, billing plan, usage stats, and member count.
|
|
45
|
+
|
|
46
|
+
Returns: project name/slug, org name/plan/members/projects, monthly usage (events, logs bytes, AI queries), active API keys.`,{},async()=>{let t=await l("/v1/info");return {content:[{type:"text",text:JSON.stringify(t,null,2)}]}});n.resource("project-info","goodlogs://info",async()=>({contents:[{uri:"goodlogs://info",mimeType:"application/json",text:JSON.stringify({api_url:c,auth:"API key (gl_sk_...)",tools:["query","get_field_keys","get_alerts"],docs:"https://github.com/goodlogs/goodlogs"},null,2)}]}));async function b(){(!c||!a)&&(console.error("Error: Set required environment variables:"),c||console.error(" GOODLOGS_API_URL - Your GoodLogs API endpoint"),a||console.error(" GOODLOGS_API_KEY - API key (create at Dashboard \u2192 API Keys)"),console.error(""),console.error("Required scopes: data:read, alerts:read"),console.error("Usage:"),console.error(" GOODLOGS_API_URL=https://... GOODLOGS_API_KEY=gl_sk_... goodlogs-mcp"),process.exit(1));let t=new StdioServerTransport;await n.connect(t);}b().catch(t=>{console.error("Fatal:",t),process.exit(1);});
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aj-2000-test/goodlogs-mcp",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "GoodLogs MCP Server — AI agents can query your logs and events",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"goodlogs-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"start": "node dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
20
|
+
"zod": "^4.4.3"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.0.0",
|
|
24
|
+
"tsup": "^8.0.0",
|
|
25
|
+
"typescript": "^5.7.0"
|
|
26
|
+
}
|
|
27
|
+
}
|