<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Developer on Grafana Labs</title><link>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/</link><description>Recent content in Developer on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/grafana/v13.0/developer-resources/mcp/developer/index.xml" rel="self" type="application/rss+xml"/><item><title>Go SDK (programmatic use)</title><link>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/go-sdk/</link><pubDate>Thu, 23 Apr 2026 10:03:11 +0200</pubDate><guid>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/go-sdk/</guid><content><![CDATA[&lt;h1 id=&#34;go-sdk-programmatic-use&#34;&gt;Go SDK (programmatic use)&lt;/h1&gt;
&lt;p&gt;You can use the Grafana MCP server as a Go library to build custom MCP server contexts, for example with custom TLS or debug settings. The package is available on &lt;a href=&#34;https://pkg.go.dev/github.com/grafana/mcp-grafana&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;pkg.go.dev&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;what-youll-achieve&#34;&gt;What you&amp;rsquo;ll achieve&lt;/h2&gt;
&lt;p&gt;You integrate the server into your own Go program, using &lt;code&gt;ComposedStdioContextFunc&lt;/code&gt; and &lt;code&gt;GrafanaConfig&lt;/code&gt; (and optionally &lt;code&gt;TLSConfig&lt;/code&gt;) so the server runs with your chosen configuration.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A Go toolchain and the module in your project: &lt;code&gt;go get github.com/grafana/mcp-grafana&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;compose-a-stdio-context-with-config&#34;&gt;Compose a stdio context with config&lt;/h2&gt;
&lt;p&gt;Create a &lt;code&gt;GrafanaConfig&lt;/code&gt; with your Grafana URL, credentials (or token), and options such as &lt;code&gt;Debug&lt;/code&gt;. For TLS to Grafana, set &lt;code&gt;TLSConfig&lt;/code&gt; with &lt;code&gt;CertFile&lt;/code&gt;, &lt;code&gt;KeyFile&lt;/code&gt;, and &lt;code&gt;CAFile&lt;/code&gt;. Then build the context function with &lt;code&gt;mcpgrafana.ComposedStdioContextFunc(grafanaConfig)&lt;/code&gt; and pass it to your MCP server setup so the server uses this context when handling requests.&lt;/p&gt;
&lt;p&gt;Example (structure only):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Go&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-go&#34;&gt;grafanaConfig := mcpgrafana.GrafanaConfig{
    Debug: true,
    TLSConfig: &amp;amp;mcpgrafana.TLSConfig{
        CertFile: &amp;#34;/path/to/client.crt&amp;#34;,
        KeyFile:  &amp;#34;/path/to/client.key&amp;#34;,
        CAFile:   &amp;#34;/path/to/ca.crt&amp;#34;,
    },
}
contextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Refer to the &lt;a href=&#34;https://pkg.go.dev/github.com/grafana/mcp-grafana&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;package documentation&lt;/a&gt; for the exact types and constructors.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../observability-metrics-and-tracing/&#34;&gt;Observability (metrics and tracing)&lt;/a&gt; for Prometheus and OTLP.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../../configure/client-tls-grafana-connection/&#34;&gt;Client TLS (Grafana connection)&lt;/a&gt; for TLS flag reference.&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="go-sdk-programmatic-use">Go SDK (programmatic use)&lt;/h1>
&lt;p>You can use the Grafana MCP server as a Go library to build custom MCP server contexts, for example with custom TLS or debug settings. The package is available on &lt;a href="https://pkg.go.dev/github.com/grafana/mcp-grafana" target="_blank" rel="noopener noreferrer">pkg.go.dev&lt;/a>.&lt;/p></description></item><item><title>Observability (metrics and tracing)</title><link>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/observability-metrics-and-tracing/</link><pubDate>Thu, 23 Apr 2026 10:03:11 +0200</pubDate><guid>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/observability-metrics-and-tracing/</guid><content><![CDATA[&lt;h1 id=&#34;observability-metrics-and-tracing&#34;&gt;Observability (metrics and tracing)&lt;/h1&gt;
&lt;p&gt;The MCP server can expose &lt;strong&gt;Prometheus metrics&lt;/strong&gt; and supports &lt;strong&gt;&lt;a href=&#34;https://opentelemetry.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;OpenTelemetry&lt;/a&gt;&lt;/strong&gt; distributed tracing, following the &lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;OTel MCP semantic conventions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Metrics require the &lt;strong&gt;SSE&lt;/strong&gt; or &lt;strong&gt;streamable-http&lt;/strong&gt; transport. Tracing uses standard &lt;code&gt;OTEL_*&lt;/code&gt; environment variables and works independently of &lt;code&gt;--metrics&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;what-youll-achieve&#34;&gt;What you&amp;rsquo;ll achieve&lt;/h2&gt;
&lt;p&gt;You can scrape MCP operation metrics or export traces to Tempo or Grafana Cloud while the server runs over HTTP transports.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The server running with &lt;strong&gt;SSE&lt;/strong&gt; or &lt;strong&gt;streamable-http&lt;/strong&gt; (metrics are not available with stdio).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;enable-prometheus-metrics&#34;&gt;Enable Prometheus metrics&lt;/h2&gt;
&lt;p&gt;When using SSE or streamable HTTP transports, enable Prometheus metrics with &lt;code&gt;--metrics&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# Metrics on the main server at /metrics
./mcp-grafana -t streamable-http --metrics&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# Metrics on a separate listen address
./mcp-grafana -t streamable-http --metrics --metrics-address :9090&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Available metrics:&lt;/strong&gt;&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Metric&lt;/th&gt;
              &lt;th&gt;Type&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;mcp_server_operation_duration_seconds&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Histogram&lt;/td&gt;
              &lt;td&gt;MCP operation duration (labels: &lt;code&gt;mcp_method_name&lt;/code&gt;, &lt;code&gt;gen_ai_tool_name&lt;/code&gt;, &lt;code&gt;error_type&lt;/code&gt;, &lt;code&gt;network_transport&lt;/code&gt;, &lt;code&gt;mcp_protocol_version&lt;/code&gt;)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;mcp_server_session_duration_seconds&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Histogram&lt;/td&gt;
              &lt;td&gt;MCP client session duration (labels: &lt;code&gt;network_transport&lt;/code&gt;, &lt;code&gt;mcp_protocol_version&lt;/code&gt;)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;http_server_request_duration_seconds&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Histogram&lt;/td&gt;
              &lt;td&gt;HTTP server request duration (from otelhttp)&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Metrics are only available when using SSE or streamable HTTP transports. They are &lt;strong&gt;not&lt;/strong&gt; available with stdio transport.&lt;/p&gt;
&lt;h2 id=&#34;enable-opentelemetry-tracing&#34;&gt;Enable OpenTelemetry tracing&lt;/h2&gt;
&lt;p&gt;When &lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt; is set, the server exports traces via OTLP/gRPC.&lt;/p&gt;
&lt;p&gt;Local example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# Send traces to a local Tempo instance
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_EXPORTER_OTLP_INSECURE=true \
./mcp-grafana -t streamable-http&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Grafana Cloud example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# Send traces to Grafana Cloud with authentication
OTEL_EXPORTER_OTLP_ENDPOINT=https://tempo-us-central1.grafana.net:443 \
OTEL_EXPORTER_OTLP_HEADERS=&amp;#34;Authorization=Basic ...&amp;#34; \
./mcp-grafana -t streamable-http&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Tool call spans follow naming like &lt;code&gt;tools/call &amp;lt;tool_name&amp;gt;&lt;/code&gt; and include attributes such as &lt;code&gt;gen_ai.tool.name&lt;/code&gt;, &lt;code&gt;mcp.method.name&lt;/code&gt;, and &lt;code&gt;mcp.session.id&lt;/code&gt;. The server supports W3C trace context propagation from the &lt;code&gt;_meta&lt;/code&gt; field of tool call requests.&lt;/p&gt;
&lt;h2 id=&#34;run-with-docker-metrics-and-tracing&#34;&gt;Run with Docker (metrics and tracing)&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;docker run --rm -p 8000:8000 \
  -e GRAFANA_URL=http://localhost:3000 \
  -e GRAFANA_SERVICE_ACCOUNT_TOKEN=&amp;lt;your token&amp;gt; \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4317 \
  -e OTEL_EXPORTER_OTLP_INSECURE=true \
  grafana/mcp-grafana \
  -t streamable-http --metrics&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../build-and-test/&#34;&gt;Build, test, and lint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../../configure/transports-and-addresses/&#34;&gt;Transports and addresses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../../configure/command-line-flags/&#34;&gt;Command-line flags&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="observability-metrics-and-tracing">Observability (metrics and tracing)&lt;/h1>
&lt;p>The MCP server can expose &lt;strong>Prometheus metrics&lt;/strong> and supports &lt;strong>&lt;a href="https://opentelemetry.io/" target="_blank" rel="noopener noreferrer">OpenTelemetry&lt;/a>&lt;/strong> distributed tracing, following the &lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/" target="_blank" rel="noopener noreferrer">OTel MCP semantic conventions&lt;/a>.&lt;/p>
&lt;p>Metrics require the &lt;strong>SSE&lt;/strong> or &lt;strong>streamable-http&lt;/strong> transport. Tracing uses standard &lt;code>OTEL_*&lt;/code> environment variables and works independently of &lt;code>--metrics&lt;/code>.&lt;/p></description></item><item><title>Build, test, and lint</title><link>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/build-and-test/</link><pubDate>Thu, 23 Apr 2026 10:03:11 +0200</pubDate><guid>https://grafana.com/docs/grafana/v13.0/developer-resources/mcp/developer/build-and-test/</guid><content><![CDATA[&lt;h1 id=&#34;build-test-and-lint&#34;&gt;Build, test, and lint&lt;/h1&gt;
&lt;p&gt;Contributions are welcome. Open an issue or pull request on &lt;a href=&#34;https://github.com/grafana/mcp-grafana&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;GitHub&lt;/a&gt;. This project is written in Go.&lt;/p&gt;
&lt;h2 id=&#34;what-youll-achieve&#34;&gt;What you&amp;rsquo;ll achieve&lt;/h2&gt;
&lt;p&gt;You can run the server from source, execute the test suites, and run linters locally.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/doc/install&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go&lt;/a&gt; installed for your platform.&lt;/li&gt;
&lt;li&gt;Optional: Docker for integration tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;run-the-server-locally&#34;&gt;Run the server locally&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;STDIO&lt;/strong&gt; (default for local development):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make run&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;SSE:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;go run ./cmd/mcp-grafana --transport sse&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;build-and-run-the-docker-image&#34;&gt;Build and run the Docker image&lt;/h2&gt;
&lt;p&gt;Build the image:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make build-image&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run in SSE mode (image default):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;docker run -it --rm -p 8000:8000 mcp-grafana:latest&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run in stdio mode:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;docker run -it --rm mcp-grafana:latest -t stdio&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;run-tests&#34;&gt;Run tests&lt;/h2&gt;
&lt;p&gt;There are three types of tests available: unit tests, integration tests, and cloud tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unit tests&lt;/strong&gt; (no external dependencies required):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make test-unit&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also run:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make test&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Integration tests&lt;/strong&gt; (requires Docker containers):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make test-integration&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Cloud tests&lt;/strong&gt; (requires Grafana Cloud instance and credentials):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make test-cloud&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Cloud tests are automatically configured in CI. For local development, you&amp;rsquo;ll need to set up your own Grafana Cloud instance and credentials.&lt;/p&gt;
&lt;p&gt;For the full integration suite, start the supporting services first (Grafana and its dependencies on port 3000):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make run-test-services
make test-integration&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you add tools, add integration tests; existing tests are a good template.&lt;/p&gt;
&lt;h2 id=&#34;run-linters&#34;&gt;Run linters&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make lint&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The repository includes a custom linter for unescaped commas in &lt;code&gt;jsonschema&lt;/code&gt; struct tags (&lt;code&gt;description&lt;/code&gt; fields must be escaped with &lt;code&gt;\\,&lt;/code&gt; to avoid truncation). Run only that linter:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;make lint-jsonschema&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Refer to the &lt;a href=&#34;https://github.com/grafana/mcp-grafana/blob/main/internal/linter/jsonschema/README.md&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;JSONSchema linter README&lt;/a&gt; in the repository.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../go-sdk/&#34;&gt;Go SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../observability-metrics-and-tracing/&#34;&gt;Observability (metrics and tracing)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="build-test-and-lint">Build, test, and lint&lt;/h1>
&lt;p>Contributions are welcome. Open an issue or pull request on &lt;a href="https://github.com/grafana/mcp-grafana" target="_blank" rel="noopener noreferrer">GitHub&lt;/a>. This project is written in Go.&lt;/p>
&lt;h2 id="what-youll-achieve">What you&amp;rsquo;ll achieve&lt;/h2>
&lt;p>You can run the server from source, execute the test suites, and run linters locally.&lt;/p></description></item></channel></rss>