grafana-unified-mcp
grafana-unified-mcp
여러 Grafana 인스턴스를 하나의 MCP 서버로 통합합니다. 표준 Grafana MCP 서버의 모든 도구에 추가로 instance라는 인수가 제공되어, 어떤 Grafana에 대해 실행할지 지정합니다.
query_prometheus(instance="appstate", expr="up", datasourceUid="...")
search_dashboards(instance="uoregon", query="login latency")존재 이유
상위 프로젝트 grafana/mcp-grafana는 GRAFANA_URL을 프로세스 시작 시 한 번만 바인딩합니다. 요청별로 X-Grafana-Service-Account-Token은 읽지만, URL은 고정되어 있으며—이전에 이를 재정의하던 헤더는 이제 명시적으로 무효화되었습니다. 상위 프로젝트의 validate_url.go에 따르면:
Deprecated: X-Grafana-URL no longer configures the Grafana client. This middleware is retained temporarily to preserve malformed-header handling.
따라서 하나의 mcp-grafana 프로세스는 오직 하나의 Grafana만 통신할 수 있습니다. Grafana가 10개라면 서버 10개, 각 클라이언트 설정에 10개의 항목, 그리고 모델이 식별해야 하는 동일한 이름의 도구 세트 10개가 필요합니다.
이 서버는 인스턴스별로 하나의 상위 프로세스를 실행하고 instance 인수를 기반으로 각 호출을 올바른 프로세스로 라우팅하여 이 문제를 해결합니다. 도구는 실제 바이너리에서 런타임에 검색되므로, 상위 프로젝트가 제공하는 모든 도구(현재 65개)가 코드에서 별도로 작성될 필요 없이 제공되며, 상위 프로젝트가 추가할 때 업데이트할 필요가 없습니다.
작동 방식
┌──────────────────────────────────┐
Claude Code / routines / │ grafana-unified-mcp │
cloud sessions │ │
│ │ ┌────────────────────────────┐ │
│ streamable-HTTP │ │ bearer auth │ │
│ Authorization: Bearer … │ │ → Principal(instances, │ │
├──────────────────────────────►│ │ read-only|read-write) │ │
│ │ └────────────┬───────────────┘ │
│ │ │ │
│ │ ┌────────────▼───────────────┐ │
│ │ │ catalog: inject `instance` │ │
│ │ │ filter by caller's grant │ │
│ │ └────────────┬───────────────┘ │
│ │ │ route on │
│ │ │ instance=… │
│ │ ┌────────────▼───────────────┐ │
│ │ │ child pool (lazy, reaped) │ │
│ │ └──┬──────────┬──────────┬───┘ │
└───────────────────────────────┴─────┼──────────┼──────────┼──────┘
│ stdio │ stdio │ stdio
┌─────▼────┐ ┌───▼──────┐ ┌▼─────────┐
│mcp-grafana│ │mcp-grafana│ │mcp-grafana│
│ appstate │ │ uoregon │ │ … │
└─────┬────┘ └───┬──────┘ └┬─────────┘
▼ ▼ ▼
appstate uoregon …Grafana자식 프로세스는 첫 사용 시 시작되고, 유휴 상태(--idle-timeout, 기본 15분)가 되면 종료되며, 종료되면 투명하게 재시작됩니다. 연결할 수 없는 Grafana가 있어도 해당 인스턴스에만 영향을 미칩니다.
설치
두 가지 구성 요소가 필요합니다: 상위 바이너리와 이 패키지입니다.
# 1. the upstream mcp-grafana binary (needs Go 1.26+; GOTOOLCHAIN=auto fetches it)
deploy/install-mcp-grafana.sh /usr/local/bin
# 2. this server
python3 -m venv /opt/grafana-unified-mcp/.venv
/opt/grafana-unified-mcp/.venv/bin/pip install 'grafana-unified-mcp[aws] @ .'이미 바이너리가 있다면 MCP_GRAFANA_BINARY=/path/to/mcp-grafana 또는 --mcp-grafana-binary로 지정하세요.
설정
엔드포인트
예상하는 그대로의 형태입니다—인스턴스 이름을 상위 환경 변수에 매핑합니다:
{
"appstate": {
"GRAFANA_URL": "https://appstate.uw2.example.cloud/grafana",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": "glsa_…"
},
"uoregon": {
"GRAFANA_URL": "https://uoregon.uw2.example.cloud/grafana",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": "glsa_…",
"description": "University of Oregon production"
}
}인스턴스별 선택적 키: GRAFANA_ORG_ID, GRAFANA_USERNAME / GRAFANA_PASSWORD, description, extra_env, extra_args. 문서 자체에 비밀 정보를 두지 않으려면 GRAFANA_SERVICE_ACCOUNT_TOKEN_ENV (이 프로세스의 환경에서 읽음) 또는 GRAFANA_SERVICE_ACCOUNT_TOKEN_FILE (자식이 읽는 경로)를 사용하세요.
인증
{
"clients": [
{
"name": "claude-routines",
"token_sha256": "3f786850e387550fdab836ed7e6dc881de23001b…",
"instances": ["appstate", "uoregon"],
"scope": "read-only"
},
{
"name": "platform-oncall",
"token_sha256": "…",
"instances": ["*"],
"scope": "read-write"
}
]
}토큰과 그 해시를 생성합니다:
grafana-unified-mcp --hash-token # generates one
grafana-unified-mcp --hash-token 'my-existing-token'클라이언트에게는 token을 제공하고, 문서에는 token_sha256을 넣습니다. 토큰은 hmac.compare_digest로 다이제스트 비교되며, 모든 시도에서 모든 클라이언트가 검사되므로 매치 위치가 타이밍을 통해 유출되지 않습니다.
호출자에게 두 가지가 적용됩니다:
instances— 호출자가 볼 수 있는instance열거형은 자신의 권한으로 범위가 좁혀지며, 권한 밖의 인스턴스를 호출하면 존재하지 않는 인스턴스와 동일한 메시지로 거부되므로 토큰이 접근 불가능한 인스턴스를 열거할 수 없습니다.scope—read-only호출자는 변경 도구를 전혀 볼 수 없습니다. 구분은 여기서 유지 관리되는 목록이 아닌 상위 프로젝트 자체의readOnlyHint어노테이션(현재 65개 도구 중 49개가 읽기 전용)에서 비롯되므로, 상위 프로젝트에서 추가된 도구는 코드 변경 없이 분류됩니다. 어노테이션이 없는 것은 읽기 전용이 아닌 것으로 처리됩니다.
이중 안전을 위해 --child-arg=--disable-write를 추가하여 모든 호출자에 대해 소스에서 쓰기 도구를 제거할 수 있습니다.
인증 없이 실행
--auth-mode none은 포트에 접근 가능한 모든 호출자에게 읽기 전용으로 제공합니다. 인스턴스를 범위 지정할 신원이 없으므로 모든 설정된 인스턴스는 읽을 수 있지만—열린 포트가 대시보드를 수정하거나 스냅샷을 삭제할 수 없어야 하므로 아무것도 쓸 수 없습니다. 이는 세 계층에서 강제됩니다:
게시된 카탈로그에서 모든 변경 도구를 제외합니다;
인증 검사가 클라이언트가 직접 도구를 이름으로 호출해도 거부합니다;
자식 프로세스는
--disable-write로 시작되므로 상위 프로젝트도 거부합니다.
세 번째 계층이 단순한 필터 이상으로 만듭니다. 상위 프로젝트는 grafana_api_request를 별도의 GET 전용 등록으로 대체합니다—body 매개변수 없음, method가 GET으로 좁혀짐, GET이 아닌 것은 런타임에 거부됨—따라서 계층 1과 2에 버그가 있어도 쓰기로 이어질 수 없습니다.
stdio는 다릅니다: 로컬 호출자는 이미 엔드포인트 문서와 모든 토큰을 보유하고 있으므로 제한하는 것은 무의미합니다. stdio는 전체 액세스 권한을 가집니다.
HTTP를 통해 쓰기가 필요하다면 열린 포트 대신 read-write 클라이언트와 함께 베어러 토큰을 사용하세요.
설정 출처
--endpoints와 --auth 모두에 대해 다음 중 하나를 사용할 수 있습니다:
출처 | 예시 |
파일 |
|
인라인 환경 변수 |
|
AWS Secrets Manager |
|
AWS SSM Parameter Store |
|
두 문서 모두 --config-refresh-seconds(기본 300)마다 다시 읽힙니다. 새로 고침 실패 시 로그에 기록하고 마지막 유효한 값을 유지하므로, 일시적인 AWS 오류나 쓰기 중인 파일이 서버를 중단시키지 않습니다. 인스턴스 추가는 재시작이 필요 없으며, 제거는 해당 자식을 중지합니다.
시작 전에 유효성 검사:
grafana-unified-mcp --endpoints … --auth … --check-config실행
# local, over stdio (no auth — the local caller already holds the config)
grafana-unified-mcp --endpoints ./examples/endpoints.json
# deployed, over streamable-HTTP behind a reverse proxy
grafana-unified-mcp \
--transport streamable-http \
--address 127.0.0.1:8900 \
--endpoints aws-secrets:prod/grafana/endpoints?region=us-west-2 \
--auth aws-secrets:prod/grafana/mcp-auth?region=us-west-2 \
--public-url https://grafana-mcp.example.com
--public-url이 중요합니다. SDK는Host헤더를 기반으로 DNS-리바인딩 보호를 적용합니다. 공개 호스트 이름을 전달하는 프록시 뒤에 있다면, 해당 호스트가 허용되어야 합니다. 그렇지 않으면 모든 요청이 거부됩니다.--public-url이 이를 허용하며(RFC 9728 리소스 메타데이터에도 사용됨);--allowed-host는 추가 호스트를 허용합니다.
GET /healthz는 Grafana에 접촉하지 않고 프로세스 상태, 활성 자식, 카탈로그 상태를 보고합니다.
클라이언트 연결
.mcp.json, 로컬 stdio용:
{
"mcpServers": {
"grafana": {
"command": "/opt/grafana-unified-mcp/.venv/bin/grafana-unified-mcp",
"args": ["--endpoints", "/etc/grafana-unified-mcp/endpoints.json"]
}
}
}배포된 서버용—Claude Code 루틴 및 클라우드 세션 포함, 베어러 토큰이 존재하는 경우:
{
"mcpServers": {
"grafana": {
"type": "http",
"url": "https://grafana-mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${GRAFANA_UNIFIED_MCP_TOKEN}"
}
}
}
}세션이 실행되는 환경에 GRAFANA_UNIFIED_MCP_TOKEN을 설정하세요—웹상의 Claude Code의 경우 환경 변수에 설정되므로, 예약된 루틴과 클라우드 세션이 비밀을 저장소에 저장하지 않고 사용할 수 있습니다. 루틴에는 read-only 클라이언트를 제공하고, read-write는 사람에게 유지하세요.
systemd 서비스로 배포
deploy/를 참조하세요. 요약:
sudo deploy/install.sh # user, dirs, venv, unit file
sudo systemctl edit grafana-unified-mcp # set the source URIs / region
sudo systemctl enable --now grafana-unified-mcp
curl -s localhost:8900/healthz | jq유닛은 전용 비특권 사용자로 실행되며 ProtectSystem=strict, PrivateTmp, NoNewPrivileges가 적용됩니다. TLS는 앞단의 nginx 또는 ALB에서 종료됩니다—deploy/nginx.conf.example을 참조하세요. 이 예제는 응답 버퍼링을 비활성화합니다(SSE 스트리밍에 필요).
사용 방법
먼저 모델이 list_grafana_instances를 가리키도록 합니다:
list_grafana_instances()
→ { "instances": [ {"name": "appstate", "url": "…", "connection": "live"}, … ],
"routing_argument": "instance",
"access": { "client": "claude-routines", "scope": "read-only" } }그러면 다른 모든 도구가 그 이름을 사용합니다:
search_dashboards(instance="appstate", query="latency")check_health=true를 전달하면 각 Grafana도 검사합니다—모든 인스턴스에 연결을 열어야 하므로 더 느립니다.
이름 관련 문제 한 가지
상위 프로젝트의 grafana_api_request에는 이미 endpoint(API 경로)라는 필수 매개변수가 있습니다. 이 이름으로 라우팅 인수를 주입하면 조용히 가려집니다. 그래서 기본적으로 라우팅 인수는 instance입니다. --routing-param endpoint로 이름을 바꾸면 해당 도구의 자체 매개변수는 자동으로 api_path로 다시 게시되고 통과 시 매핑됩니다—어떤 선택을 하든 충돌로 인해 도구가 손상되지 않습니다.
개발
uv venv && uv pip install -e '.[dev,aws]'
uv run pytest # unit + integration통합 테스트는 실제 mcp-grafana 자식을 연결할 수 없는 Grafana에 대해 구동합니다: 라이브 자격 증명 없이도 카탈로그 검색, instance 주입 및 제거, 라우팅, 인증 필터링을 증명하기에 충분합니다. MCP_GRAFANA_BINARY를 바이너리 경로로 설정하세요. 그렇지 않으면 건너뜁니다.
로드맵
OAuth 2.1 — 인증 계층은 이미 인터페이스이며, SDK는 이미 토큰 검증기와 함께 OAuth 제공자를 받습니다.
OAuth2Provider.verify_token을 구현하는 것이 전부입니다;auth/oauth.py는 세 단계를 문서화합니다. IdP 그룹을 기존의grafana:read/grafana:write/instance:<name>범위에 매핑하면 모든 인증 검사가 변경 없이 계속 작동합니다.Fan-out —
instance: "*"를 사용하여 모든 인스턴스에 대해 하나의 읽기 전용 쿼리를 실행하고 결과를 병합합니다. "어느 것이 알림을 보내고 있나요?"와 같은 질문에 유용합니다. 결과 병합은 자체 설계가 필요하므로 현재는 포함되지 않았습니다.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
An MCP server giving access to Grafana dashboards, data and more.
Remote MCP for GenAI span mapping, provider normalization, dashboard schemas, and receipts.
MCP server for interacting with the Supabase platform
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/robert-sinclair/grafana-unified-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server