Vault
Connect AI agents to Vault using the MCP server
In this tutorial, you will configure VS Code to use the Vault MCP server tools. You will scope a policy and Vault token for the AI agent, and connect the server to GitHub Copilot in VS Code to manage application secrets as part of your software development lifecycle.
If you are new to Vault, checkout the Vault foundations tutorial series.
Overview
Secrets management tasks like storing credentials, and issuing internal TLS certificates require developers to break their local workflow. These context switches break development flow and can lead to misconfigurations when developers work outside their primary tooling.
The Vault MCP server exposes Vault APIs as Model Context Protocol (MCP) tools that AI coding agents call through natural language prompts
Scenario
The engineering team at HashiCups is reviewing how to incorporate AI into the software development lifecycle. Alice and Danielle are concerned about the cognitive load of switching between tools to manage secrets and certificates for the engineering team. Alice asks Danielle to test the Vault MCP server using Copilot. Oliver from the operations team will help set up Vault policies to support Danielle's testing.
The Vault MCP server exposes Vault operations as callable tools for AI agents. GitHub Copilot in VS Code invokes these tools through natural language prompts, giving developers access to the following capabilities:
- KV secrets management: List, read, write, and delete secrets in KV v1 and KV v2 mounts
- PKI certificate authority: Enable the PKI secrets engine, create root issuers, configure roles, and sign TLS certificates
- Mount management: List, create, and remove secrets engine mounts
- Secrets auditing: Enumerate mounts and secret paths to review your Vault instance without switching to the CLI or UI
Review the security model
The Vault MCP server supports two transport modes: stdio and
streamable-http. Your choice of transport determines the attack surface.
This tutorial uses stdio, which is the default and the recommended choice
for individual developer workstations.
STDIO transport
In stdio mode the server communicates over standard input and output streams
rather than a network socket. The stdio transport provides the following
security properties:
- No network port is opened. Other processes on the machine or on the network cannot reach the MCP server because there is no listening socket to connect to.
- Only the process that spawned the server — VS Code in this tutorial — can send requests to it. This supports a zero trust security posture by eliminating network exposure at the workstation level.
Use stdio for local developer workflows. It requires no additional network or
TLS configuration and has the smallest attack surface.
StreamableHTTP transport
In streamable-http mode the server listens on an HTTP port, defaulting to
127.0.0.1:8080. This mode is intended for environments where the MCP client
cannot use STDIO — for example, a shared team service or a remote development
environment. It introduces a larger attack surface and requires additional
controls.
- Bind to loopback only. IBM recommends binding the server to
127.0.0.1, not0.0.0.0. Binding to all interfaces exposes the Vault MCP server — and by extension, your Vault token — to anyone who can reach that machine on the network. This directly undermines the principle of preventing lateral movement. - Require TLS for remote access. If you must expose the server beyond localhost, configure a valid TLS certificate. The server enforces TLS configuration when remote access is enabled. Without TLS, Vault tokens and secret values transit the network in plaintext.
- Configure CORS strictly. The server defaults to strict CORS mode with an empty allowed-origins list, which blocks all cross-origin requests. If your MCP client requires CORS access, add only the specific origins you trust. Permissive CORS rules can allow malicious web pages to invoke Vault operations through the MCP server.
- Enable rate limiting. Without rate limiting, a compromised or misbehaving
MCP client can flood the server with requests and overwhelm the Vault instance
it connects to. Configure both global and per-session rate limits when running
in
streamable-httpmode.
Shared security considerations
The following behaviors apply regardless of which transport you use.
- Grant least privilege: The server authenticates using the Vault token you provide. Create a dedicated token and policy scoped to only the paths and capabilities the AI agent needs. Do not use a root token or a token shared across team members.
- Secrets may reach the model. Depending on your prompts, the server can return Vault secret values to GitHub Copilot. Review your AI provider's data use terms and the Well-Architected Framework guidance on protecting sensitive data before sending secrets through the model.
- Write operations are on by default. The
ENABLE_VAULT_OPERATIONSenvironment variable controls whether the server can create, update, or delete Vault resources. Set it tofalseto restrict the agent to read-only operations. - Validate AI output before applying it. LLMs can generate plausible but incorrect Vault configuration. Review any policy documents, PKI settings, or mount configurations the agent produces before writing them to a non-development Vault instance.
For the complete threat model — including prompt injection, tool poisoning, and rug-pull attack mitigations — refer to the Vault MCP server security model.
Your GitHub Copilot plan determines how GitHub handles the Vault data that passes through the model. Business and Enterprise plans guarantee your prompts are not used to train GitHub's models. If you use the individual plan, review GitHub's data use terms before sending Vault data through Copilot.
Prerequisites
This tutorial was last tested 15 May 2026 on macOS 26.3.1.
- Docker installed and running
- Vault binary installed
- Vault installed
- Visual Studio Code installed
- Visual Studio Code configured to launch from the command line
- The GitHub Copilot extension installed
- An active GitHub Copilot subscription
Set up the lab
This tutorial runs a Vault dev server as a Docker container.
Start Vault in a container.
$ docker run --name vault \ --cap-add=IPC_LOCK \ --env VAULT_DEV_ROOT_TOKEN_ID=root \ --env VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \ --publish 8200:8200 \ --detach \ --rm \ hashicorp/vault:1.21The Vault dev server is initialized and unsealed, listening on all addresses using port
8200.Export an environment variable for the
vaultCLI to address the Vault server.$ export VAULT_ADDR=http://127.0.0.1:8200Export an environment variable for the
vaultCLI to authenticate with the Vault server.$ export VAULT_TOKEN=rootThe Vault server is ready to proceed with the tutorial.
Create a policy for the MCP server
(Persona: operations)
The Vault MCP server uses a Vault token to authenticate. Create a dedicated policy that limits the token to only the paths and capabilities the agent needs: reading and writing KV v2 secrets, and configuring the PKI mount.
Applying the principle of least privilege limits the blast radius if the agent performs unintended operations. Rotate the token by revoking it and creating a new one at the end of each working session, following the Well-Architected Framework guidance on managing the access lifecycle.
In the terminal where you set
VAULT_ADDR, write the following policy definition to a file namedvault-mcp-policy.hcl.$ cat > vault-mcp-policy.hcl <<'EOF' # KV v2 secret operations on the default secret/ mount path "secret/data/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "secret/metadata/*" { capabilities = ["read", "list", "delete"] } path "secret/+" { capabilities = ["list"] } # Read the mount table for auditing path "sys/mounts" { capabilities = ["read"] } # Enable and manage the specific pki mount used in this tutorial path "sys/mounts/pki" { capabilities = ["create", "read", "update", "delete"] } # PKI operations scoped to the pki/ mount path "pki/root/generate/*" { capabilities = ["create", "update"] } path "pki/config/*" { capabilities = ["create", "read", "update"] } path "pki/roles/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "pki/sign/*" { capabilities = ["create", "update"] } path "pki/issuers/*" { capabilities = ["create", "read", "update", "list"] } path "pki/cert/*" { capabilities = ["read", "list"] } path "sys/mounts/pki/tune" { capabilities = ["create", "read", "update"] } EOFThe KV paths use a wildcard (
*) that grants the AI agent token access to every secret on thesecret/mount. In production, scope these paths to your application prefix — for example,secret/data/myapp/*andsecret/metadata/myapp/*— to prevent the agent from reading or writing secrets owned by other applications on the same mount.The PKI paths are scoped to the
pki/mount by name rather than using a glob likepki*. A glob matches every PKI mount in the cluster — including mounts created by other teams — and grants the AI agent token the ability to delete root CA issuers or revoke certificates on mounts it should not touch. If you use a different mount name for your PKI engine, update thesys/mounts/pkiandpki/*paths in the policy to match.The
sys/mounts/pkipath allows the AI agent to enable the PKI engine for this tutorial. In production, a separate privileged token should enable mounts — not the AI agent's token.Create the Vault policy.
$ vault policy write vault-mcp-developer vault-mcp-policy.hcl Success! Uploaded policy: vault-mcp-developerA good practice is to store policy documents in version control.
Create a token attached to the
vault-mcp-developerpolicy.$ vault token create \ -policy=vault-mcp-developer \ -ttl=8h \ -display-name="vault-mcp-server"Example output:
Key Value --- ----- token hvs.CAESIG4x... token_accessor 4Kz8rT... token_duration 8h token_renewable true token_policies ["default" "vault-mcp-developer"] identity_policies [] policies ["default" "vault-mcp-developer"]The token auth method is the default auth method enabled for all Vault clusters at startup. However, you would typically not use this auth method in real world scenarios. For production use, choose an auth method allows your developers to authenticate to Vault such as the GitHub or LDAP auth method. You can configure the auth method to issue tokens with the
vault-mcp-developerpolicy attached. For autonomous agents, consider using a workload focused auth method such as OIDC with the A2A protocol.
Configure VS Code to use the Vault MCP server
(Persona: developer)
Now that Oliver has created a policy and token for the Vault MCP server, Danielle needs to make the token available in their development environment. This allows the development team to avoid hard coding secrets in MCP server configuration file.
Copy the
tokenvalue from the output and export it as an environment variable namedVAULT_MCP_TOKEN.$ export VAULT_MCP_TOKEN=hvs....Confirm the new token is valid and scoped to the
vault-mcp-developerpolicy.$ vault token lookup $VAULT_MCP_TOKEN | grep policies policies [default vault-mcp-developer]The token uses the
vault-mcp-developerpolicy you created, which scopes it to the necessary paths and capabilities for the AI agent.Create a
.vscodedirectory in the root of your workspace if one does not already exist.Create
.vscode/mcp.jsonwith the following configuration.{ "servers": { "vault-mcp-server": { "command": "docker", "args": [ "run", "-i", "--rm", "-e", "VAULT_ADDR", "-e", "VAULT_TOKEN", "hashicorp/vault-mcp-server" ], "env": { "VAULT_ADDR": "http://host.docker.internal:8200", "VAULT_TOKEN": "${env:VAULT_MCP_TOKEN}" }, "type": "stdio" } } }The
${env:...}references instruct VS Code to read values from the process environment at startup. The launcher script in the next section ensures VS Code inherits the correct Vault environment variables.For this tutorial, the MCP Server runs on the same Docker network as the Vault dev mode server. In production environments, update the
VAULT_ADDRenvironment variable to point to your Vault cluster. Verify the Docker configuration supports your operating system.
Launch VS Code with Vault environment variables
(Persona: developer)
The Vault MCP server binary reads its credentials from the mcp.json
configuration file. The launcher script validates your Vault
session, ensures a Vault token is available, and starts VS Code so the mcp.json
configuration does not use hard-coded secrets.
Create a file named
launch-vs-code.shin the root of your workspace.$ vi launch-vs-code.shPaste the following script into the file.
#!/usr/bin/env bash set -euo pipefail SCRIPT_NAME="$(basename "$0")" VAULT_BIN="${VAULT_BIN:-vault}" CODE_BIN="${CODE_BIN:-code}" WORKSPACE_PATH="" CODE_ARGS=() usage() { cat <<EOF Launch VS Code with Vault environment variables injected into the process. Usage: $SCRIPT_NAME [--workspace PATH] [--vault-bin PATH] [--code-bin PATH] [-- CODE_ARGS] Options: --workspace PATH Directory to open in VS Code (default: current directory) --vault-bin PATH Path to the vault binary (default: vault) --code-bin PATH Path to the VS Code binary (default: code) -h, --help Print this message Environment variables VAULT_ADDR, and VAULT_TOKEN must be exported before running this script. VS Code must be fully quit before running so that the environment variables take effect in the new process. EOF } die() { echo "error: $*" >&2; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"; } while (( $# )); do case "$1" in --workspace) WORKSPACE_PATH="${2?--workspace requires a value}"; shift 2 ;; --vault-bin) VAULT_BIN="${2?--vault-bin requires a value}"; shift 2 ;; --code-bin) CODE_BIN="${2?--code-bin requires a value}"; shift 2 ;; -h|--help) usage; exit 0 ;; --) shift; CODE_ARGS+=("$@"); break ;; *) die "unknown argument: $1" ;; esac done need "$VAULT_BIN" need "$CODE_BIN" [[ -n "${VAULT_ADDR:-}" ]] || die "VAULT_ADDR is not set." [[ -n "${VAULT_MCP_TOKEN:-}" ]] || die "VAULT_MCP_TOKEN is not set." "$VAULT_BIN" token lookup "$VAULT_MCP_TOKEN" >/dev/null 2>&1 \ || die "Vault token lookup failed. Check that VAULT_ADDR and VAULT_MCP_TOKEN are correct." # macOS names the VS Code process "Code"; adjust this check on other platforms pgrep -x "Code" >/dev/null 2>&1 \ && die "VS Code is running. Quit VS Code completely and re-run this script." [[ -n "$WORKSPACE_PATH" ]] || WORKSPACE_PATH="$PWD" (( ${#CODE_ARGS[@]} )) || CODE_ARGS=("$WORKSPACE_PATH") env \ VAULT_ADDR="$VAULT_ADDR" \ VAULT_MCP_TOKEN="$VAULT_MCP_TOKEN" \ "$CODE_BIN" --wait "${CODE_ARGS[@]}" # Revoke the MCP server token when the VS Code session ends "$VAULT_BIN" token revoke "$VAULT_MCP_TOKEN" >/dev/null 2>&1 \ && echo "Vault MCP server token revoked." \ || echo "Warning: token revocation failed. Run: vault token revoke \$VAULT_MCP_TOKEN"This script is one example of how to launch VS Code with the correct environment variables for the Vault MCP server. You can modify it to fit your needs or launch VS Code manually after exporting the environment variables.
Save and close the file.
Quit VS Code if it is running.
Make the script executable.
$ chmod +x launch-vs-code.shRun the script to start VS Code from the same terminal environment where you set the Vault environment variables.
$ ./launch-vs-code.sh &Trust the workspace if VS Code prompts you.
VS Code opens with
VAULT_MCP_TOKENset in the process environment. The Vault MCP server binary receives the value when Copilot invokes it.The script uses
code --wait, which blocks until you quit VS Code. When the session ends, the script automatically revokes the MCP server token so it cannot be reused after your working session is complete. If you close VS Code without using the launcher, revoke the token manually.$ vault token revoke "$VAULT_MCP_TOKEN"Open Chat from the Activity Bar or press
Cmd+Shift+I.Switch the chat mode to Agent using the selector at the bottom of the Chat panel.
Click the tools icon (slider) and confirm that Vault MCP server tools appear in the list. If you do not have the full listing of tools under vault-mcp-server as shown in the screenshot, click Update tools to refresh the listing.

If the tools are missing, confirm that
VAULT_MCP_TOKENwas set in the terminal before you ran the launcher script, quit VS Code and run the script again.
Manage secrets with GitHub Copilot
(Persona: developer)
The Vault MCP server is well-suited for the parts of secrets management that do not involve handling the credential values themselves:
- Planning secret structure
- Recommending path organization
- Verifying that secrets exist with the correct keys and metadata.
Write credential values using the Vault CLI, API, or UI - not the chat panel. Anything you type into Copilot leaves your Vault trust boundary.
Plan secret structure and write credentials
Open the Chat panel and select Agent mode.
Ask the agent to recommend a path and key structure for your application's database credentials.
I need to store database credentials for my application in the Vault KV v2 secret/ mount. Recommend a path and the key names I should use.Click Allow if VS Code prompts you to permit the MCP server to run.
The agent recommends a path and key names based on Vault conventions without handling any credential values using the Vault MCP server.
Example output:
The secret/ mount is confirmed as KV v2 and is currently empty. Here's my recommendation: Path: secret/data/app/<your-app-name>/database For example: secret/data/app/myapp/database This follows a common convention: <app-name>/<component>, keeping credentials organized by application and concern. Suggested keys: - username — the database user your application authenticates as - password — the database user's password - host — the database hostname or IP address - port — the database port (5432 for PostgreSQL, 3306 for MySQL) - database — the name of the database to connect to This structure keeps credentials grouped by application (myapp/) and type (database), making it straightforward to grant read access to only the paths a specific service needs.Write the credentials to Vault using the CLI in your terminal.
$ vault kv put secret/myapp/database \ username="appuser" \ host="db.internal.example.com" \ port="5432" \ database="appdb" \ password="j3ffAlb3rts0n"Example output:
======= Secret Path ======= secret/data/myapp/database ======= Metadata ======= Key Value --- ----- created_time 2026-05-15T21:18:46.219022712Z custom_metadata <nil> deletion_time n/a destroyed false version 1Ask the agent to confirm the secret was written with the correct structure. Request key names and metadata only — not the values.
Confirm that secret/myapp/database exists in Vault KV v2 and show me the key names and version metadata. Do not return the values.Example output:
The secret at secret/myapp/database exists. The key names are: - database - host - password - port - username To retrieve actual values for use in your application, use the Vault CLI or SDK rather than this chat panel.Use the same pattern for a third-party API integration. Ask the agent for a path structure first.
What path and key names should I use to store payment gateway API credentials alongside my database credentials under secret/myapp?Example output:
Your existing structure has secret/myapp/database, so follow the same pattern: Path: secret/myapp/payment-gateway Suggested keys: - api_key — your payment provider API key - endpoint — the API base URL - timeout_seconds — request timeout in seconds Placing integrations under secret/myapp/integrations/ separates third-party credentials from internal credentials and allows different policies to be applied to each group.Write the integration credentials using the CLI.
$ vault kv put secret/myapp/integrations/payment-gateway \ endpoint="https://api.payments.example.com" \ timeout_seconds="30" \ api_key="abc8647d-1492-s3as3m3-st33t"Example output:
================= Secret Path ================= secret/data/myapp/integrations/payment-gateway ======= Metadata ======= Key Value --- ----- created_time 2026-05-15T21:23:04.637488763Z custom_metadata <nil> deletion_time n/a destroyed false version 1
Audit the secrets hierarchy
Run a pre-release audit to verify the secrets your application depends on are present and up to date before you push a build.
List the full path hierarchy under the
secret/mount.List all secrets under the secret KV v2 mount and show the complete path hierarchy including nested paths.Example output:
Secrets stored under the secret/ mount: secret/ └── myapp/ ├── database └── integrations/ └── payment-gateway 2 secret paths found across 1 application prefix.Request metadata for each secret to check when it was last updated.
For each secret path under secret/myapp, show the key names (not values) and the last-updated timestamp from Vault metadata.Example output:
Secrets audit for secret/myapp: Path: secret/myapp/database Keys: database, host, password, port, username Updated: 2026-05-11T14:23:11Z Path: secret/myapp/integrations/payment-gateway Keys: api_key, endpoint, timeout_seconds Updated: 2026-05-11T14:31:45ZWithout leaving your IDE, you managed Vault secrets engines using natural language prompts and audited their structure and metadata.
Knowledge checks
A quiz to test your knowledge.
How does the Vault MCP server communicate with GitHub Copilot in VS Code?
🔘 Over a TCP port published on localhost
🔘 Through a HashiCorp-hosted relay service
🔘 Over a local STDIO connection through standard input/output
🔘 Using a WebSocket tunnel to the VS Code extension host
❌ Over a TCP port published on localhost
❌ Through a HashiCorp-hosted relay service
✅ Over a local STDIO connection through standard input/output
❌ Using a WebSocket tunnel to the VS Code extension host
The Vault MCP server runs in
stdiomode by default. It communicates through standard input and output streams, so no network port is opened. Only the VS Code process that spawned the binary can send requests to it.Why should you use a scoped Vault token rather than a root token with the Vault MCP server?
🔘 Root tokens expire after sixty minutes and cannot be renewed.
🔘 The MCP server requires a token display name that root tokens do not have.
🔘 A root token gives the AI agent unrestricted access to all Vault operations.
🔘 Root tokens cannot be passed to child processes via environment variables.
❌ Root tokens expire after sixty minutes and cannot be renewed.
❌ The MCP server requires a token display name that root tokens do not have.
✅ A root token gives the AI agent unrestricted access to all Vault operations.
❌ Root tokens cannot be passed to child processes via environment variables.
The Vault MCP server inherits whatever Vault token is in its environment. A root token has no capability restrictions, so an AI agent using one could delete mounts, modify policies, or read any secret. A scoped token bounds the blast radius of unintended or hallucinated operations.
What does setting
ENABLE_VAULT_OPERATIONS=falsedo to the Vault MCP server?Setting
ENABLE_VAULT_OPERATIONStofalsedisables the tools that perform write operations in Vault — such as creating, updating, or deleting secrets and mounts. The AI agent is limited to read-only queries against Vault. This is useful in environments where you want to allow secrets auditing or certificate inspection but do not want the AI to be able to modify Vault state.
Summary
In this tutorial, you configured VS Code to launch the Vault MCP server container, created a least-privilege Vault policy and token, and connected the MCP server to Copilot in VS Code.
The launcher script is one possible solution to inject the correct Vault
environment variables to start the MCP server without hard coding secret values
in the mcp.json configuration file.
You then used natural language prompts to store and audit application secrets in the KV v2 secrets engine.
Bringing Vault operations into the editor removes the context switches that slow development velocity and can lead developers to work around secrets management rather than through it. Keeping the token scoped to what the agent needs ensures the convenience of AI-assisted workflows does not come at the cost of security.
Additional resources
- Vault MCP server overview — architecture, transport options, and supported operations.
- Deploy the Vault MCP server — Docker and source installation options alongside the binary method.
- Vault MCP server security model — threat model and recommendations for local deployments.
- Prompt the Vault MCP server — examples and heuristics for effective tool routing.