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
6 changes: 6 additions & 0 deletions pkg/tools/kv/delete_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func DeleteSecret(logger *log.Logger) server.ServerTool {
mcp.DefaultString(""),
mcp.Description("A optional key in the secret to delete. If not specified, all keys in the the secret will be deleted."),
),
mcp.WithString("namespace",
mcp.DefaultString(""),
mcp.Description("Optional Vault namespace override for this call (for example: 'admin/team-03'). If not set, uses the MCP session namespace."),
),
),
Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return deleteSecretHandler(ctx, req, logger)
Expand Down Expand Up @@ -69,6 +73,7 @@ func deleteSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *l
if !ok {
return mcp.NewToolResultError("Missing or invalid 'key' parameter"), nil
}
namespace, _ := args["namespace"].(string)

logger.WithFields(log.Fields{
"mount": mount,
Expand All @@ -82,6 +87,7 @@ func deleteSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *l
logger.WithError(err).Error("Failed to get Vault client")
return mcp.NewToolResultError(fmt.Sprintf("Failed to get Vault client: %v", err)), nil
}
vault = withOptionalNamespace(vault, namespace)

mounts, err := vault.Sys().ListMounts()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions pkg/tools/kv/list_secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ func ListSecrets(logger *log.Logger) server.ServerTool {
mcp.WithString("path",
mcp.DefaultString(""),
mcp.Description("The full path to list the secrets to without the mount prefix. For example, if you want to list from 'secrets/application/credentials', this should be 'application/credentials'.")),
mcp.WithString("namespace",
mcp.DefaultString(""),
mcp.Description("Optional Vault namespace override for this call (for example: 'admin/team-03'). If not set, uses the MCP session namespace."),
),
),
Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return listSecretsHandler(ctx, req, logger)
Expand All @@ -58,6 +62,7 @@ func listSecretsHandler(ctx context.Context, req mcp.CallToolRequest, logger *lo
if path == "" {
path = ""
}
namespace, _ := args["namespace"].(string)

logger.WithFields(log.Fields{
"mount": mount,
Expand All @@ -70,6 +75,7 @@ func listSecretsHandler(ctx context.Context, req mcp.CallToolRequest, logger *lo
logger.WithError(err).Error("Failed to get Vault client")
return mcp.NewToolResultError(fmt.Sprintf("Failed to get Vault client: %v", err)), nil
}
vault = withOptionalNamespace(vault, namespace)

// Construct the full path for listing
fullPath := fmt.Sprintf(mount+"/%s", path)
Expand Down
18 changes: 18 additions & 0 deletions pkg/tools/kv/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: MPL-2.0

package kv

import (
"strings"

"github.com/hashicorp/vault/api"
)

func withOptionalNamespace(vault *api.Client, namespace string) *api.Client {
ns := strings.TrimSpace(namespace)
if ns == "" {
return vault
}
return vault.WithNamespace(ns)
}
Comment on lines +12 to +18
6 changes: 6 additions & 0 deletions pkg/tools/kv/read_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ func ReadSecret(logger *log.Logger) server.ServerTool {
mcp.Required(),
mcp.Description("The full path to read the secret to without the mount prefix. For example, if you want to read from 'secrets/application/credentials', this should be 'application/credentials'."),
),
mcp.WithString("namespace",
mcp.DefaultString(""),
mcp.Description("Optional Vault namespace override for this call (for example: 'admin/team-03'). If not set, uses the MCP session namespace."),
),
Comment on lines +33 to +36
),
Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return readSecretHandler(ctx, req, logger)
Expand All @@ -55,6 +59,7 @@ func readSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *log
if !ok || path == "" {
return mcp.NewToolResultError("Missing or invalid 'path' parameter"), nil
}
namespace, _ := args["namespace"].(string)

logger.WithFields(log.Fields{
"mount": mount,
Expand All @@ -67,6 +72,7 @@ func readSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *log
logger.WithError(err).Error("Failed to get Vault client")
return mcp.NewToolResultError(fmt.Sprintf("Failed to get Vault client: %v", err)), nil
}
vault = withOptionalNamespace(vault, namespace)

mounts, err := vault.Sys().ListMounts()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions pkg/tools/kv/write_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func WriteSecret(logger *log.Logger) server.ServerTool {
mcp.Required(),
mcp.Description("The value to store the given key. For example if you want to write mysecret=myvalue, this should be 'myvalue'"),
),
mcp.WithString("namespace",
mcp.DefaultString(""),
mcp.Description("Optional Vault namespace override for this call (for example: 'admin/team-03'). If not set, uses the MCP session namespace."),
),
),
Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return writeSecretHandler(ctx, req, logger)
Expand Down Expand Up @@ -78,6 +82,7 @@ func writeSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *lo
if !ok || value == "" {
return mcp.NewToolResultError("Missing or invalid 'value' parameter"), nil
}
namespace, _ := args["namespace"].(string)

logger.WithFields(log.Fields{
"mount": mount,
Expand All @@ -91,6 +96,7 @@ func writeSecretHandler(ctx context.Context, req mcp.CallToolRequest, logger *lo
logger.WithError(err).Error("Failed to get Vault client")
return mcp.NewToolResultError(fmt.Sprintf("Failed to get Vault client: %v", err)), nil
}
vault = withOptionalNamespace(vault, namespace)

mounts, err := vault.Sys().ListMounts()
if err != nil {
Expand Down
Loading