@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.
Files changed (3) hide show
  1. package/README.md +6 -5
  2. package/build/index.js +234 -21
  3. 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
- "MACKEREL_API_KEY",
22
- "-----TBD_IMAGE_NAME"
21
+ "MACKEREL_APIKEY",
22
+ "ghcr.io/mackerelio-labs/mcp-server:latest"
23
23
  ],
24
24
  "env": {
25
- "MACKEREL_API_KEY": "${MACKEREL_API_KEY}"
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
- "-----TBD_PACKAGE_NAME"
41
+ "@mackerel/mcp-server"
42
42
  ],
43
43
  "env": {
44
- "MACKEREL_API_KEY": "${MACKEREL_API_KEY}"
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:i.ListAlertsToolInput.shape},r.listAlerts),y.registerTool(`get_alert`,{title:`Get Alert`,description:`Retrieve a specific alert by ID from Mackerel.
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:i.GetAlertToolInput.shape},r.getAlert),y.registerTool(`get_alert_logs`,{title:`Get Alert Logs`,description:`Retrieve logs for a specific alert by ID from Mackerel.
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:i.GetAlertLogsToolInput.shape},r.getAlertLogs),y.registerTool(`list_dashboards`,{title:`List Dashboards`,description:`Retrieve all dashboards from Mackerel.
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:a.ListDashboardsToolInput.shape},f.listDashboards),y.registerTool(`get_dashboard`,{title:`Get Dashboard`,description:`Retrieve a specific dashboard by ID from Mackerel.
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:a.GetDashboardToolInput.shape},f.getDashboard),y.registerTool(`update_dashboard`,{title:`Update Dashboard`,description:`Update a specific dashboard by ID in Mackerel.
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:a.UpdateDashboardToolInput.shape},f.updateDashboard),y.registerTool(`list_hosts`,{title:`List Hosts`,description:`Retrieve hosts from Mackerel.
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(status=["working","standby"])
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:s.ListHostsToolInput.shape},h.listHosts),y.registerTool(`get_host_metrics`,{title:`Get Host Metrics`,description:`Retrieve metrics data for a specific host from Mackerel.
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 all metrics for a host
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:d.GetHostMetricsToolInput.shape},g.getHostMetrics),y.registerTool(`list_services`,{title:`List Services`,description:`Retrieve all services from Mackerel.
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:c.ListServicesToolInput.shape},_.listServices),y.registerTool(`get_service_metrics`,{title:`Get Service Metrics`,description:`Retrieve metrics data for a specific service from Mackerel.
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
- - Get metrics data for a specific service
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 metrics
303
+ ### Get service response time
142
304
  \`\`\`
143
- get_service_metrics(serviceName="web", name="response_time", from=1609459200, to=1609462800)
305
+ get_service_metrics(serviceName="web", name="__externalhttp.responsetime.<monitorId>", from=1609459200, to=1609462800)
144
306
  \`\`\`
145
- </examples>
146
- `,inputSchema:u.GetServiceMetricsToolInput.shape},v.getServiceMetrics),y.registerTool(`list_monitors`,{title:`List Monitors`,description:`Retrieve all monitor configurations from Mackerel.
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:o.ListMonitorsToolInput.shape},m.listMonitors),y.registerTool(`get_monitor`,{title:`Get Monitor`,description:`Retrieve a specific monitor configuration by ID from Mackerel.
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:o.GetMonitorToolInput.shape},m.getMonitor);let b=new t;await y.connect(b),console.error(`Mackerel MCP Server running on stdio`)}function p(){let e=process.env.MACKEREL_API_KEY;if(!e)throw Error(`MACKEREL_API_KEY environment variable is not set.`);return e}f().catch(e=>{console.error(`Fatal error in main():`,e),process.exit(1)});export{};
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.1",
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 MACKEREL_API_KEY=$MACKEREL_API_KEY tsx src/index.ts",
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
  },