Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/do-release-mcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Release MCP Server

on:
workflow_dispatch:
inputs:
version:
description: "Semver type of new version (major / minor / patch)"
required: true
type: choice
options:
- patch
- minor
- major

jobs:
release-mcp:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write

steps:
- id: get-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@a37de51f3d713a30a9e4b21bcdfbd38170020593 # v1.3.0
with:
repo_secrets: |
GITHUB_APP_ID=plugins-platform-bot-app:app_id
GITHUB_APP_PRIVATE_KEY=plugins-platform-bot-app:app_pem
export_env: false

- name: Generate token
id: generate_token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ fromJSON(steps.get-secrets.outputs.secrets).GITHUB_APP_ID }}
private-key: ${{ fromJSON(steps.get-secrets.outputs.secrets).GITHUB_APP_PRIVATE_KEY }}
permission-contents: write

- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ steps.generate_token.outputs.token }}
persist-credentials: true

- name: Setup Git
run: |
git config user.name 'grafana-plugins-platform-bot[bot]'
git config user.email '144369747+grafana-plugins-platform-bot[bot]@users.noreply.github.com'

- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "24"

- name: Bump MCP version and create tag
run: |
cd mcp-package
npm version ${INPUT_VERSION} --no-git-tag-version
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--no-git-tag-version so it does not auto commit and tag 0.0.1. We need to mcp/v prefix.

NEW_VERSION=$(jq -r .version package.json)
cd ..

git add mcp-package/package.json
git commit -m "chore(mcp): release v${NEW_VERSION}"
git tag "mcp/v${NEW_VERSION}"
Copy link
Contributor Author

@s4kh s4kh Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We manually tag with mcp/ prefix so it does not conflict with the validator's tags.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env:
INPUT_VERSION: ${{ github.event.inputs.version }}

- name: Push changes and tag
run: |
git push origin main
git push origin --tags
101 changes: 101 additions & 0 deletions .github/workflows/release-mcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Create MCP release and publish to github, npm and docker hub
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first tried with modifying the release.yml by accepting package: mcp|validator but needed to add if check for each of the jobs depending on the tag prefix.


on: # zizmor: ignore[cache-poisoning]
push:
tags:
- 'mcp/v[0-9]*'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only triggered for mcp tag pushes.


jobs:
release-mcp-to-github:
runs-on: ubuntu-arm64
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false

- run: git fetch --force --tags
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version-file: go.mod
check-latest: true

- id: get-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@a37de51f3d713a30a9e4b21bcdfbd38170020593 # v1.3.0
with:
repo_secrets: |
GITHUB_APP_ID=plugins-platform-bot-app:app_id
GITHUB_APP_PRIVATE_KEY=plugins-platform-bot-app:app_pem
export_env: false

- name: Generate token
id: generate_token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ fromJSON(steps.get-secrets.outputs.secrets).GITHUB_APP_ID }}
private-key: ${{ fromJSON(steps.get-secrets.outputs.secrets).GITHUB_APP_PRIVATE_KEY }}
permission-contents: write

- name: Extract MCP version
run: echo "MCP_VERSION=${GITHUB_REF_NAME#mcp/v}" >> $GITHUB_ENV

- uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
distribution: goreleaser
version: latest
args: release --clean --config .goreleaser.mcp.yaml --skip=validate
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--skip=validate is added for bypassing the mcp/v* git tag semver validation for goreleaser.

env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
GORELEASER_CURRENT_TAG: ${{ github.ref_name }}
MCP_VERSION: ${{ env.MCP_VERSION }}

release-mcp-to-npm:
runs-on: ubuntu-latest
needs: release-mcp-to-github
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- run: cd mcp-package && npm install
- run: cd mcp-package && npm publish

release-mcp-to-dockerhub:
runs-on: ubuntu-x64
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- name: Get version from package.json
id: get_version
run: |
echo "version=$(jq -r .version mcp-package/package.json)" >> "$GITHUB_OUTPUT"

- id: push-mcp-to-dockerhub
uses: grafana/shared-workflows/actions/build-push-to-dockerhub@f02d5da7ddff4ea32bbe5034c7c70e90d2b9622c # build-push-to-dockerhub/v0.4.1
with:
repository: grafana/plugin-validator-mcp
context: .
file: mcp-package/Dockerfile
build-args: |
MCP_VERSION=${{ steps.get_version.outputs.version }}
tags: |-
"v${{ steps.get_version.outputs.version }}"
"latest"
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Create release and publish to github, npm and docker hub
on: # zizmor: ignore[cache-poisoning]
push:
tags:
- "*"
- 'v[0-9]*'
Copy link
Contributor Author

@s4kh s4kh Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only triggered on validator's version tag pushes.


jobs:
release-to-github:
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ on:
- renovate/*

jobs:
test-mcp-server:
runs-on: ubuntu-x64
permissions:
contents: read
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Run MCP server tests
run: go test -v ./pkg/cmd/mcpserver/...

test-docker-build:
runs-on: ubuntu-x64
permissions:
Expand Down
37 changes: 37 additions & 0 deletions .goreleaser.mcp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# Separate goreleaser config for the MCP server.
# Triggered by mcp/v* tags independently of the main plugin-validator releases.
# MCP_VERSION env var must be set to the bare semver (e.g. "0.2.0") by the workflow.
version: 2

project_name: plugin-validator-mcp

before:
hooks:
- go mod tidy

builds:
- id: mcpserver
main: ./pkg/cmd/mcpserver
binary: plugin-validator-mcp
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X main.version={{ .Env.MCP_VERSION }}

archives:
- name_template: "plugin-validator-mcp_{{ .Env.MCP_VERSION }}_{{ .Os }}_{{ .Arch }}"
formats: [tar.gz]

checksum:
name_template: "checksums.txt"

changelog:
disable: true
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ Then you can run the utility:
plugincheck2 -sourceCodeUri [source_code_location/] [plugin_archive.zip]
```

### MCP Server (for AI assistants)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider this will be what we ask people to do to install our MCP server the instructions are far off.

Most people that want to install an mcp server expect instructions to tell them something like:

modify your mcp.json file and add

{
 "mcpServers": {
    "grafana-plugin-validator": {
      "command": "npx",
      "args": ["-y", "@grafana/plugin-validator-mcp"]
    }
  }
}


The plugin validator can be used as an MCP (Model Context Protocol) server, allowing AI assistants like Claude, Cline, and other MCP-compatible tools to validate Grafana plugins.

See the [MCP Server README](mcp-package/README.md) for configuration instructions.

### Generating local files For validation

You must create a `.zip` archive containing the `dist/` directory but named as your plugin ID:
Expand Down Expand Up @@ -186,7 +192,6 @@ analyzers:
- my-plugin-id
```


### Source code

You can specify the location of the plugin source code to the validator with the `-sourceCodeUri` option. Doing so allows for additional [analyzers](#analyzers) to be run and for a more complete scan.
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/hashicorp/go-version v1.8.0
github.com/jarcoal/httpmock v1.4.1
github.com/magefile/mage v1.15.0
github.com/modelcontextprotocol/go-sdk v1.3.0
github.com/ossf/osv-schema/bindings/go v0.0.0-20251230224438-88c48750ddae
github.com/r3labs/diff/v3 v3.0.2
github.com/smartystreets/goconvey v1.8.1
Expand Down Expand Up @@ -123,6 +124,7 @@ require (
github.com/google/generative-ai-go v0.15.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.20.6 // indirect
github.com/google/jsonschema-go v0.4.2 // indirect
github.com/google/osv-scalibr v0.4.1-0.20251202121049-5e7e15f4a036 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down Expand Up @@ -194,6 +196,7 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.etcd.io/bbolt v1.4.2 // indirect
go.opencensus.io v0.24.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gohugoio/hashstructure v0.5.0 h1:G2fjSBU36RdwEJBWJ+919ERvOVqAg9tfcYp47K9swqg=
github.com/gohugoio/hashstructure v0.5.0/go.mod h1:Ser0TniXuu/eauYmrwM4o64EBvySxNzITEOLlm4igec=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
Expand Down Expand Up @@ -262,6 +264,8 @@ github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB
github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932 h1:5/4TSDzpDnHQ8rKEEQBjRlYx77mHOvXu08oGchxej7o=
github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932/go.mod h1:cC6EdPbj/17GFCPDK39NRarlMI+kt+O60S12cNB5J9Y=
github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8=
github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/osv-scalibr v0.4.1-0.20251202121049-5e7e15f4a036 h1:a+w+8ZQYYybXPWI1yJD+mXri5fMLcThlP41rIB7XNns=
github.com/google/osv-scalibr v0.4.1-0.20251202121049-5e7e15f4a036/go.mod h1:9Ze2W6nQmu1WX2s95ezOAVZhPDbcA6ZGuEHgFT/sQEU=
github.com/google/osv-scanner/v2 v2.3.1 h1:97NVCr8QNdS9deD8zxB0cIPI7vmcqAm8YJhclnXETu8=
Expand Down Expand Up @@ -354,6 +358,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modelcontextprotocol/go-sdk v1.3.0 h1:gMfZkv3DzQF5q/DcQePo5rahEY+sguyPfXDfNBcT0Zs=
github.com/modelcontextprotocol/go-sdk v1.3.0/go.mod h1:AnQ//Qc6+4nIyyrB4cxBU7UW9VibK4iOZBeyP/rF1IE=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/montanaflynn/stats v0.6.3/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
Expand Down Expand Up @@ -510,6 +516,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
22 changes: 22 additions & 0 deletions mcp-package/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM golang:1.25-alpine3.22@sha256:fa3380ab0d73b706e6b07d2a306a4dc68f20bfc1437a6a6c47c8f88fe4af6f75 AS builder

ARG MCP_VERSION=dev

WORKDIR /build
COPY pkg/cmd/mcpserver ./pkg/cmd/mcpserver
COPY go.mod go.sum ./

RUN apk add --no-cache git ca-certificates && \
update-ca-certificates && \
CGO_ENABLED=0 GO111MODULE=on go build -ldflags "-s -w -X main.version=${MCP_VERSION}" -o plugin-validator-mcp ./pkg/cmd/mcpserver

FROM alpine:3.22@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412

RUN apk add --no-cache ca-certificates docker-cli nodejs npm && \
update-ca-certificates

WORKDIR /app
COPY --from=builder /build/plugin-validator-mcp /app/plugin-validator-mcp

# MCP servers communicate over stdin/stdout
ENTRYPOINT ["/app/plugin-validator-mcp"]
Loading
Loading