feet(tools+context): Dynamic tool registration#309
Conversation
gerboland
left a comment
There was a problem hiding this comment.
nit: please update the README to reflect the new CLI flag & behaviour.
|
Added a comment about supported protocols. |
| // ToolsetInfo provides information about a toolset | ||
| type ToolsetInfo struct { | ||
| Name string `json:"name" jsonschema:"required,description=The name of the toolset"` | ||
| Description string `json:"description" jsonschema:"description=Description of what the toolset provides"` | ||
| Enabled bool `json:"enabled" jsonschema:"description=Whether the toolset is currently enabled"` | ||
| } |
There was a problem hiding this comment.
Do you think it would be worth including ToolNames []string here, as a more concrete hint of what tools this contains?
README.md
Outdated
| - ✅ **stdio protocol** - Fully supported | ||
| - ❌ **SSE (Server-Sent Events)** - Not yet supported | ||
| - ❌ **Streamable HTTP** - Not yet supported |
There was a problem hiding this comment.
Huh, is this because notifications aren't as well supported over streamable HTTP?
There was a problem hiding this comment.
This is now fixed. After rebasing on top of your PR. https://github.com/grafana/mcp-grafana/pull/314/files 🥳
3744eaa to
88579d6
Compare
Yeah it should update on the UI as well. The moment you ask more tools to be enabled and the tool is called, the new tools should appear on the UI. |
835e637 to
f57223e
Compare
f57223e to
b28d052
Compare
sd2k
left a comment
There was a problem hiding this comment.
Looks cool! Would love to see it in, think we need to fix conflicts and lints/tests but otherwise LGTM
README.md
Outdated
| | `grafana_list_toolsets` | Meta | List available toolsets for [dynamic discovery](#dynamic-toolset-discovery) | None (meta-tool) | N/A | | ||
| | `grafana_enable_toolset` | Meta | Enable a specific toolset [dynamically](#dynamic-toolset-discovery) | None (meta-tool) | N/A | |
There was a problem hiding this comment.
nit: let's keep this table aligned
README.md
Outdated
|
|
||
| **Integration with `--enabled-tools`:** | ||
| - No flag → all toolsets are discoverable | ||
| - `--enabled-tools=""` → no toolsets are discoverable |
There was a problem hiding this comment.
Is this ever likely to be useful? I wonder if we should just error in this case 🤷
README.md
Outdated
|
|
||
| **How it works:** | ||
| 1. Start the server with `--dynamic-toolsets` flag | ||
| 2. Use `grafana_list_toolsets` to discover available toolset categories |
There was a problem hiding this comment.
This list conflates things that the user does (start the server) with things that the LLM does (use those tools); we should make it clear that the user doesn't have to actually do those things, and it's the LLM doing it instead.
README.md
Outdated
| | `grafana_list_toolsets` | Meta | List available toolsets for [dynamic discovery](#dynamic-toolset-discovery) | None (meta-tool) | N/A | | ||
| | `grafana_enable_toolset` | Meta | Enable a specific toolset [dynamically](#dynamic-toolset-discovery) | None (meta-tool) | N/A | |
There was a problem hiding this comment.
GitHub's dynamic tool discovery has 3 tools (enable_toolset, list_available_toolsets, get_toolset_tools) - did you experiment with this instead? I guess get_toolset_tools returns some more detailed info about the tools vs just the name (which we provide in the toolset list).
Either way we can iterate on that, not a blocker!
There was a problem hiding this comment.
I haven't no. I don't remember this being a thing when I raised this PR.
I can have a look if we push this but I would do it separately mainly because I need to put time again into that! 😏
b28d052 to
73f99c7
Compare
This comment has been minimized.
This comment has been minimized.
c13da9a to
162f9bd
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
162f9bd to
6c94455
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
6c94455 to
d52bd80
Compare
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Ben Sully <ben.sully@grafana.com>
d52bd80 to
610b045
Compare
This comment has been minimized.
This comment has been minimized.
MCP Token Analysis✅ Passed
|
| // Define all available toolsets | ||
| allToolsets := []struct { | ||
| name string | ||
| description string | ||
| toolNames []string | ||
| addFunc func(*server.MCPServer) | ||
| }{ | ||
| {"search", "Tools for searching dashboards, folders, and other Grafana resources", []string{"search_dashboards", "search_folders"}, tools.AddSearchTools}, | ||
| {"datasource", "Tools for listing and fetching datasource details", []string{"list_datasources", "get_datasource_by_uid", "get_datasource_by_name"}, tools.AddDatasourceTools}, | ||
| {"incident", "Tools for managing Grafana Incident (create, update, search incidents)", []string{"list_incidents", "create_incident", "add_activity_to_incident", "get_incident"}, func(mcp *server.MCPServer) { tools.AddIncidentTools(mcp, enableWriteTools) }}, | ||
| {"prometheus", "Tools for querying Prometheus metrics and metadata", []string{"list_prometheus_metric_metadata", "query_prometheus", "list_prometheus_metric_names", "list_prometheus_label_names", "list_prometheus_label_values"}, tools.AddPrometheusTools}, | ||
| {"loki", "Tools for querying Loki logs and labels", []string{"list_loki_label_names", "list_loki_label_values", "query_loki_stats", "query_loki_logs"}, tools.AddLokiTools}, | ||
| {"alerting", "Tools for managing alert rules and notification contact points", []string{"list_alert_rules", "get_alert_rule_by_uid", "list_contact_points", "create_alert_rule", "update_alert_rule", "delete_alert_rule"}, func(mcp *server.MCPServer) { tools.AddAlertingTools(mcp, enableWriteTools) }}, | ||
| {"dashboard", "Tools for managing Grafana dashboards (get, update, extract queries)", []string{"get_dashboard_by_uid", "update_dashboard", "get_dashboard_panel_queries", "get_dashboard_property", "get_dashboard_summary"}, func(mcp *server.MCPServer) { tools.AddDashboardTools(mcp, enableWriteTools) }}, | ||
| {"folder", "Tools for managing Grafana folders", []string{"create_folder"}, func(mcp *server.MCPServer) { tools.AddFolderTools(mcp, enableWriteTools) }}, | ||
| {"oncall", "Tools for managing OnCall schedules, shifts, teams, and users", []string{"list_oncall_schedules", "get_oncall_shift", "get_current_oncall_users", "list_oncall_teams", "list_oncall_users", "list_alert_groups", "get_alert_group"}, tools.AddOnCallTools}, | ||
| {"asserts", "Tools for Grafana Asserts cloud functionality", []string{"get_assertions"}, tools.AddAssertsTools}, | ||
| {"sift", "Tools for Sift investigations (analyze logs/traces, find errors, detect slow requests)", []string{"get_sift_investigation", "get_sift_analysis", "list_sift_investigations", "find_error_pattern_logs", "find_slow_requests"}, func(mcp *server.MCPServer) { tools.AddSiftTools(mcp, enableWriteTools) }}, | ||
| {"admin", "Tools for administrative tasks (list teams, manage users)", []string{"list_teams", "list_users_by_org"}, tools.AddAdminTools}, | ||
| {"pyroscope", "Tools for profiling applications with Pyroscope", []string{"list_pyroscope_label_names", "list_pyroscope_label_values", "list_pyroscope_profile_types", "fetch_pyroscope_profile"}, tools.AddPyroscopeTools}, | ||
| {"navigation", "Tools for generating deeplink URLs to Grafana resources", []string{"generate_deeplink"}, tools.AddNavigationTools}, | ||
| {"annotations", "Tools for managing annotations", []string{"get_annotations", "create_annotation", "create_graphite_annotation", "update_annotation", "patch_annotation", "get_annotation_tags"}, func(mcp *server.MCPServer) { tools.AddAnnotationTools(mcp, enableWriteTools) }}, | ||
| {"rendering", "Tools for rendering dashboard panels as images", []string{"get_panel_image"}, tools.AddRenderingTools}, | ||
| } |
There was a problem hiding this comment.
This is gonna get out of date very quickly 😅 can we think of a better way of constructing this slice automatically?
| - search: Search dashboards, folders, and resources | ||
| - datasource: Manage datasources | ||
| - prometheus: Query Prometheus metrics | ||
| - loki: Query Loki logs | ||
| - dashboard: Manage dashboards | ||
| - folder: Manage folders | ||
| - incident: Manage incidents | ||
| - alerting: Manage alerts | ||
| - oncall: Manage OnCall schedules | ||
| - asserts: Grafana Asserts functionality | ||
| - sift: Sift investigations | ||
| - admin: Administrative tasks | ||
| - pyroscope: Application profiling | ||
| - navigation: Generate deeplinks | ||
| - proxied: Access tools from external MCP servers (like Tempo) through dynamic discovery |
There was a problem hiding this comment.
likewise I think this will get out of date quickly.
| - ✅ **Cursor** - Fully supported (supports notifications via stdio, SSE, and streamable-http) | ||
| - ✅ **VS Code** - Fully supported (supports notifications via stdio, SSE, and streamable-http) | ||
| - ❌ **Claude Desktop** - Not yet supported (no notification support, but open issues exist) | ||
| - ❌ **Claude Code** - Not yet supported (no notification support, but open issues exist) |
There was a problem hiding this comment.
Any chance these have been updated since we last checked?


Dynamic Toolset Discovery and Loading
Summary
Adds dynamic toolset functionality that allows clients to discover and selectively enable tool categories at runtime, significantly reducing context window usage by only loading tools when needed.
Motivation
MCP tool descriptions can consume substantial context window space. By enabling dynamic discovery, clients only load the tools they actually need, preserving context for more important data.
Implementation
New flag:
--dynamic-toolsetsenables dynamic toolset modeDiscovery tools: Added grafana_list_toolsets and grafana_enable_toolset meta-tools
Notification support: Sends tools/list_changed notification when toolsets are enabled, triggering client refresh
Integration with --enabled-tools:
--enabled-tools=""--> no toolsets discoverable--enabled-tools="datasources,dashboards"--> only specified toolsets discoverableLimitations and client compatibility
Protocol Support:
✅ stdio protocol - Fully supported
✅ SSE (Server-Sent Events) - Fully supported
✅ Streamable HTTP - Fully supported
After pr https://github.com/grafana/mcp-grafana/pull/314/files from @sd2k all protocols are supported.
Client Support
✅ Supported: Cursor, VSCode (support notifications),
❌ Not Supported: Claude Desktop, Claude Code
Known Behavior
Slight delay expected: There may be a few seconds of delay between calling grafana_enable_toolset and the tools becoming available in the client, as the client needs to receive and process the
tools/list_changednotification.Note: This is opt-in via the
--dynamic-toolsetsflag. Existing static tool registration remains the default behavior.How it works with Cursor.
Currently Sonnet 4.5 model selected - 1m tokens available for this conversation
Normal behavior all tools available:
At the beginning 13.9% of context used

How many tools are available 14.1%

List my prometheus datasources 14.8%

Dynamic tool discovery enabled with all tools discoverable.
At the beginning 5.5% of context used

List available toolsets - 5.9%

Enable Datasource toolset

List Datasources 7%
