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
9 changes: 7 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,13 @@ The `docs/specs/` directory contains feature specifications (living documentatio
### Documentation conventions

- Use **lowercase filenames** for new documentation files (e.g., `configuration.md`, `prompts.md`)
- The toolsets table in `README.md` and `docs/configuration.md` is **auto-generated** - use `make update-readme-tools` to update it
- Both files use markers (`<!-- AVAILABLE-TOOLSETS-START -->` / `<!-- AVAILABLE-TOOLSETS-END -->`) for the generated content
- The toolsets table, tools, prompts, resources, and resource templates in `README.md` and `docs/configuration.md` are **auto-generated** - use `make update-readme-tools` to update them after modifying toolsets
- Both files use marker pairs for the generated content:
- `<!-- AVAILABLE-TOOLSETS-START -->` / `<!-- AVAILABLE-TOOLSETS-END -->` (toolset summary table)
- `<!-- AVAILABLE-TOOLSETS-TOOLS-START -->` / `<!-- AVAILABLE-TOOLSETS-TOOLS-END -->` (tool details)
- `<!-- AVAILABLE-TOOLSETS-PROMPTS-START -->` / `<!-- AVAILABLE-TOOLSETS-PROMPTS-END -->` (prompt details)
- `<!-- AVAILABLE-TOOLSETS-RESOURCES-START -->` / `<!-- AVAILABLE-TOOLSETS-RESOURCES-END -->` (resource details)
- `<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-START -->` / `<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-END -->` (resource template details)

## Distribution Methods

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,20 @@ Silences are used to temporarily mute alerts based on label matchers. This tool

<!-- AVAILABLE-TOOLSETS-PROMPTS-END -->

### Resources

<!-- AVAILABLE-TOOLSETS-RESOURCES-START -->


<!-- AVAILABLE-TOOLSETS-RESOURCES-END -->

### Resource Templates

<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-START -->


<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-END -->

## Helm Chart

A [Helm Chart](https://helm.sh) is available to simplify the deployment of the Kubernetes MCP server.
Expand Down
14 changes: 14 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,20 @@ Toolsets group related tools together. Enable only the toolsets you need to redu
toolsets = ["core", "config", "helm", "kubevirt"]
```

**Available Resources:**

<!-- AVAILABLE-TOOLSETS-RESOURCES-START -->


<!-- AVAILABLE-TOOLSETS-RESOURCES-END -->

**Available Resource Templates:**

<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-START -->


<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-END -->

### Tool Filtering

Fine-grained control over individual tools within enabled toolsets.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
golang.org/x/sync v0.20.0
golang.org/x/time v0.15.0
google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.20.2
k8s.io/api v0.35.4
k8s.io/apiextensions-apiserver v0.35.4
Expand Down Expand Up @@ -186,7 +187,6 @@ require (
google.golang.org/grpc v1.80.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiserver v0.35.4 // indirect
k8s.io/component-base v0.35.4 // indirect
knative.dev/pkg v0.0.0-20260318013857-98d5a706d4fd // indirect
Expand Down
15 changes: 15 additions & 0 deletions internal/test/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,21 @@ func (m *McpClient) ListPrompts() (*mcp.ListPromptsResult, error) {
return m.Session.ListPrompts(m.ctx, &mcp.ListPromptsParams{})
}

// ListResources helper function to list available resources
func (m *McpClient) ListResources() (*mcp.ListResourcesResult, error) {
return m.Session.ListResources(m.ctx, &mcp.ListResourcesParams{})
}

// ReadResource helper function to read a resource by URI
func (m *McpClient) ReadResource(uri string) (*mcp.ReadResourceResult, error) {
return m.Session.ReadResource(m.ctx, &mcp.ReadResourceParams{URI: uri})
}

// ListResourceTemplates helper function to list available resource templates
func (m *McpClient) ListResourceTemplates() (*mcp.ListResourceTemplatesResult, error) {
return m.Session.ListResourceTemplates(m.ctx, &mcp.ListResourceTemplatesParams{})
}

// GetPrompt helper function to get a prompt by name
func (m *McpClient) GetPrompt(name string, arguments map[string]string) (*mcp.GetPromptResult, error) {
return m.Session.GetPrompt(m.ctx, &mcp.GetPromptParams{
Expand Down
45 changes: 45 additions & 0 deletions internal/tools/update-readme/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kcp"
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kiali"
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt"
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/mustgather"
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/tekton"
_ "github.com/rhobs/obs-mcp/pkg/toolset"
)
Expand Down Expand Up @@ -136,6 +137,50 @@ func main() {
toolsetPrompts.String(),
)

// Available Toolset Resources
toolsetResources := strings.Builder{}
for _, toolset := range toolsetsList {
resources := toolset.GetResources()
if len(resources) == 0 {
continue
}
toolsetResources.WriteString("<details>\n\n<summary>" + toolset.GetName() + "</summary>\n\n")
for _, resource := range resources {
fmt.Fprintf(&toolsetResources, "- **%s** - %s\n", resource.Resource.Name, resource.Resource.Description)
fmt.Fprintf(&toolsetResources, " - URI: `%s`\n", resource.Resource.URI)
fmt.Fprintf(&toolsetResources, " - MIME Type: `%s`\n", resource.Resource.MIMEType)
}
toolsetResources.WriteString("</details>\n\n")
}
updated = replaceBetweenMarkers(
updated,
"<!-- AVAILABLE-TOOLSETS-RESOURCES-START -->",
"<!-- AVAILABLE-TOOLSETS-RESOURCES-END -->",
toolsetResources.String(),
)

// Available Toolset Resource Templates
toolsetResourceTemplates := strings.Builder{}
for _, toolset := range toolsetsList {
templates := toolset.GetResourceTemplates()
if len(templates) == 0 {
continue
}
toolsetResourceTemplates.WriteString("<details>\n\n<summary>" + toolset.GetName() + "</summary>\n\n")
for _, template := range templates {
fmt.Fprintf(&toolsetResourceTemplates, "- **%s** - %s\n", template.ResourceTemplate.Name, template.ResourceTemplate.Description)
fmt.Fprintf(&toolsetResourceTemplates, " - URI Template: `%s`\n", template.ResourceTemplate.URITemplate)
fmt.Fprintf(&toolsetResourceTemplates, " - MIME Type: `%s`\n", template.ResourceTemplate.MIMEType)
}
toolsetResourceTemplates.WriteString("</details>\n\n")
}
updated = replaceBetweenMarkers(
updated,
"<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-START -->",
"<!-- AVAILABLE-TOOLSETS-RESOURCES-TEMPLATES-END -->",
toolsetResourceTemplates.String(),
)

if err := os.WriteFile(localReadmePath, []byte(updated), 0o644); err != nil {
panic(err)
}
Expand Down
56 changes: 56 additions & 0 deletions pkg/api/toolsets.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ type Toolset interface {
// GetPrompts returns the prompts provided by this toolset.
// Returns nil if the toolset doesn't provide any prompts.
GetPrompts() []ServerPrompt
// GetResources returns the resources provided by this toolset.
// Returns nil if the toolset doesn't provide any resources.
GetResources() []ServerResource
// GetResourceTemplates returns the resource templates provided by this toolset.
// Returns nil if the toolset doesn't provide any resource templates.
GetResourceTemplates() []ServerResourceTemplate
}

type ToolCallRequest interface {
Expand Down Expand Up @@ -103,6 +109,56 @@ func NewToolCallResultStructured(structured any, err error) *ToolCallResult {
return NewToolCallResultFull(content, structured, err)
}

// Resource represents the metadata of an MCP resource.
type Resource struct {
URI string
Name string
Description string
MIMEType string
}

// ResourceContent is the value returned by a resource handler.
// Exactly one of Text or Blob must be set; both cannot be nil or both non-nil.
type ResourceContent struct {
// MIMEType overrides Resource.MIMEType when set; otherwise Resource.MIMEType is used.
MIMEType string
// Text is the UTF-8 text content of the resource.
Text string
// Blob is the binary content of the resource.
Blob []byte
}

// ResourceHandler is called when a client reads a resource.
// Session state (auth, request context) is available on ctx via sessionInjectionMiddleware.
// Handlers should return a ResourceContent with exactly one of Text or Blob set.
type ResourceHandler func(ctx context.Context) (*ResourceContent, error)

// ServerResource represents a resource that can be registered with the MCP server.
type ServerResource struct {
Resource Resource
Handler ResourceHandler
}

// ResourceTemplate represents the metadata of an MCP resource template.
type ResourceTemplate struct {
URITemplate string
Name string
Description string
MIMEType string
}

// ResourceTemplateHandler is called when a client reads a resource matching a template.
// Session state (auth, request context) is available on ctx via sessionInjectionMiddleware.
// The uri parameter is the actual resource URI that matches the template.
// Handlers should return a ResourceContent with exactly one of Text or Blob set.
type ResourceTemplateHandler func(ctx context.Context, uri string) (*ResourceContent, error)

// ServerResourceTemplate represents a resource template that can be registered with the MCP server.
type ServerResourceTemplate struct {
ResourceTemplate ResourceTemplate
Handler ResourceTemplateHandler
}

type ToolHandlerParams struct {
context.Context
BaseConfig
Expand Down
8 changes: 8 additions & 0 deletions pkg/mcp/elicit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@ func (m *mockElicitToolset) GetPrompts() []api.ServerPrompt {
return nil
}

func (m *mockElicitToolset) GetResources() []api.ServerResource {
return nil
}

func (m *mockElicitToolset) GetResourceTemplates() []api.ServerResourceTemplate {
return nil
}

func TestElicitationSuite(t *testing.T) {
suite.Run(t, new(ElicitationSuite))
}
12 changes: 6 additions & 6 deletions pkg/mcp/gosdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ func ServerToolToGoSdkTool(s *Server, tool api.ServerTool) (*mcp.Tool, mcp.ToolH
}

result, err := tool.Handler(api.ToolHandlerParams{
Context: ctx,
BaseConfig: s.configuration,
KubernetesClient: k,
ToolCallRequest: toolCallRequest,
ListOutput: s.configuration.ListOutput(),
Elicitor: &sessionElicitor{},
Context: ctx,
BaseConfig: s.configuration,
KubernetesClient: k,
ToolCallRequest: toolCallRequest,
ListOutput: s.configuration.ListOutput(),
Elicitor: &sessionElicitor{},
})
if err != nil {
return nil, err
Expand Down
Loading