Module: LocalVault::MCP::Tools
- Defined in:
- lib/localvault/mcp/tools.rb
Constant Summary collapse
- VAULT_PARAM =
{ "vault" => { "type" => "string", "description" => "Vault name to use (uses default vault if omitted)" } }.freeze
- DEFINITIONS =
MCP tool definitions conforming to the MCP tools/list schema. Each entry specifies a tool name, description, and JSON Schema for input.
[ { "name" => "get_secret", "description" => "Reveal plaintext only when the task truly requires the value in model context. Prefer localvault_build_exec for commands, evaluations, and API calls.", "inputSchema" => { "type" => "object", "properties" => { "key" => { "type" => "string", "description" => "The exact secret key to reveal" }, "allow_plaintext" => { "type" => "boolean", "description" => "Must be true to acknowledge that plaintext will enter model context" }, **VAULT_PARAM }, "required" => ["key", "allow_plaintext"] }, "annotations" => { "readOnlyHint" => true, "openWorldHint" => false } }, { "name" => "list_secrets", "description" => "Discover secret names without values. After selecting names, use localvault_build_exec to inject them into a process.", "inputSchema" => { "type" => "object", "properties" => { "prefix" => { "type" => "string", "description" => "Only return keys starting with this prefix" }, "query" => { "type" => "string", "description" => "Case-insensitive substring filter for key names" }, **VAULT_PARAM }, "required" => [] }, "annotations" => { "readOnlyHint" => true, "openWorldHint" => false } }, { "name" => "localvault_build_exec", "description" => "Build, but never execute, a shell-safe localvault exec command that injects secrets directly into a subprocess without exposing values to the model.", "inputSchema" => { "type" => "object", "properties" => { "command" => { "type" => "array", "items" => { "type" => "string" }, "description" => "Command argv to run with injected secrets" }, "vault" => { "type" => "string", "description" => "Vault name" }, "project" => { "type" => "string", "description" => "Dot-notation project group to inject without a prefix" }, "only" => { "type" => "array", "items" => { "type" => "string" }, "description" => "Exact keys or GROUP.* selectors" }, "except" => { "type" => "array", "items" => { "type" => "string" }, "description" => "Selectors to exclude" }, "map" => { "type" => "object", "additionalProperties" => { "type" => "string" }, "description" => "Vault-key to environment-variable mappings" }, "profile" => { "type" => "string", "enum" => ["aws"], "description" => "Built-in mapping profile" } }, "required" => ["command"] }, "outputSchema" => { "type" => "object", "properties" => { "command" => { "type" => "string" }, "exposes_plaintext" => { "type" => "boolean" }, "executes_command" => { "type" => "boolean" }, "next_action" => { "type" => "string" } }, "required" => %w[command exposes_plaintext executes_command next_action], "additionalProperties" => false }, "annotations" => { "readOnlyHint" => true, "openWorldHint" => false } }, { "name" => "localvault_whoami", "description" => "Show which localvault home, vault, and unlocked sessions the MCP server can see", "inputSchema" => { "type" => "object", "properties" => { **VAULT_PARAM }, "required" => [] }, "annotations" => { "readOnlyHint" => true, "openWorldHint" => false } }, { "name" => "set_secret", "description" => "Store a secret key-value pair in a localvault vault. Use dot-notation (project.KEY) for namespaced secrets.", "inputSchema" => { "type" => "object", "properties" => { "key" => { "type" => "string", "description" => "The secret key (supports dot-notation: project.KEY)" }, "value" => { "type" => "string", "description" => "The secret value" }, **VAULT_PARAM }, "required" => ["key", "value"] }, "annotations" => { "readOnlyHint" => false, "destructiveHint" => true, "idempotentHint" => false, "openWorldHint" => false } }, { "name" => "delete_secret", "description" => "Delete a secret by key from a localvault vault", "inputSchema" => { "type" => "object", "properties" => { "key" => { "type" => "string", "description" => "The secret key to delete" }, **VAULT_PARAM }, "required" => ["key"] }, "annotations" => { "readOnlyHint" => false, "destructiveHint" => true, "idempotentHint" => true, "openWorldHint" => false } } ].freeze
Class Method Summary collapse
-
.call(name, arguments, vault_resolver, status_resolver = nil) ⇒ Hash
Dispatch an MCP tool call by name.
Class Method Details
.call(name, arguments, vault_resolver, status_resolver = nil) ⇒ Hash
Dispatch an MCP tool call by name.
Resolves the target vault via the provided callable, then executes the requested tool (get_secret, list_secrets, set_secret, or delete_secret).
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/localvault/mcp/tools.rb', line 136 def self.call(name, arguments, vault_resolver, status_resolver = nil) unless DEFINITIONS.any? { |t| t["name"] == name } raise ArgumentError, "Unknown tool: #{name}" end return error_result("Invalid arguments; expected object") unless arguments.is_a?(Hash) vault_name = arguments["vault"] return whoami(status_resolver.call(vault_name)) if name == "localvault_whoami" return build_exec(arguments) if name == "localvault_build_exec" return required_argument_error("key") if name == "get_secret" && !present_string?(arguments["key"]) if name == "get_secret" && arguments["allow_plaintext"] != true return error_result( "Plaintext retrieval is blocked by default. For authentication or an external command, call " \ "localvault_build_exec instead. Retry get_secret with allow_plaintext=true only when the user " \ "explicitly needs the secret text or injection cannot complete the task." ) end vault = vault_resolver.call(vault_name) unless vault hint = vault_name ? "localvault show -v #{vault_name}" : "localvault show" return error_result("No unlocked vault session. Run `localvault mcp --check`, then unlock with: #{hint}") end case name when "get_secret" then get_secret(arguments["key"], vault) when "list_secrets" then list_secrets(vault, prefix: arguments["prefix"], query: arguments["query"]) when "set_secret" then set_secret(arguments["key"], arguments["value"], vault) when "delete_secret" then delete_secret(arguments["key"], vault) end rescue StandardError => e error_result(e.) end |