@mackerel/mcp-server 0.0.1 → 0.2.0
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/README.md +6 -5
- package/build/index.js +234 -21
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -18,11 +18,11 @@ The MCP server can be run either via Docker or npx.
|
|
|
18
18
|
"--rm",
|
|
19
19
|
"-i",
|
|
20
20
|
"-e",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
21
|
+
"MACKEREL_APIKEY",
|
|
22
|
+
"ghcr.io/mackerelio-labs/mcp-server:latest"
|
|
23
23
|
],
|
|
24
24
|
"env": {
|
|
25
|
-
"
|
|
25
|
+
"MACKEREL_APIKEY": "${MACKEREL_APIKEY}"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -38,10 +38,10 @@ The MCP server can be run either via Docker or npx.
|
|
|
38
38
|
"command": "npx",
|
|
39
39
|
"args": [
|
|
40
40
|
"-y",
|
|
41
|
-
"
|
|
41
|
+
"@mackerel/mcp-server"
|
|
42
42
|
],
|
|
43
43
|
"env": {
|
|
44
|
-
"
|
|
44
|
+
"MACKEREL_APIKEY": "${MACKEREL_APIKEY}"
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -62,3 +62,4 @@ The MCP server can be run either via Docker or npx.
|
|
|
62
62
|
* `get_service_metrics` - Retrieve metrics data for a specific service.
|
|
63
63
|
* `list_monitors` - Retrieve monitor configurations.
|
|
64
64
|
* `get_monitor` - Retrieve a specific monitor configuration.
|
|
65
|
+
* `get_trace` - Retrieve trace data by trace ID for distributed tracing analysis.
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,131 @@
|
|
|
1
|
-
import{McpServer as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as t}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as n}from"zod";async function r(e){try{let t=await e();return{content:[{type:`text`,text:JSON.stringify(t)}]}}catch(e){let t=e instanceof Error?e.message:String(e);return{content:[{type:`text`,text:`Error occurred: ${t}`}],isError:!0}}}var i=class{constructor(e){this.mackerelClient=e}static ListAlertsToolInput=n.object({withClosed:n.boolean().optional().describe(`Whether or not to get resolved alerts. If true, resolved alerts as well as open alerts are retrieved`),nextId:n.string().optional().describe(`If specified, alerts older than the alert with the specified id are retrieved`),limit:n.number().min(1).max(100).optional().describe(`The maximum number of alerts to retrieve. When omitted, up to 100 cases are retrieved. The most that can be specified is 100`)});listAlerts=async({withClosed:e,nextId:t,limit:n})=>await r(async()=>await this.mackerelClient.getAlerts(e,t,n));static GetAlertToolInput=n.object({alertId:n.string().describe(`The ID of the alert to retrieve`)});getAlert=async({alertId:e})=>await r(async()=>await this.mackerelClient.getAlert(e));static GetAlertLogsToolInput=n.object({alertId:n.string().describe(`The ID of the alert to retrieve logs for`),nextId:n.string().optional().describe(`If specified, alert logs older than the specified are retrieved`),limit:n.number().min(1).max(100).optional().describe(`The maximum number of alert logs to retrieve. When omitted, up to 100 logs are retrieved. The most that can be specified is 100`)});getAlertLogs=async({alertId:e,nextId:t,limit:n})=>await r(async()=>await this.mackerelClient.getAlertLogs(e,t,n))},a=class e{constructor(e){this.mackerelClient=e}static ListDashboardsToolInput=n.object({});listDashboards=async({})=>await r(async()=>await this.mackerelClient.getDashboards());static GetDashboardToolInput=n.object({dashboardId:n.string().describe(`The ID of the dashboard to retrieve`)});getDashboard=async({dashboardId:e})=>await r(async()=>await this.mackerelClient.getDashboard(e));static LayoutSchema=n.object({x:n.number().describe(`X coordinate of widget`),y:n.number().describe(`Y coordinate of widget`),width:n.number().describe(`Width of widget`),height:n.number().describe(`Height of widget`)});static RangeSchema=n.union([n.object({type:n.literal(`relative`).describe(`Relative time range`),period:n.number().describe(`Length of the period (in seconds)`),offset:n.number().describe(`Difference from the current time (in seconds)`)}),n.object({type:n.literal(`absolute`).describe(`Absolute time range`),start:n.number().describe(`Start time (in epoch seconds)`),end:n.number().describe(`End time (in epoch seconds)`)}),n.object({min:n.number().optional().describe(`Minimum value on vertical axis`),max:n.number().optional().describe(`Maximum value on vertical axis`)})]);static ValueRangeSchema=n.object({min:n.number().optional().describe(`Minimum value on vertical axis`),max:n.number().optional().describe(`Maximum value on vertical axis`)});static GraphSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`host`).describe(`Host graph`),hostId:n.string().describe(`Host ID`),name:n.string().describe(`Graph name (e.g., loadavg, cpu)`)}),n.object({type:n.literal(`role`).describe(`Role graph`),roleFullname:n.string().describe("The service name and role name linked with `:`"),name:n.string().describe(`Graph name`),isStacked:n.boolean().optional().describe(`Whether the graph is stacked or line graph`)}),n.object({type:n.literal(`service`).describe(`Service graph`),serviceName:n.string().describe(`Service name`),name:n.string().describe(`Graph name`)}),n.object({type:n.literal(`expression`).describe(`Expression graph`),expression:n.string().describe(`Expression representing a graph`)}),n.object({type:n.literal(`query`).describe(`Query graph`),query:n.string().describe(`PromQL-style queries`),legend:n.string().optional().describe('Query legend. by specifiying the label key in `{{ }}`, it can be expanded to the value of the label. e.g. if you have a label `{ http.method: "GET" }` and you specify `method: {{http.method}}` in the `legend`, it will expand to `method: GET`.')}),n.object({type:n.literal(`unknown`).describe(`Unknown graph`)})]);static ReferenceLineSchema=n.object({label:n.string().describe(`Label of the reference line`),value:n.number().describe(`Value of the reference line`)});static MetricSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`host`).describe(`Host metric`),hostId:n.string().describe(`Host ID`),name:n.string().describe("The name of the metric (`loadavg5` etc)")}),n.object({type:n.literal(`service`).describe(`Service metric`),serviceName:n.string().describe(`The name of the service`),name:n.string().describe(`The name of the metric`)}),n.object({type:n.literal(`expression`).describe(`Expression metric`),expression:n.string().describe(`An expression that represents a metric`)}),n.object({type:n.literal(`query`).describe(`Query metric`),query:n.string().describe(`PromQL-style queries`),legend:n.string().describe('Query legend. by specifying the label key in `{{ }}`, it can be expanded to the value of the label. e.g. if you have a label `{ http.method: "GET" }` and you specify `method: {{http.method}}` in the `legend`, it will expand to `method: GET`')}),n.object({type:n.literal(`unknown`).describe(`Unknown metric type (fallback when source is deleted)`)})]);static FormatRuleSchema=n.object({name:n.string().optional().describe(`Name of the format rule`),threshold:n.number().describe(`Base value of the conditional expression`),operator:n.enum([`>`,`<`]).describe(`Specify the conditions under which the emphasized style will be applied.`)});static WidgetSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`graph`).describe(`Graph widget`),title:n.string().describe(`The title of the widget`),graph:e.GraphSchema.describe(`Object representing a graph`),range:e.RangeSchema.optional().describe(`Object representing the graph display range`),valueRange:e.ValueRangeSchema.optional().describe(`Object representing the value range of vertical axis`),referenceLines:n.array(e.ReferenceLineSchema).optional().describe(`Array of objects representing the reference line. If you want to remove the reference line setting, specify an empty array. If reference line is not set when get dashboards, an empty array is returned. Cannot specify more than one element in an array.`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`value`).describe(`Value widget`),title:n.string().describe(`The title of the widget`),metric:e.MetricSchema.describe(`Object representing a metric`),fractionSize:n.number().optional().describe(`Decimal places displayed on the widget (0–16)`),suffix:n.string().optional().describe(`The units to be displayed after the value`),formatRules:n.array(e.FormatRuleSchema).optional().describe(`Array of objects representing the format rule. If you want to remove the format rule setting, specify an empty array. If format rule is not set when get dashboards, an empty array is returned. Cannot specify more than one element in an array.`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`markdown`).describe(`Markdown widget`),title:n.string().describe(`The title of the widget`),markdown:n.string().describe(`A character string in Markdown format`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`alertStatus`).describe(`Alert status widget`),title:n.string().describe(`The title of the widget`),roleFullname:n.string().describe("The service name and role name linked by `:`.However, if the relevant role or service has been deleted when the dashboard is retrieved, `roleFullname` will be set as `null`. "),layout:e.LayoutSchema.describe(`Object representing the layout`)})]);static UpdateDashboardToolInput=n.object({dashboardId:n.string().describe(`The ID of the dashboard to update`),title:n.string().describe(`Dashboard name`),memo:n.string().describe(`Dashboard notes`),urlPath:n.string().describe(`Dashboard URL path`),widgets:n.array(e.WidgetSchema).describe(`List of widget objects`)});updateDashboard=async({dashboardId:e,title:t,memo:n,urlPath:i,widgets:a})=>await r(async()=>await this.mackerelClient.updateDashboard(e,{title:t,memo:n,urlPath:i,widgets:a}))},o=class{constructor(e){this.mackerelClient=e}static ListMonitorsToolInput=n.object({});listMonitors=async({})=>await r(async()=>await this.mackerelClient.getMonitors());static GetMonitorToolInput=n.object({monitorId:n.string().describe(`Monitor ID`)});getMonitor=async({monitorId:e})=>await r(async()=>await this.mackerelClient.getMonitor(e))},s=class{constructor(e){this.mackerelClient=e}static ListHostsToolInput=n.object({service:n.string().optional().describe(`Service name`),role:n.array(n.string()).optional().describe(`Role names in the service, multiple assignments possible (result will be a unit of the hosts that belong to each role) if service has not been assigned it will be ignored.`),name:n.string().optional().describe(`Host name`),status:n.array(n.string()).optional().describe("Filters the host status. multiple specifications are possible. defaults are `working` and `standby`."),customIdentifier:n.string().optional().describe(`An identifier for the host that is user-specific and unique to the organization (registered at Register Host Information or Update Host Information API)`)});listHosts=async({service:e,role:t,name:n,status:i,customIdentifier:a})=>await r(async()=>await this.mackerelClient.getHosts(e,t,n,i,a))},c=class{constructor(e){this.mackerelClient=e}static ListServicesToolInput=n.object({});listServices=async e=>await r(async()=>await this.mackerelClient.getServices())},l=class{baseUrl;apiKey;constructor(e,t){this.baseUrl=e,this.apiKey=t}async request(e,t,{searchParams:n,body:r}={}){let i=`${this.baseUrl}${t}${n?`?`+n.toString():``}`,a={"X-Api-Key":this.apiKey,"Content-Type":`application/json`},o={method:e,headers:a};r&&(o.body=JSON.stringify(r));let s=await fetch(i,o);if(!s.ok){let e=await s.text();throw Error(`Mackerel API error: ${s.status} ${e}`)}return await s.json()}async getAlerts(e,t,n){let r=new URLSearchParams;return e!==void 0&&r.append(`withClosed`,e.toString()),t&&r.append(`nextId`,t),n!==void 0&&r.append(`limit`,n.toString()),this.request(`GET`,`/api/v0/alerts`,{searchParams:r})}async getAlert(e){return this.request(`GET`,`/api/v0/alerts/${e}`)}async getAlertLogs(e,t,n){let r=new URLSearchParams;return t&&r.append(`nextId`,t),n!==void 0&&r.append(`limit`,n.toString()),this.request(`GET`,`/api/v0/alerts/${e}/logs`,{searchParams:r})}async getDashboards(){return this.request(`GET`,`/api/v0/dashboards`)}async getDashboard(e){return this.request(`GET`,`/api/v0/dashboards/${e}`)}static WidgetArray=n.array(a.WidgetSchema);async updateDashboard(e,t){return this.request(`PUT`,`/api/v0/dashboards/${e}`,{body:t})}async getHosts(e,t,n,r,i){let a=new URLSearchParams;if(e&&a.append(`service`,e),t)for(let e of t)a.append(`role`,e);if(n&&a.append(`name`,n),r)for(let e of r)a.append(`status`,e);return i&&a.append(`customIdentifier`,i),this.request(`GET`,`/api/v0/hosts`,{searchParams:a})}async getHostMetrics(e,t,n,r){let i=new URLSearchParams;return i.append(`name`,t),i.append(`from`,n.toString()),i.append(`to`,r.toString()),this.request(`GET`,`/api/v0/hosts/${e}/metrics`,{searchParams:i})}async getServices(){return this.request(`GET`,`/api/v0/services`)}async getServiceMetrics(e,t,n,r){let i=new URLSearchParams;return i.append(`name`,t),i.append(`from`,n.toString()),i.append(`to`,r.toString()),this.request(`GET`,`/api/v0/services/${e}/metrics`,{searchParams:i})}async getMonitors(){return this.request(`GET`,`/api/v0/monitors`)}async getMonitor(e){return this.request(`GET`,`/api/v0/monitors/${e}`)}},u=class{constructor(e){this.mackerelClient=e}static GetServiceMetricsToolInput=n.object({serviceName:n.string().describe(`Service name`),name:n.string().describe(`Metric name`),from:n.number().describe(`The start of the time period you want metrics for (unix time)`),to:n.number().describe(`The end of the time period you want metrics for (unix time)`)});getServiceMetrics=async({serviceName:e,name:t,from:n,to:i})=>await r(async()=>await this.mackerelClient.getServiceMetrics(e,t,n,i))},d=class{constructor(e){this.mackerelClient=e}static GetHostMetricsToolInput=n.object({hostId:n.string().describe(`Host ID`),name:n.string().describe(`Metric name(loadavg5, etc.)`),from:n.number().describe(`The start of the time period you want metrics for (unix time)`),to:n.number().describe(`The end of the time period you want metrics for (unix time)`)});getHostMetrics=async({hostId:e,name:t,from:n,to:i})=>await r(async()=>await this.mackerelClient.getHostMetrics(e,t,n,i))};async function f(){let n=new l(`https://api.mackerelio.com`,p()),r=new i(n),f=new a(n),m=new o(n),h=new s(n),g=new d(n),_=new c(n),v=new u(n),y=new e({name:`mackerel-mcp`,version:`0.0.1`});y.registerTool(`list_alerts`,{title:`List Alerts`,description:`Retrieve alerts from Mackerel.
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{McpServer as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as t}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as n}from"zod";const r=25e3;function i(e,t){let{limit:n=20,offset:r=0}=t;return e.slice(r,r+n)}function a(e){return Math.ceil(e.length/4)}function o(e){return`Response too large (estimated ${e.toLocaleString()} tokens, limit ${r.toLocaleString()} tokens). Please resolve this by:
|
|
3
|
+
- Using the limit parameter to reduce the number of items returned
|
|
4
|
+
- Using offset or nextId parameters for pagination
|
|
5
|
+
- Applying more specific filters to narrow down the results`}function s(){return`
|
|
6
|
+
## Available Host Metrics:
|
|
7
|
+
- **loadavg**: loadavg1, loadavg5, loadavg15
|
|
8
|
+
- **cpu**: cpu.user.percentage, cpu.system.percentage, cpu.idle.percentage, cpu.iowait.percentage, cpu.nice.percentage, cpu.irq.percentage, cpu.softirq.percentage, cpu.steal.percentage, cpu.guest.percentage
|
|
9
|
+
- **memory**: memory.used, memory.available, memory.total, memory.swap_used, memory.swap_cached, memory.swap_total (Kernel 3.14+)
|
|
10
|
+
- For older Linux: memory.free, memory.buffers, memory.cached, memory.used, memory.total, memory.swap_used, memory.swap_cached, memory.swap_total
|
|
11
|
+
- **disk**: disk.*.reads.delta, disk.*.writes.delta (replace * with device name)
|
|
12
|
+
- **interface**: interface.*.rxBytes.delta, interface.*.txBytes.delta (replace * with interface name)
|
|
13
|
+
- **filesystem**: filesystem.*.size, filesystem.*.used (replace * with mount point)`}function c(){return`
|
|
14
|
+
## Available Service Metrics:
|
|
15
|
+
- Custom metrics posted to your service via mackerel-agent or API
|
|
16
|
+
- Check your service configuration for available metric names
|
|
17
|
+
- Common patterns: response_time, throughput, error_rate, custom.metric_name`}function l(e){let t=e.toLowerCase();return t.includes(`host not found`)?`## Host Not Found
|
|
18
|
+
|
|
19
|
+
Your request failed because the specified hostId does not exist in your Mackerel organization.
|
|
20
|
+
|
|
21
|
+
## Error Summary
|
|
22
|
+
${e}
|
|
23
|
+
|
|
24
|
+
## Possible Causes
|
|
25
|
+
- The hostId does not exist in your Mackerel organization
|
|
26
|
+
- The host may have been deleted or decommissioned
|
|
27
|
+
- There may be a typo in the hostId
|
|
28
|
+
|
|
29
|
+
## Resolving Host Issues
|
|
30
|
+
- Use the list_hosts tool to find valid host IDs
|
|
31
|
+
- Check for typos in the hostId
|
|
32
|
+
- Verify the host hasn't been deleted from your organization
|
|
33
|
+
- Ensure you have the correct permissions to access this host`:t.includes(`metric not found`)?`## Metric Not Found
|
|
34
|
+
|
|
35
|
+
Your request failed because the specified metric name is invalid or not available for this host.
|
|
36
|
+
|
|
37
|
+
## Error Summary
|
|
38
|
+
${e}
|
|
39
|
+
|
|
40
|
+
## Possible Causes
|
|
41
|
+
- The metric name contains typos or incorrect format
|
|
42
|
+
- The metric may not be available on this host
|
|
43
|
+
- The metric collection may not be enabled
|
|
44
|
+
|
|
45
|
+
## Resolving Metric Issues
|
|
46
|
+
- Check for typos in the metric name
|
|
47
|
+
- Verify the metric is available on this host type
|
|
48
|
+
|
|
49
|
+
${s()}
|
|
50
|
+
|
|
51
|
+
## Valid Metric Name Examples
|
|
52
|
+
- loadavg5, cpu.user.percentage, memory.used, disk.sda.reads.delta`:`## Resource Not Found: Invalid Host or Metric
|
|
53
|
+
|
|
54
|
+
Your request failed because the specified hostId does not exist or the metric name is invalid.
|
|
55
|
+
|
|
56
|
+
## Error Summary
|
|
57
|
+
${e}
|
|
58
|
+
|
|
59
|
+
## Possible Causes
|
|
60
|
+
- The hostId does not exist in your Mackerel organization
|
|
61
|
+
- The metric name contains typos or incorrect format
|
|
62
|
+
- The host may have been deleted or renamed
|
|
63
|
+
|
|
64
|
+
## Resolving Host Issues
|
|
65
|
+
- Verify the hostId exists by listing all hosts first
|
|
66
|
+
- Check for typos in the hostId
|
|
67
|
+
- Use the list_hosts tool to find valid host IDs
|
|
68
|
+
|
|
69
|
+
${s()}
|
|
70
|
+
|
|
71
|
+
## Valid Metric Name Examples
|
|
72
|
+
- loadavg5, cpu.user.percentage, memory.used, disk.sda.reads.delta`}function u(e){let t=e.toLowerCase();return t.includes(`service not found`)?`## Service Not Found
|
|
73
|
+
|
|
74
|
+
Your request failed because the specified serviceName does not exist in your Mackerel organization.
|
|
75
|
+
|
|
76
|
+
## Error Summary
|
|
77
|
+
${e}
|
|
78
|
+
|
|
79
|
+
## Possible Causes
|
|
80
|
+
- The serviceName does not exist in your Mackerel organization
|
|
81
|
+
- The service may have been deleted or renamed
|
|
82
|
+
- There may be a typo in the serviceName
|
|
83
|
+
|
|
84
|
+
## Resolving Service Issues
|
|
85
|
+
- Use the list_services tool to find valid service names
|
|
86
|
+
- Check for typos in the serviceName
|
|
87
|
+
- Verify the service hasn't been deleted from your organization
|
|
88
|
+
- Ensure you have the correct permissions to access this service`:t.includes(`metric not found`)?`## Metric Not Found
|
|
89
|
+
|
|
90
|
+
Your request failed because the specified metric name is invalid or not available for this service.
|
|
91
|
+
|
|
92
|
+
## Error Summary
|
|
93
|
+
${e}
|
|
94
|
+
|
|
95
|
+
## Possible Causes
|
|
96
|
+
- The metric name contains typos or incorrect format
|
|
97
|
+
- The metric may not be posted to this service
|
|
98
|
+
- The metric collection may not be configured
|
|
99
|
+
|
|
100
|
+
## Resolving Metric Issues
|
|
101
|
+
- Check for typos in the metric name
|
|
102
|
+
- Verify the metric is being posted to this service
|
|
103
|
+
- Configure metric collection if needed
|
|
104
|
+
|
|
105
|
+
${c()}
|
|
106
|
+
|
|
107
|
+
## Valid Metric Name Examples
|
|
108
|
+
- response_time, custom.my_metric, throughput`:`## Resource Not Found: Invalid Service or Metric
|
|
109
|
+
|
|
110
|
+
Your request failed because the specified serviceName does not exist or the metric name is invalid.
|
|
111
|
+
|
|
112
|
+
## Error Summary
|
|
113
|
+
${e}
|
|
114
|
+
|
|
115
|
+
## Possible Causes
|
|
116
|
+
- The serviceName does not exist in your Mackerel organization
|
|
117
|
+
- The metric name contains typos or incorrect format
|
|
118
|
+
- The service may have been deleted or renamed
|
|
119
|
+
|
|
120
|
+
## Resolving Service Issues
|
|
121
|
+
- Verify the serviceName exists by listing all services first
|
|
122
|
+
- Check for typos in the serviceName
|
|
123
|
+
- Use the list_services tool to find valid service names
|
|
124
|
+
|
|
125
|
+
${c()}
|
|
126
|
+
|
|
127
|
+
## Valid Metric Name Examples
|
|
128
|
+
- response_time, custom.my_metric, throughput`}async function d(e,t){try{let t=await e(),n=JSON.stringify(t),i=a(n);return i>r?{content:[{type:`text`,text:o(i)}],isError:!0}:{content:[{type:`text`,text:n}]}}catch(e){let n=e instanceof Error?e.message:String(e);if(t&&n.includes(`404`)&&(t===`get_host_metrics`||t===`get_service_metrics`)){let e;return e=t===`get_host_metrics`?l(n):u(n),{content:[{type:`text`,text:e}],isError:!0}}return{content:[{type:`text`,text:`Error occurred: ${n}`}],isError:!0}}}var f=class{constructor(e){this.mackerelClient=e}static ListAlertsToolInput=n.object({withClosed:n.boolean().optional().describe(`Whether or not to get resolved alerts. If true, resolved alerts as well as open alerts are retrieved`),nextId:n.string().optional().describe(`If specified, alerts older than the alert with the specified id are retrieved`),limit:n.number().min(1).max(100).optional().describe(`The maximum number of alerts to retrieve. When omitted, up to 100 cases are retrieved. The most that can be specified is 100`)});listAlerts=async({withClosed:e,nextId:t,limit:n})=>await d(async()=>await this.mackerelClient.getAlerts(e,t,n));static GetAlertToolInput=n.object({alertId:n.string().describe(`The ID of the alert to retrieve`)});getAlert=async({alertId:e})=>await d(async()=>await this.mackerelClient.getAlert(e));static GetAlertLogsToolInput=n.object({alertId:n.string().describe(`The ID of the alert to retrieve logs for`),nextId:n.string().optional().describe(`If specified, alert logs older than the specified are retrieved`),limit:n.number().min(1).max(100).optional().describe(`The maximum number of alert logs to retrieve. When omitted, up to 100 logs are retrieved. The most that can be specified is 100`)});getAlertLogs=async({alertId:e,nextId:t,limit:n})=>await d(async()=>await this.mackerelClient.getAlertLogs(e,t,n))},p=class e{constructor(e){this.mackerelClient=e}static ListDashboardsToolInput=n.object({limit:n.number().int().positive().optional().describe(`Maximum number of dashboards to return (default: 20)`),offset:n.number().int().min(0).optional().describe(`Number of dashboards to skip (default: 0)`),summary:n.boolean().optional().default(!0).describe(`If true, omit widget details to reduce response size (default: true)`)});listDashboards=async({limit:e,offset:t,summary:n=!0})=>await d(async()=>{let r=await this.mackerelClient.getDashboards(e,t);if(n){let e=r.dashboards.map(e=>({id:e.id,title:e.title,memo:e.memo,urlPath:e.urlPath,createdAt:e.createdAt,updatedAt:e.updatedAt,widgetCount:e.widgets?.length||0}));return{dashboards:e,pageInfo:r.pageInfo}}return r});static GetDashboardToolInput=n.object({dashboardId:n.string().describe(`The ID of the dashboard to retrieve`)});getDashboard=async({dashboardId:e})=>await d(async()=>await this.mackerelClient.getDashboard(e));static LayoutSchema=n.object({x:n.number().describe(`X coordinate of widget`),y:n.number().describe(`Y coordinate of widget`),width:n.number().describe(`Width of widget`),height:n.number().describe(`Height of widget`)});static RangeSchema=n.union([n.object({type:n.literal(`relative`).describe(`Relative time range`),period:n.number().describe(`Length of the period (in seconds)`),offset:n.number().describe(`Difference from the current time (in seconds)`)}),n.object({type:n.literal(`absolute`).describe(`Absolute time range`),start:n.number().describe(`Start time (in epoch seconds)`),end:n.number().describe(`End time (in epoch seconds)`)}),n.object({min:n.number().optional().describe(`Minimum value on vertical axis`),max:n.number().optional().describe(`Maximum value on vertical axis`)})]);static ValueRangeSchema=n.object({min:n.number().optional().describe(`Minimum value on vertical axis`),max:n.number().optional().describe(`Maximum value on vertical axis`)});static GraphSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`host`).describe(`Host graph`),hostId:n.string().describe(`Host ID`),name:n.string().describe(`Graph name (e.g., loadavg, cpu)`)}),n.object({type:n.literal(`role`).describe(`Role graph`),roleFullname:n.string().describe("The service name and role name linked with `:`"),name:n.string().describe(`Graph name`),isStacked:n.boolean().optional().describe(`Whether the graph is stacked or line graph`)}),n.object({type:n.literal(`service`).describe(`Service graph`),serviceName:n.string().describe(`Service name`),name:n.string().describe(`Graph name`)}),n.object({type:n.literal(`expression`).describe(`Expression graph`),expression:n.string().describe(`Expression representing a graph`)}),n.object({type:n.literal(`query`).describe(`Query graph`),query:n.string().describe(`PromQL-style queries`),legend:n.string().optional().describe('Query legend. by specifiying the label key in `{{ }}`, it can be expanded to the value of the label. e.g. if you have a label `{ http.method: "GET" }` and you specify `method: {{http.method}}` in the `legend`, it will expand to `method: GET`.')}),n.object({type:n.literal(`unknown`).describe(`Unknown graph`)})]);static ReferenceLineSchema=n.object({label:n.string().describe(`Label of the reference line`),value:n.number().describe(`Value of the reference line`)});static MetricSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`host`).describe(`Host metric`),hostId:n.string().describe(`Host ID`),name:n.string().describe("The name of the metric (`loadavg5` etc)")}),n.object({type:n.literal(`service`).describe(`Service metric`),serviceName:n.string().describe(`The name of the service`),name:n.string().describe(`The name of the metric`)}),n.object({type:n.literal(`expression`).describe(`Expression metric`),expression:n.string().describe(`An expression that represents a metric`)}),n.object({type:n.literal(`query`).describe(`Query metric`),query:n.string().describe(`PromQL-style queries`),legend:n.string().describe('Query legend. by specifying the label key in `{{ }}`, it can be expanded to the value of the label. e.g. if you have a label `{ http.method: "GET" }` and you specify `method: {{http.method}}` in the `legend`, it will expand to `method: GET`')}),n.object({type:n.literal(`unknown`).describe(`Unknown metric type (fallback when source is deleted)`)})]);static FormatRuleSchema=n.object({name:n.string().optional().describe(`Name of the format rule`),threshold:n.number().describe(`Base value of the conditional expression`),operator:n.enum([`>`,`<`]).describe(`Specify the conditions under which the emphasized style will be applied.`)});static WidgetSchema=n.discriminatedUnion(`type`,[n.object({type:n.literal(`graph`).describe(`Graph widget`),title:n.string().describe(`The title of the widget`),graph:e.GraphSchema.describe(`Object representing a graph`),range:e.RangeSchema.optional().describe(`Object representing the graph display range`),valueRange:e.ValueRangeSchema.optional().describe(`Object representing the value range of vertical axis`),referenceLines:n.array(e.ReferenceLineSchema).optional().describe(`Array of objects representing the reference line. If you want to remove the reference line setting, specify an empty array. If reference line is not set when get dashboards, an empty array is returned. Cannot specify more than one element in an array.`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`value`).describe(`Value widget`),title:n.string().describe(`The title of the widget`),metric:e.MetricSchema.describe(`Object representing a metric`),fractionSize:n.number().optional().describe(`Decimal places displayed on the widget (0–16)`),suffix:n.string().optional().describe(`The units to be displayed after the value`),formatRules:n.array(e.FormatRuleSchema).optional().describe(`Array of objects representing the format rule. If you want to remove the format rule setting, specify an empty array. If format rule is not set when get dashboards, an empty array is returned. Cannot specify more than one element in an array.`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`markdown`).describe(`Markdown widget`),title:n.string().describe(`The title of the widget`),markdown:n.string().describe(`A character string in Markdown format`),layout:e.LayoutSchema.describe(`Object representing the layout`)}),n.object({type:n.literal(`alertStatus`).describe(`Alert status widget`),title:n.string().describe(`The title of the widget`),roleFullname:n.string().describe("The service name and role name linked by `:`.However, if the relevant role or service has been deleted when the dashboard is retrieved, `roleFullname` will be set as `null`. "),layout:e.LayoutSchema.describe(`Object representing the layout`)})]);static UpdateDashboardToolInput=n.object({dashboardId:n.string().describe(`The ID of the dashboard to update`),title:n.string().describe(`Dashboard name`),memo:n.string().describe(`Dashboard notes`),urlPath:n.string().describe(`Dashboard URL path`),widgets:n.array(e.WidgetSchema).describe(`List of widget objects`)});updateDashboard=async({dashboardId:e,title:t,memo:n,urlPath:r,widgets:i})=>await d(async()=>await this.mackerelClient.updateDashboard(e,{title:t,memo:n,urlPath:r,widgets:i}))},m=class{constructor(e){this.mackerelClient=e}static ListMonitorsToolInput=n.object({});listMonitors=async({})=>await d(async()=>await this.mackerelClient.getMonitors());static GetMonitorToolInput=n.object({monitorId:n.string().describe(`Monitor ID`)});getMonitor=async({monitorId:e})=>await d(async()=>await this.mackerelClient.getMonitor(e))},h=class{constructor(e){this.mackerelClient=e}static ListHostsToolInput=n.object({service:n.string().optional().describe(`Service name`),role:n.array(n.string()).optional().describe(`Role names in the service, multiple assignments possible (result will be a unit of the hosts that belong to each role) if service has not been assigned it will be ignored.`),name:n.string().optional().describe(`Host name`),status:n.array(n.string()).optional().describe("Filters the host status. multiple specifications are possible. defaults are `working` and `standby`."),customIdentifier:n.string().optional().describe(`An identifier for the host that is user-specific and unique to the organization (registered at Register Host Information or Update Host Information API)`),limit:n.number().int().positive().max(100).optional().describe(`Maximum number of hosts to return (default: 20, max: 100)`),offset:n.number().int().min(0).optional().describe(`Number of hosts to skip (default: 0)`)});listHosts=async({service:e,role:t,name:n,status:r,customIdentifier:i,limit:a=20,offset:o=0})=>await d(async()=>{let s=await this.mackerelClient.getHosts(e,t,n,r,i,a,o);return s})},g=class{constructor(e){this.mackerelClient=e}static ListServicesToolInput=n.object({});listServices=async e=>await d(async()=>await this.mackerelClient.getServices())},_=class{constructor(e){this.mackerelClient=e}static GetTraceToolInput=n.object({traceId:n.string().describe(`The ID of the trace to retrieve`),includeAttributes:n.boolean().optional().default(!1).describe(`Whether to include span attributes. Default is false to reduce response size`),includeEvents:n.boolean().optional().default(!0).describe(`Whether to include span events. Default is true as events contain important error information`),limit:n.number().int().positive().max(100).optional().default(20).describe(`Maximum number of spans to return per page (default: 20, max: 100)`),offset:n.number().int().min(0).optional().default(0).describe(`Number of spans to skip (default: 0)`),duration:n.number().min(0).optional().describe(`Only return spans with duration (in milliseconds) equal to or greater than this value. Useful for identifying bottlenecks`),errorSpansOnly:n.boolean().optional().default(!1).describe(`If true, only return spans that have errors or status code indicating failure`)});optimizeSpan(e,t,n){let r=e.endTime-e.startTime,i=this.hasSpanError(e),a={spanId:e.spanId,name:e.name,startTime:e.startTime,endTime:e.endTime,duration:r,hasError:i};return t&&(a.attributes=e.attributes),n&&(a.events=e.events),e.status&&e.status.code.toLowerCase()===`error`&&(a.status=e.status),a}hasSpanError(e){return e.status&&e.status.code.toLowerCase()===`error`?!0:e.events?e.events.some(e=>e.name.toLowerCase().includes(`exception`)):!1}filterAndSortSpans(e,t,n){let r=e;return n&&(r=r.filter(e=>e.hasError)),t!==void 0&&(r=r.filter(e=>e.duration>=t)),r.sort((e,t)=>e.hasError&&!t.hasError?-1:!e.hasError&&t.hasError?1:t.duration-e.duration),r}createPageInfo(e,t,n){let r=Math.floor(n/t)+1,i=Math.ceil(e/t);return{hasNextPage:n+t<e,hasPrevPage:n>0,currentPage:r,totalPages:i}}getTrace=async({traceId:e,includeAttributes:t=!1,includeEvents:n=!0,limit:r=20,offset:a=0,duration:o,errorSpansOnly:s=!1})=>await d(async()=>{let c=await this.mackerelClient.getTrace(e),l=c.spans.map(e=>this.optimizeSpan(e,t,n)),u=this.filterAndSortSpans(l,o,s),d=i(u,{limit:r,offset:a}),f=this.createPageInfo(u.length,r,a),p=c.spans.length,m=d.some(e=>e.hasError),h=0;if(l.length>0){let e=Math.min(...l.map(e=>e.startTime)),t=Math.max(...l.map(e=>e.endTime));h=t-e}return{traceId:e,summary:{totalSpans:p,hasErrors:m,totalDuration:h,pageInfo:f},spans:d}})},v=class{baseUrl;apiKey;cacheMap=new Map;cacheTTL;constructor(e,t,n=300){this.baseUrl=e,this.apiKey=t,this.cacheTTL=n*1e3}getCacheKey(e,t,n){let r=n?n.toString():``;return`${e}:${t}:${r}`}getFromCache(e){let t=this.cacheMap.get(e);if(!t)return null;let n=Date.now();return n-t.timestamp>this.cacheTTL?(this.cacheMap.delete(e),null):t.data}setCache(e,t){this.cacheMap.set(e,{data:t,timestamp:Date.now()})}clearCache(){this.cacheMap.clear()}async request(e,t,{searchParams:n,body:r}={}){if(e===`GET`){let r=this.getCacheKey(e,t,n),i=this.getFromCache(r);if(i!==null)return i}let i=`${this.baseUrl}${t}${n?`?`+n.toString():``}`,a={"X-Api-Key":this.apiKey,"Content-Type":`application/json`},o={method:e,headers:a};r&&(o.body=JSON.stringify(r));let s=await fetch(i,o);if(!s.ok){let e=await s.text();throw Error(`Mackerel API error: ${s.status} ${e}`)}let c=await s.json();if(e===`GET`){let r=this.getCacheKey(e,t,n);this.setCache(r,c)}return c}async getAlerts(e,t,n){let r=new URLSearchParams;return e!==void 0&&r.append(`withClosed`,e.toString()),t&&r.append(`nextId`,t),n!==void 0&&r.append(`limit`,n.toString()),this.request(`GET`,`/api/v0/alerts`,{searchParams:r})}async getAlert(e){return this.request(`GET`,`/api/v0/alerts/${e}`)}async getAlertLogs(e,t,n){let r=new URLSearchParams;return t&&r.append(`nextId`,t),n!==void 0&&r.append(`limit`,n.toString()),this.request(`GET`,`/api/v0/alerts/${e}/logs`,{searchParams:r})}async getDashboards(e,t){let n=await this.request(`GET`,`/api/v0/dashboards`),r=e||20,a=t||0,o=n.dashboards.length,s=i(n.dashboards,{limit:r,offset:a}),c={hasPrevPage:a>0,hasNextPage:a+r<o};return{dashboards:s,pageInfo:c}}async getDashboard(e){return this.request(`GET`,`/api/v0/dashboards/${e}`)}static WidgetArray=n.array(p.WidgetSchema);async updateDashboard(e,t){return this.request(`PUT`,`/api/v0/dashboards/${e}`,{body:t})}async getHosts(e,t,n,r,a,o,s){let c=new URLSearchParams;if(e&&c.append(`service`,e),t)for(let e of t)c.append(`role`,e);if(n&&c.append(`name`,n),r)for(let e of r)c.append(`status`,e);a&&c.append(`customIdentifier`,a);let l=await this.request(`GET`,`/api/v0/hosts`,{searchParams:c}),u=o||20,d=s||0,f=l.hosts.length,p=i(l.hosts,{limit:u,offset:d}),m={hasPrevPage:d>0,hasNextPage:d+u<f};return{hosts:p,pageInfo:m}}async getHostMetrics(e,t,n,r){let i=new URLSearchParams;return i.append(`name`,t),i.append(`from`,n.toString()),i.append(`to`,r.toString()),this.request(`GET`,`/api/v0/hosts/${e}/metrics`,{searchParams:i})}async getServices(){return this.request(`GET`,`/api/v0/services`)}async getServiceMetrics(e,t,n,r){let i=new URLSearchParams;return i.append(`name`,t),i.append(`from`,n.toString()),i.append(`to`,r.toString()),this.request(`GET`,`/api/v0/services/${e}/metrics`,{searchParams:i})}async getMonitors(){return this.request(`GET`,`/api/v0/monitors`)}async getMonitor(e){return this.request(`GET`,`/api/v0/monitors/${e}`)}async getTrace(e){return this.request(`GET`,`/api/v0/traces/${e}`)}},y=class{constructor(e){this.mackerelClient=e}static GetServiceMetricsToolInput=n.object({serviceName:n.string().describe(`Service name`),name:n.string().describe(`Metric name (e.g., __externalhttp.responsetime.<monitorId>, sales.count, analytics.page_view, etc.)`),from:n.number().describe(`The start of the time period you want metrics for (unix time)`),to:n.number().describe(`The end of the time period you want metrics for (unix time)`)});getServiceMetrics=async({serviceName:e,name:t,from:n,to:r})=>await d(async()=>await this.mackerelClient.getServiceMetrics(e,t,n,r),`get_service_metrics`)},b=class{constructor(e){this.mackerelClient=e}static GetHostMetricsToolInput=n.object({hostId:n.string().describe(`Host ID`),name:n.string().describe(`Metric name (e.g., loadavg5, cpu.user, memory.used, custom.myapp.*, ec2.cpu.used, etc.)`),from:n.number().describe(`The start of the time period you want metrics for (unix time)`),to:n.number().describe(`The end of the time period you want metrics for (unix time)`)});getHostMetrics=async({hostId:e,name:t,from:n,to:r})=>await d(async()=>await this.mackerelClient.getHostMetrics(e,t,n,r),`get_host_metrics`)};async function x(){let n=new v(`https://api.mackerelio.com`,S()),r=new f(n),i=new p(n),a=new m(n),o=new h(n),s=new b(n),c=new g(n),l=new y(n),u=new _(n),d=new e({name:`@mackerel/mcp-server`,version:`0.0.1`});d.registerTool(`list_alerts`,{title:`List Alerts`,description:`Retrieve alerts from Mackerel.
|
|
2
129
|
|
|
3
130
|
🔍 USE THIS TOOL WHEN USERS:
|
|
4
131
|
- Check currently active alerts
|
|
@@ -15,7 +142,7 @@ list_alerts()
|
|
|
15
142
|
list_alerts(withClosed=true)
|
|
16
143
|
\`\`\`
|
|
17
144
|
</examples>
|
|
18
|
-
`,inputSchema:
|
|
145
|
+
`,inputSchema:f.ListAlertsToolInput.shape},r.listAlerts),d.registerTool(`get_alert`,{title:`Get Alert`,description:`Retrieve a specific alert by ID from Mackerel.
|
|
19
146
|
|
|
20
147
|
🔍 USE THIS TOOL WHEN USERS:
|
|
21
148
|
- Investigate a particular alert
|
|
@@ -26,7 +153,7 @@ list_alerts(withClosed=true)
|
|
|
26
153
|
get_alert(alertId=3Yr)
|
|
27
154
|
\`\`\`
|
|
28
155
|
</example>
|
|
29
|
-
`,inputSchema:
|
|
156
|
+
`,inputSchema:f.GetAlertToolInput.shape},r.getAlert),d.registerTool(`get_alert_logs`,{title:`Get Alert Logs`,description:`Retrieve logs for a specific alert by ID from Mackerel.
|
|
30
157
|
|
|
31
158
|
🔍 USE THIS TOOL WHEN USERS:
|
|
32
159
|
- View status change history for a specific alert
|
|
@@ -38,7 +165,7 @@ get_alert(alertId=3Yr)
|
|
|
38
165
|
get_alert_logs(alertId=3Yr)
|
|
39
166
|
\`\`\`
|
|
40
167
|
</example>
|
|
41
|
-
`,inputSchema:
|
|
168
|
+
`,inputSchema:f.GetAlertLogsToolInput.shape},r.getAlertLogs),d.registerTool(`list_dashboards`,{title:`List Dashboards`,description:`Retrieve all dashboards from Mackerel.
|
|
42
169
|
|
|
43
170
|
🔍 USE THIS TOOL WHEN USERS:
|
|
44
171
|
- Get a list of dashboards
|
|
@@ -50,7 +177,7 @@ get_alert_logs(alertId=3Yr)
|
|
|
50
177
|
list_dashboards()
|
|
51
178
|
\`\`\`
|
|
52
179
|
</example>
|
|
53
|
-
`,inputSchema:
|
|
180
|
+
`,inputSchema:p.ListDashboardsToolInput.shape},i.listDashboards),d.registerTool(`get_dashboard`,{title:`Get Dashboard`,description:`Retrieve a specific dashboard by ID from Mackerel.
|
|
54
181
|
|
|
55
182
|
🔍 USE THIS TOOL WHEN USERS:
|
|
56
183
|
- Get details of a specific dashboard
|
|
@@ -62,7 +189,7 @@ list_dashboards()
|
|
|
62
189
|
get_dashboard(dashboardId="3Yr")
|
|
63
190
|
\`\`\`
|
|
64
191
|
</examples>
|
|
65
|
-
`,inputSchema:
|
|
192
|
+
`,inputSchema:p.GetDashboardToolInput.shape},i.getDashboard),d.registerTool(`update_dashboard`,{title:`Update Dashboard`,description:`Update a specific dashboard by ID in Mackerel.
|
|
66
193
|
|
|
67
194
|
🔍 USE THIS TOOL WHEN USERS:
|
|
68
195
|
- Modify dashboard title, memo, or URL path
|
|
@@ -85,7 +212,7 @@ update_dashboard(
|
|
|
85
212
|
)
|
|
86
213
|
\`\`\`
|
|
87
214
|
</examples>
|
|
88
|
-
`,inputSchema:
|
|
215
|
+
`,inputSchema:p.UpdateDashboardToolInput.shape},i.updateDashboard),d.registerTool(`list_hosts`,{title:`List Hosts`,description:`Retrieve hosts from Mackerel.
|
|
89
216
|
|
|
90
217
|
🔍 USE THIS TOOL WHEN USERS:
|
|
91
218
|
- Get a list of hosts
|
|
@@ -93,7 +220,7 @@ update_dashboard(
|
|
|
93
220
|
- Check host status and information
|
|
94
221
|
|
|
95
222
|
<examples>
|
|
96
|
-
### Get all hosts
|
|
223
|
+
### Get all hosts (first 20)
|
|
97
224
|
\`\`\`
|
|
98
225
|
list_hosts()
|
|
99
226
|
\`\`\`
|
|
@@ -103,24 +230,51 @@ list_hosts()
|
|
|
103
230
|
list_hosts(service="web",role=["app"])
|
|
104
231
|
\`\`\`
|
|
105
232
|
|
|
106
|
-
### Get hosts by status
|
|
233
|
+
### Get hosts by status with pagination
|
|
234
|
+
\`\`\`
|
|
235
|
+
list_hosts(status=["working","standby"], limit=10, offset=0)
|
|
236
|
+
\`\`\`
|
|
237
|
+
|
|
238
|
+
### Get hosts in summary format (reduced response size)
|
|
107
239
|
\`\`\`
|
|
108
|
-
list_hosts(
|
|
240
|
+
list_hosts(summary=true)
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
### Get next page of hosts
|
|
244
|
+
\`\`\`
|
|
245
|
+
list_hosts(limit=20, offset=20)
|
|
109
246
|
\`\`\`
|
|
110
247
|
</examples>
|
|
111
|
-
`,inputSchema:
|
|
248
|
+
`,inputSchema:h.ListHostsToolInput.shape},o.listHosts),d.registerTool(`get_host_metrics`,{title:`Get Host Metrics`,description:`Retrieve metrics data for a specific host from Mackerel.
|
|
112
249
|
|
|
113
250
|
🔍 USE THIS TOOL WHEN USERS:
|
|
114
251
|
- Get metrics data for a specific host
|
|
115
252
|
- Analyze host performance over time
|
|
116
253
|
|
|
254
|
+
📊 AVAILABLE METRIC NAMES:
|
|
255
|
+
- **Standard metrics (mackerel-agent)**: loadavg5, cpu.user, memory.used, disk.sda1.reads, network.eth0.rxBytes, etc.
|
|
256
|
+
- **Custom metrics**: custom.myapp.* (user-defined metrics)
|
|
257
|
+
- **AWS integration**: ec2.cpu.used, rds.database_connections.used, etc.
|
|
258
|
+
- **Azure integration**: azure.virtual_machine.cpu.percent, azure.sql_database.cpu.percent, etc.
|
|
259
|
+
- **GCP integration**: gce.instance.cpu.used, etc.
|
|
260
|
+
|
|
117
261
|
<examples>
|
|
118
|
-
### Get
|
|
262
|
+
### Get CPU load average for a host
|
|
119
263
|
\`\`\`
|
|
120
264
|
get_host_metrics(hostId="host123", name="loadavg5", from=1609459200, to=1609462800)
|
|
121
265
|
\`\`\`
|
|
266
|
+
|
|
267
|
+
### Get custom metric
|
|
268
|
+
\`\`\`
|
|
269
|
+
get_host_metrics(hostId="host123", name="custom.myapp.response_time", from=1609459200, to=1609462800)
|
|
270
|
+
\`\`\`
|
|
271
|
+
|
|
272
|
+
### Get AWS EC2 CPU utilization
|
|
273
|
+
\`\`\`
|
|
274
|
+
get_host_metrics(hostId="host123", name="ec2.cpu.used", from=1609459200, to=1609462800)
|
|
275
|
+
\`\`\`
|
|
122
276
|
</examples>
|
|
123
|
-
`,inputSchema:
|
|
277
|
+
`,inputSchema:b.GetHostMetricsToolInput.shape},s.getHostMetrics),d.registerTool(`list_services`,{title:`List Services`,description:`Retrieve all services from Mackerel.
|
|
124
278
|
|
|
125
279
|
🔍 USE THIS TOOL WHEN USERS:
|
|
126
280
|
- Get a list of services
|
|
@@ -132,18 +286,31 @@ get_host_metrics(hostId="host123", name="loadavg5", from=1609459200, to=16094628
|
|
|
132
286
|
list_services()
|
|
133
287
|
\`\`\`
|
|
134
288
|
</examples>
|
|
135
|
-
`,inputSchema:
|
|
289
|
+
`,inputSchema:g.ListServicesToolInput.shape},c.listServices),d.registerTool(`get_service_metrics`,{title:`Get Service Metrics`,description:`Retrieve metrics data for a specific service from Mackerel.
|
|
136
290
|
|
|
137
291
|
🔍 USE THIS TOOL WHEN USERS:
|
|
138
|
-
-
|
|
292
|
+
- "Service metrics" are metrics that correspond to a service that consists of multiple hosts and their collective roles
|
|
293
|
+
- The following can be visualized and monitored.
|
|
294
|
+
- The total number of registered users in a service
|
|
295
|
+
- The number of PVs for a website
|
|
296
|
+
- Business related KPIs such as sales or the number of orders received from EC sites
|
|
297
|
+
|
|
298
|
+
📊 AVAILABLE METRIC NAMES:
|
|
299
|
+
- **Custom metrics**: http.response_time, sales.count, analytics.page_view, etc.
|
|
300
|
+
|
|
139
301
|
|
|
140
302
|
<examples>
|
|
141
|
-
### Get service
|
|
303
|
+
### Get service response time
|
|
142
304
|
\`\`\`
|
|
143
|
-
get_service_metrics(serviceName="web", name="
|
|
305
|
+
get_service_metrics(serviceName="web", name="__externalhttp.responsetime.<monitorId>", from=1609459200, to=1609462800)
|
|
144
306
|
\`\`\`
|
|
145
|
-
|
|
146
|
-
|
|
307
|
+
|
|
308
|
+
### Get service page views
|
|
309
|
+
\`\`\`
|
|
310
|
+
get_service_metrics(serviceName="web", name="analytics.page_view", from=1609459200, to=1609462800)
|
|
311
|
+
\`\`\`
|
|
312
|
+
|
|
313
|
+
</examples>`,inputSchema:y.GetServiceMetricsToolInput.shape},l.getServiceMetrics),d.registerTool(`list_monitors`,{title:`List Monitors`,description:`Retrieve all monitor configurations from Mackerel.
|
|
147
314
|
|
|
148
315
|
🔍 USE THIS TOOL WHEN USERS:
|
|
149
316
|
- Get a list of all monitors
|
|
@@ -155,7 +322,7 @@ get_service_metrics(serviceName="web", name="response_time", from=1609459200, to
|
|
|
155
322
|
list_monitors()
|
|
156
323
|
\`\`\`
|
|
157
324
|
</examples>
|
|
158
|
-
`,inputSchema:
|
|
325
|
+
`,inputSchema:m.ListMonitorsToolInput.shape},a.listMonitors),d.registerTool(`get_monitor`,{title:`Get Monitor`,description:`Retrieve a specific monitor configuration by ID from Mackerel.
|
|
159
326
|
|
|
160
327
|
🔍 USE THIS TOOL WHEN USERS:
|
|
161
328
|
- Get details of a specific monitor
|
|
@@ -166,4 +333,50 @@ list_monitors()
|
|
|
166
333
|
get_monitor(monitorId="2cSZzK3XfmB")
|
|
167
334
|
\`\`\`
|
|
168
335
|
</examples>
|
|
169
|
-
`,inputSchema:
|
|
336
|
+
`,inputSchema:m.GetMonitorToolInput.shape},a.getMonitor),d.registerTool(`get_trace`,{title:`Get Trace`,description:`Retrieve trace data by trace ID from Mackerel for distributed tracing analysis.
|
|
337
|
+
|
|
338
|
+
🔍 USE THIS TOOL WHEN USERS:
|
|
339
|
+
- Analyze performance bottlenecks in distributed systems
|
|
340
|
+
- Investigate error propagation across microservices
|
|
341
|
+
- Understand request flow and service dependencies
|
|
342
|
+
- Debug latency issues and identify slow operations
|
|
343
|
+
- Generate documentation of system architecture from trace data
|
|
344
|
+
|
|
345
|
+
<examples>
|
|
346
|
+
### Basic trace retrieval (first page)
|
|
347
|
+
\`\`\`
|
|
348
|
+
get_trace(traceId="abc123def456")
|
|
349
|
+
\`\`\`
|
|
350
|
+
|
|
351
|
+
### Focus on errors only
|
|
352
|
+
\`\`\`
|
|
353
|
+
get_trace(traceId="abc123def456", errorSpansOnly=true)
|
|
354
|
+
\`\`\`
|
|
355
|
+
|
|
356
|
+
### Filter spans with duration over 100ms
|
|
357
|
+
\`\`\`
|
|
358
|
+
get_trace(traceId="abc123def456", duration=100)
|
|
359
|
+
\`\`\`
|
|
360
|
+
|
|
361
|
+
### Detailed analysis with attributes
|
|
362
|
+
\`\`\`
|
|
363
|
+
get_trace(traceId="abc123def456", includeAttributes=true, limit=50)
|
|
364
|
+
\`\`\`
|
|
365
|
+
|
|
366
|
+
### Minimal view for overview
|
|
367
|
+
\`\`\`
|
|
368
|
+
get_trace(traceId="abc123def456", includeEvents=false, limit=10)
|
|
369
|
+
\`\`\`
|
|
370
|
+
|
|
371
|
+
### Pagination through large traces
|
|
372
|
+
\`\`\`
|
|
373
|
+
get_trace(traceId="abc123def456", limit=20, offset=0) # First page
|
|
374
|
+
get_trace(traceId="abc123def456", limit=20, offset=20) # Second page
|
|
375
|
+
\`\`\`
|
|
376
|
+
|
|
377
|
+
### Combined filtering and pagination
|
|
378
|
+
\`\`\`
|
|
379
|
+
get_trace(traceId="abc123def456", errorSpansOnly=true, limit=10, offset=0)
|
|
380
|
+
\`\`\`
|
|
381
|
+
</examples>
|
|
382
|
+
`,inputSchema:_.GetTraceToolInput.shape},u.getTrace);let x=new t;await d.connect(x),console.error(`Mackerel MCP Server running on stdio`)}function S(){let e=process.env.MACKEREL_APIKEY;if(!e)throw Error(`MACKEREL_APIKEY environment variable is not set.`);return e}x().catch(e=>{console.error(`Fatal error in main():`,e),process.exit(1)});export{};
|
package/package.json
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mackerel/mcp-server",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"description": "A Model Context Protocol server for interacting with Mackerel",
|
|
8
8
|
"main": "build/index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"mcp-server": "build/index.js"
|
|
11
|
+
},
|
|
9
12
|
"type": "module",
|
|
10
13
|
"scripts": {
|
|
11
14
|
"build": "tsdown",
|
|
12
15
|
"dev": "tsx src/index.ts",
|
|
13
|
-
"inspector": "npx @modelcontextprotocol/inspector -e
|
|
16
|
+
"inspector": "npx @modelcontextprotocol/inspector -e MACKEREL_APIKEY=$MACKEREL_APIKEY tsx src/index.ts",
|
|
14
17
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
15
18
|
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
|
16
19
|
"test": "vitest run"
|
|
@@ -22,6 +25,10 @@
|
|
|
22
25
|
"LICENSE"
|
|
23
26
|
],
|
|
24
27
|
"types": "build/index.d.ts",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/mackerelio-labs/mcp-server.git"
|
|
31
|
+
},
|
|
25
32
|
"bugs": {
|
|
26
33
|
"url": "https://github.com/mackerelio-labs/mcp-server/issues"
|
|
27
34
|
},
|