skeleton-mcp
This server provides secure management of application configuration (via Postgres) and secrets (via HashiCorp Vault), with built-in authorization and redaction controls.
Connection & Health
connection_info— Retrieve MCP server, Vault, and Postgres connection details with sensitive values redactedvault_connection_info— View active Vault configuration without exposing secret valueshealthcheck— Run live connectivity checks against Postgres and Vault
Configuration Management (Postgres)
list_configs— List configuration records, optionally filtered by key prefixget_config— Read a specific configuration value by keyset_config(mutating) — Create or update a configuration key-value pairdelete_config(mutating) — Delete a configuration record by key
Secret Management (Vault KV v2)
list_secrets— List child keys under a given Vault path prefixget_secret— Read a secret by path (output redacted by default unlessMCP_ALLOW_SENSITIVE_OUTPUT=true)set_secret(mutating) — Create or update a secret at a Vault path (writes are retried with exponential backoff)delete_secret(mutating) — Delete a secret at a given Vault path
Security & Access Control
Mutating tools require an
authorizationKeywhenMCP_ADMIN_AUTH_KEYis configuredSensitive output is redacted by default
HTTP transport (
/mcp,/healthz) supports bearer token, OAuth2, or Vault multi-user token authentication, with rate limiting and IP/origin restrictionsSupports
stdio,http, or combined transport modesDesigned as an extensible skeleton for adding new domain services and custom MCP tools
Provides tools for reading and writing secrets in HashiCorp Vault, including listing, getting, setting, and deleting secrets, with retry queues and authorization for mutating operations.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@skeleton-mcplist all configs"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
skeleton-mcp
Node.js MCP skeleton with:
Vault-backed secret management
Postgres-backed configuration management
Security and operational defaults for production-style patterns
Purpose
This repository is a starter template for building an MCP server that needs:
Multi-user support.
Secret reads and writes through Vault
Config reads and writes through Postgres
Tool-level authorization for mutating operations
Redacted tool output by default
Basic reliability controls for external secret writes
Design requirements:
Secrets are persistent in Vault.
Configuration is persistent in Postgres.
User-scoped behavior is mandatory, with default-user fallback where supported.
Related MCP server: mcp-server-toolkit
Skeleton Architecture
Runtime flow:
src/index.js boots the app, creates services, and connects MCP stdio transport.
src/config/env.js loads and validates environment configuration.
src/services/configStore.js handles Postgres persistence.
src/services/vault.js handles Vault operations and write retry queue.
src/services/security.js redacts sensitive fields.
src/mcp/server.js registers MCP tools and applies auth/error wrappers.
src/http/server.js exposes MCP over HTTP with auth, limits, and access logs.
src/http/index.js boots the dedicated HTTP MCP process.
src/start-both.js starts stdio and HTTP as separate child processes.
Local infrastructure:
docker-compose.yml runs Postgres and Vault for local development.
docker-compose.external.yml runs only the MCP app against external Postgres and Vault services.
initdb/001_config.sh creates and seeds the app-prefixed config table.
Registering The MCP Server
This repository can be registered with MCP clients in either stdio mode or HTTP mode.
For local development, stdio is the simplest option:
{
"mcpServers": {
"skeleton-mcp": {
"command": "npm",
"args": ["run", "start:stdio"],
"cwd": "/Users/lesterjohn/Documents/GitHub/skeleton-mcp"
}
}
}For HTTP-capable clients, use npm run start:http and point the client at the /mcp endpoint.
Codex
Use stdio for Codex unless you specifically need HTTP. Add the server to your Codex MCP configuration using the local workspace path:
Config file:
~/.codex/config.tomlTransport: stdio
{
"mcpServers": {
"skeleton-mcp": {
"command": "npm",
"args": ["run", "start:stdio"],
"cwd": "/Users/lesterjohn/Documents/GitHub/skeleton-mcp"
}
}
}If you prefer HTTP, run npm run start:http in this repository and configure Codex to send MCP requests to http://127.0.0.1:3000/mcp.
VS Code
Use stdio in VS Code for local workspace access, or HTTP if your setup routes MCP servers over a local endpoint:
Config file:
.vscode/mcp.jsonTransport: stdio or HTTP
{
"command": "npm",
"args": ["run", "start:stdio"],
"cwd": "/Users/lesterjohn/Documents/GitHub/skeleton-mcp"
}If your VS Code setup uses HTTP transport, point it at http://127.0.0.1:3000/mcp after starting npm run start:http.
Claude
For Claude Desktop, use stdio and add an MCP server entry that launches the process from this repository:
Config file:
~/Library/Application Support/Claude/claude_desktop_config.jsonTransport: stdio
{
"mcpServers": {
"skeleton-mcp": {
"command": "npm",
"args": ["run", "start:stdio"],
"cwd": "/Users/lesterjohn/Documents/GitHub/skeleton-mcp"
}
}
}If you are using a Claude setup that supports MCP over HTTP, point it at http://127.0.0.1:3000/mcp.
Tool Catalog
All tools return MCP text content containing JSON. Success payloads follow this shape:
{
"ok": true,
"status": 200,
"data": {}
}Errors follow this shape and set MCP isError=true:
{
"ok": false,
"status": 401,
"error": "Unauthorized: invalid authorizationKey for mutating API operation"
}If MCP_ADMIN_AUTH_KEY is configured, mutating tools (and mutating service_api_request calls) require authorizationKey.
service_query_suggestion
Category: advisory (read-only)
Risk: low
Use when: you want schema discovery for all MCP tools and recommendations on what tool sequence to run for an intent/workflow
Do not use when: you already know the exact specialized tool and validated endpoint path
Required permissions/prerequisites: none
Environment behavior:
Detects whether a workflow is mutating from
operationTypeormethodReports whether
authorizationKeyis required for the suggested mutating call whenMCP_ADMIN_AUTH_KEYis configured
Parameters:
intent(optional string)operationType(optional enum:discover|read|mutate|suspend_logging|resume_logging|get_drive_gpx|scoped)method(optional string, normalized to uppercase)path(optional string, normalized to leading slash)includeExamples(optional boolean, defaulttrue)includeToolSchemas(optional boolean, defaulttrue)
Expected response shape:
data.summary: intent + mutating/auth flagsdata.recommendedOrder: ordered tool recommendations with reasonsdata.safetyChecks: checklist for safer executiondata.toolSchemas: schema-like catalog for all operational tools (unless disabled)data.examples: baseline read/mutate examples (unless disabled)
Common failures:
500for unexpected internal recommendation errors
Recommended tools:
Prerequisite: none
Follow-up: any tool listed in
data.recommendedOrder
Example:
{
"name": "service_query_suggestion",
"arguments": {
"intent": "discover endpoints then suspend logging for car 42",
"operationType": "suspend_logging",
"method": "PUT",
"path": "/api/car/42/logging/suspend"
}
}Recommended Playbooks
Intent | Suggested tool sequence | Notes |
Verify runtime and service connectivity |
| Baseline check before any operational request. |
Discover supported routes before custom request |
| Use discovered paths to reduce schema/path mistakes. |
Suspend logging for a car |
| If |
Resume logging for a car |
| Prefer specialized tool over generic mutate calls. |
Export drive GPX |
| Dedicated GPX path and payload handling. |
Execute a generic read request |
| Safer for non-destructive endpoint exploration. |
Execute a generic mutating request |
| PUT |
Inspect user/app scope metadata |
| Use scope details for app/user-aware workflows. |
service_connection_info
Category: read-only
Risk: low
Use when: you need runtime MCP + target-service connection metadata (server name/version, auth-gate status, scope model, service base URL/timeout)
Do not use when: you need health verification or endpoint discovery; prefer
service_health_checkorservice_list_endpointsRequired permissions/prerequisites: none
Environment behavior: reports current process config (
APP_NAME,MCP_CONFIG_DEFAULT_USER_ID, and admin-auth configured state)Parameters: none
Expected response shape:
data.server: server metadata andscopeModeldata.service: service client connection info
Common failures:
500if service client metadata retrieval fails
Recommended tools:
Prerequisite: none
Follow-up:
service_health_check,service_list_endpoints
Example:
{
"name": "service_connection_info",
"arguments": {}
}service_scope_info
Category: read-only
Risk: low
Use when: you need app/user scoping details used for Postgres and Vault paths before making scoped calls
Do not use when: you only need default scope metadata;
service_connection_infoalready includes default scope modelRequired permissions/prerequisites: none
Environment behavior: defaults
userIdtoMCP_CONFIG_DEFAULT_USER_IDwhen omittedParameters:
userId(optional string, non-empty)
Expected response shape:
data.appNamedata.userIddata.userIdPathSegmentdata.postgres.tableName,data.postgres.primaryKey,data.postgres.scopedata.vault.tokenIndexPath,data.vault.scope
Common failures:
500for unexpected normalization/path construction errors
Recommended tools:
Prerequisite: none
Follow-up:
service_api_request(for scoped API calls)
Example:
{
"name": "service_scope_info",
"arguments": {
"userId": "default"
}
}service_list_endpoints
Category: read-only
Risk: low
Use when: you want a safe discovery list of implemented/documented target endpoints
Do not use when: you need endpoint liveness; use
service_health_checkRequired permissions/prerequisites: none
Environment behavior: output depends on service adapter implementation bundled with current build
Parameters: none
Expected response shape:
data.endpoints: adapter-provided endpoint list
Common failures:
500if endpoint catalog cannot be produced
Recommended tools:
Prerequisite:
service_connection_infoFollow-up:
service_api_request,service_health_check
Example:
{
"name": "service_list_endpoints",
"arguments": {}
}service_health_check
Category: read-only
Risk: low
Use when: you need reachability/health validation before operational calls
Do not use when: you need to retrieve business data; use specific service tools
Required permissions/prerequisites: network path to target service must be available
Environment behavior: uses configured service base URL and auth mode from runtime env
Parameters: none
Expected response shape:
data: adapter-specific health payload
Common failures:
5xxif target service is down/unreachable401/403when upstream service credentials are invalid
Recommended tools:
Prerequisite:
service_connection_infoFollow-up:
service_list_endpoints,service_api_request
Example:
{
"name": "service_health_check",
"arguments": {}
}service_suspend_logging
Category: mutating
Risk: high
Use when: you intentionally need to disable logging for a specific car resource
Do not use when: you are exploring state only; use read-only tools first
Required permissions/prerequisites:
If
MCP_ADMIN_AUTH_KEYis set,authorizationKeymust matchCaller should validate target id and operational impact
Environment behavior: authorization enforcement is env-driven (
MCP_ADMIN_AUTH_KEY)Parameters:
carId(required, non-empty string or positive integer)authorizationKey(optional unless admin key is configured)
Expected response shape:
data: adapter-specific suspend result
Common failures:
401invalid/missingauthorizationKeywhen required404car id not found409invalid state transition (already suspended)5xxupstream service failure
Safety warning: this changes operational behavior; confirm rollback path before invoking
Recommended tools:
Prerequisite:
service_health_check,service_list_endpointsFollow-up:
service_resume_logging,service_api_request(state verification)
Example:
{
"name": "service_suspend_logging",
"arguments": {
"carId": 42,
"authorizationKey": "<admin-key-if-required>"
}
}service_resume_logging
Category: mutating
Risk: high
Use when: you need to restore logging after a prior suspension
Do not use when: you only need status checks
Required permissions/prerequisites:
If
MCP_ADMIN_AUTH_KEYis set,authorizationKeymust matchLogging was previously suspended for the target resource
Environment behavior: authorization enforcement is env-driven (
MCP_ADMIN_AUTH_KEY)Parameters:
carId(required, non-empty string or positive integer)authorizationKey(optional unless admin key is configured)
Expected response shape:
data: adapter-specific resume result
Common failures:
401invalid/missingauthorizationKeywhen required404car id not found409invalid state transition (not suspended)5xxupstream service failure
Safety warning: operational state change; coordinate with incident/runbook procedures
Recommended tools:
Prerequisite:
service_health_checkFollow-up:
service_api_request(state verification)
Example:
{
"name": "service_resume_logging",
"arguments": {
"carId": "42",
"authorizationKey": "<admin-key-if-required>"
}
}service_get_drive_gpx
Category: read-only
Risk: medium (may contain sensitive location/history data)
Use when: you need a GPX export for a specific drive id
Do not use when: you only need summary metadata; use a lighter endpoint via
service_api_requestif availableRequired permissions/prerequisites: drive id must exist and caller must be permitted by upstream service
Environment behavior: uses configured service auth and base URL
Parameters:
driveId(required, non-empty string or positive integer)
Expected response shape:
data: adapter-specific GPX payload/metadata
Common failures:
404drive id not found401/403upstream authorization failure5xxupstream service failure
Recommended tools:
Prerequisite:
service_health_checkFollow-up:
service_api_requestfor related resource lookups
Example:
{
"name": "service_get_drive_gpx",
"arguments": {
"driveId": 123
}
}service_api_request
Category: read-only or mutating (depends on
method)Risk: variable; high for
POST|PUT|PATCH|DELETEUse when: you need flexible access to supported target-service endpoints not covered by specialized tools
Do not use when: a specialized tool exists (
service_suspend_logging,service_resume_logging,service_get_drive_gpx) because those provide clearer intent and safer contractsRequired permissions/prerequisites:
Mutating methods require
authorizationKeyifMCP_ADMIN_AUTH_KEYis setpathmust target valid adapter-supported route behavior
Environment behavior:
methodis normalized to uppercasepathis normalized to leading slash formatauth and host safeguards are enforced by adapter
Parameters:
method(required string, e.g.GET,POST)path(required string;/-prefixed normalization applied)query(optional object: string keys, scalar values string|number|boolean)body(optional JSON value)headers(optional object: string keys and string values)authorizationKey(optional unless mutating call requires it)
Expected response shape:
data: adapter HTTP response payload
Common failures:
400invalid path/query/body for upstream API401invalid/missingauthorizationKeyfor required mutating call403upstream access denied404endpoint/resource not found429upstream rate limiting5xxupstream/transport failure
Safety warning: treat mutating methods as destructive-capable operations; verify target path, method, and body before invocation
Recommended tools:
Prerequisite:
service_list_endpoints,service_health_checkFollow-up: specialized read tools for validation, or another
service_api_requestGET for post-change verification
Examples:
{
"name": "service_api_request",
"arguments": {
"method": "GET",
"path": "/api/car/42"
}
}{
"name": "service_api_request",
"arguments": {
"method": "PATCH",
"path": "/api/car/42",
"body": {
"nickname": "track-ready"
},
"authorizationKey": "<admin-key-if-required>"
}
}Security Behavior
Sensitive fields are redacted unless MCP_ALLOW_SENSITIVE_OUTPUT=true.
Mutating operations can be access controlled with MCP_ADMIN_AUTH_KEY.
Vault write operations are serialized through an internal queue and retried with exponential backoff.
Environment Variables
Core:
APP_NAME
MCP_SERVER_NAME
MCP_SERVER_VERSION
MCP_ALLOW_SENSITIVE_OUTPUT
MCP_ADMIN_AUTH_KEY
MCP_TRANSPORT_MODE (
stdio,http, orboth)MCP_CONFIG_DEFAULT_USER_ID
MCP_TOKEN_ROTATION_DEFAULT_INTERVAL_MS
MCP_TOKEN_ROTATION_USER_INTERVAL_CONFIG_KEY
MCP_VAULT_AGENT_AUTH_MODE_CONFIG_KEY
MCP_VAULT_AGENT_TOKEN_FILE_PATH_CONFIG_KEY
MCP_VAULT_AGENT_LISTENER_ADDR_CONFIG_KEY
HTTP transport:
MCP_HTTP_HOST
MCP_HTTP_PORT
MCP_HTTP_PATH
MCP_HTTP_HEALTH_PATH
MCP_HTTP_AUTH_MODE (
token,oauth2,both)MCP_HTTP_TOKEN_SOURCE (
vault,env)MCP_HTTP_AUTH_TOKENS (comma-separated bearer tokens)
MCP_HTTP_TRUST_PROXY
MCP_HTTP_ALLOWED_ORIGINS (comma-separated)
MCP_HTTP_ALLOWED_IPS (comma-separated)
MCP_HTTP_MAX_BODY_BYTES
MCP_HTTP_RATE_LIMIT_WINDOW_MS
MCP_HTTP_RATE_LIMIT_MAX_REQUESTS
MCP_HTTP_VAULT_TOKEN_INDEX_PATH
MCP_HTTP_VAULT_TOKEN_DEFAULT_USER_ID
MCP_HTTP_VAULT_TOKEN_REQUIRED_SCOPES
MCP_HTTP_VAULT_TOKEN_REQUIRED_AUDIENCE
MCP_HTTP_VAULT_TOKEN_CACHE_TTL_MS
MCP_HTTP_OAUTH2_INTROSPECTION_URL
MCP_HTTP_OAUTH2_CLIENT_ID
MCP_HTTP_OAUTH2_CLIENT_SECRET
MCP_HTTP_OAUTH2_REQUIRED_SCOPES
MCP_HTTP_OAUTH2_REQUIRED_AUDIENCE
MCP_HTTP_OAUTH2_TIMEOUT_MS
MCP_HTTP_OAUTH2_CACHE_TTL_MS
MCP_HTTP_TLS_ENABLED
MCP_HTTP_TLS_CERT_PATH
MCP_HTTP_TLS_KEY_PATH
Postgres:
POSTGRES_HOST
POSTGRES_PORT
POSTGRES_DB
POSTGRES_USER
POSTGRES_PASSWORD
Postgres config model:
Configuration data is app-scoped in
${APP_NAME}_configand user-scoped with composite key(user_id, key).MCP config tools accept optional
userId; when omitted,MCP_CONFIG_DEFAULT_USER_IDis used.Seed records include:
default/sample.featuredefault/app.defaultsfor future default parameters.default/token.rotation.intervalMsdefault/vault.agent.auth.modedefault/vault.agent.tokenFilePathdefault/vault.agent.listener.addr
Vault:
VAULT_ADDR
VAULT_TOKEN
VAULT_AGENT_ENABLED
VAULT_AGENT_AUTH_MODE (
none,file,listener,both)VAULT_AGENT_TOKEN_FILE_PATH
VAULT_AGENT_LISTENER_ENABLED
VAULT_AGENT_LISTENER_ADDR
VAULT_UNSEAL_KEY
VAULT_KV_MOUNT
VAULT_WRITE_RETRY_ATTEMPTS
VAULT_WRITE_RETRY_BASE_DELAY_MS
VAULT_WRITE_RETRY_MAX_DELAY_MS
Naming defaults:
APP_NAMEdefaults toskeleton.The Postgres config table defaults to
${APP_NAME}_config.The Vault token index path defaults to
${APP_NAME}/users/${MCP_HTTP_VAULT_TOKEN_DEFAULT_USER_ID}/http/auth/token-index.Set only
APP_NAMEto rename the app-scoped Vault/Postgres schema across local and external stores.
Reference values are in .env.example.
Quick Start
Install dependencies.
Copy .env.example to .env.
Start local services with docker compose up -d.
Resolve the managed unseal key:
npm run vault:unseal-key -- --json.Initialize and unseal local Vault (first run):
docker exec -e VAULT_ADDR=http://127.0.0.1:8200 skeleton-mcp-vault vault operator init -key-shares=1 -key-threshold=1 -format=json
docker exec -e VAULT_ADDR=http://127.0.0.1:8200 skeleton-mcp-vault vault operator unseal <unseal_key_from_init_or_env>Seed a test secret in Vault.
Start the MCP server with npm start.
Run tests with npm test.
External Services Mode
Use this mode when Vault and Postgres are already managed outside this repository.
Required environment variables:
POSTGRES_HOST,POSTGRES_PORT,POSTGRES_DB,POSTGRES_USER,POSTGRES_PASSWORDVAULT_ADDR,VAULT_TOKEN
Run the app-only compose stack:
docker compose -f docker-compose.external.yml up -dNotes:
The app still uses Vault for secrets and Postgres for config.
The external stack is the same MCP HTTP container, but it skips local Postgres/Vault containers.
If you keep Vault sealed, the app will still require whatever unseal process your external Vault uses.
Test Coverage Notes
Current automation includes listener-related coverage for Vault Agent runtime resolution.
tests/vault-agent-runtime.test.js validates:
listener mode resolution from Postgres defaults
both mode resolution (listener + file)
fallback to environment values when database mode is invalid
Transport scripts:
# stdio only (default)
npm run start:stdio
# HTTP transport only
npm run start:http
# run stdio + HTTP as two processes
npm run start:bothHTTP MCP Endpoint
Default endpoint values:
MCP URL:
http://127.0.0.1:3000/mcpHealth URL:
http://127.0.0.1:3000/healthz
HTTP transport security controls:
Every
/mcprequest requiresAuthorization: Bearer <token>.For
MCP_HTTP_AUTH_MODE=token, setMCP_HTTP_TOKEN_SOURCE=vaultto validate tokens from Vault.For
MCP_HTTP_AUTH_MODE=oauth2, bearer tokens are validated by OAuth2 introspection.For
MCP_HTTP_AUTH_MODE=both, either token strategy can authorize requests.Mutating tools still require
authorizationKeywhenMCP_ADMIN_AUTH_KEYis set.Request limits are enforced with:
MCP_HTTP_MAX_BODY_BYTESMCP_HTTP_RATE_LIMIT_WINDOW_MSMCP_HTTP_RATE_LIMIT_MAX_REQUESTS
Optional network restrictions:
MCP_HTTP_ALLOWED_ORIGINSMCP_HTTP_ALLOWED_IPS
Vault Multi-User Token Model
Store HTTP bearer tokens in Vault at MCP_HTTP_VAULT_TOKEN_INDEX_PATH.
If unset, seeding tools default to ${APP_NAME}/users/<user_id>/http/auth/token-index.
Default-user fallback behavior:
MCP_HTTP_VAULT_TOKEN_DEFAULT_USER_IDdefaults todefault.If no non-default users exist in the token index, the default user is always used as fallback.
Supported index shape:
{
"tokens": {
"<sha256(token)>": {
"userId": "user-123",
"tokenId": "tok-123",
"active": true,
"scopes": ["mcp:invoke", "mcp:read"],
"audience": ["codex", "claude"],
"expiresAt": "2026-12-31T23:59:59Z"
}
}
}Notes:
Store only token hashes in Vault index data, never plaintext tokens.
MCP_HTTP_VAULT_TOKEN_REQUIRED_SCOPESandMCP_HTTP_VAULT_TOKEN_REQUIRED_AUDIENCEenforce policy checks.This keeps secrets in Vault under the app-prefixed root while configuration remains in the app-prefixed Postgres table.
Vault HTTP Token Seeding
Use the helper script to generate an opaque bearer token and store it in the Vault user token structure:
npm run vault:seed-http-token -- --user-id default --jsonUseful options:
--user-id <id>: Vault user to seed.--token-id <id>: Optional token id stored with the entry.--scopes <list>: Comma or space separated scopes.--audience <list>: Comma or space separated audience values.--expires-at <value>: Optional ISO timestamp or unix seconds.--path <vault-path>: Override the token index path.
The script writes the token record under the app-prefixed user structure and mirrors the token in the top-level token map for compatibility.
If you need to reseed a user, run the script again with the same --user-id and a new --token-id.
Vault OAuth Token Seeding
Use the helper script to store a provided OAuth access token in the Vault user token structure:
npm run vault:seed-oauth-token -- --token "$OAUTH_ACCESS_TOKEN" --user-id default --jsonUseful options:
--token <value>: OAuth access token to seed.--user-id <id>: Vault user to seed.--token-id <id>: Optional token id stored with the entry.--scopes <list>: Comma or space separated scopes.--audience <list>: Comma or space separated audience values.--expires-at <value>: Optional ISO timestamp or unix seconds.--path <vault-path>: Override the token index path.
The script stores the provided token under the app-prefixed user structure, keeps the top-level token map aligned, and marks the entry as oauth2 in Vault metadata.
MCP Tool
The same capability is exposed as an MCP tool for controlled setup workflows:
vault_seed_http_token: generate a bearer token and store it in the Vault HTTP token index for a user.vault_seed_oauth_token: store a provided OAuth access token in the Vault HTTP token index for a user.
For both tools, include app/user scope in requests so clients can reason about target storage:
appNamedetermines app-level namespace defaults.userIddetermines user-level namespace under${APP_NAME}/users/<user_id>/....
The tool requires authorizationKey when MCP_ADMIN_AUTH_KEY is configured.
Vault Token Lifecycle MCP Tools
The skeleton exposes node-vault token lifecycle methods as MCP tools:
token_lookup_self->tokenLookupSelftoken_renew_self->tokenRenewSelftoken_create->tokenCreatetoken_revoke->tokenRevoketoken_revoke_self->tokenRevokeSelf
These tools are intended for controlled operational usage and are guarded by admin authorization when MCP_ADMIN_AUTH_KEY is configured.
Vault Agent Auto-Auth and Token Renewal
Vault Agent can own token auth/renewal while this service reads the sink token file.
Enable with
VAULT_AGENT_ENABLED=trueChoose auth mode with
VAULT_AGENT_AUTH_MODE:file: use Vault Agent token sink filelistener: use Vault Agent listener endpointboth: enable listener operations and file-based token read workflows
Configure sink file path with
VAULT_AGENT_TOKEN_FILE_PATHEnable listener with
VAULT_AGENT_LISTENER_ENABLED=trueConfigure listener with
VAULT_AGENT_LISTENER_ADDRUse
vault_agent_token_readwhen application workflows need token sink visibility
When Vault Agent mode is enabled:
File mode refreshes token state from the configured token sink path.
Listener mode routes Vault operations through the configured Vault Agent listener.
Both mode supports listener operations and token sink read workflows.
Option 3: Postgres-Backed Non-Secret Vault Agent Settings
This skeleton supports storing non-secret Vault Agent runtime pointers/settings in Postgres while keeping token material in Vault.
Runtime settings are read from default user config scope (
MCP_CONFIG_DEFAULT_USER_ID).Key names are configurable with:
MCP_VAULT_AGENT_AUTH_MODE_CONFIG_KEYMCP_VAULT_AGENT_TOKEN_FILE_PATH_CONFIG_KEYMCP_VAULT_AGENT_LISTENER_ADDR_CONFIG_KEY
Recommended values in Postgres:
vault.agent.auth.modevault.agent.tokenFilePathvault.agent.listener.addr
Rotation Time Configuration
Rotation interval supports both global defaults and user-scoped overrides:
Global default env variable:
MCP_TOKEN_ROTATION_DEFAULT_INTERVAL_MSUser-scoped config key name:
MCP_TOKEN_ROTATION_USER_INTERVAL_CONFIG_KEY(defaulttoken.rotation.intervalMs)
Effective value resolution is:
User-scoped Postgres config (
userId+ key)Default user Postgres config (
default+ key)Global env default
Use token_rotation_config tool to inspect the resolved rotation interval for a user scope.
Minimal remote call example:
curl -i http://127.0.0.1:3000/mcp \
-H "Authorization: Bearer replace-me-token" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": { "name": "client", "version": "1.0.0" }
}
}'HTTPS Deployment Choice
This repository uses a reverse proxy (recommended): terminate TLS at a reverse proxy or load balancer.
Keep this app on internal HTTP.
Enforce HTTPS, client allowlists, and edge-level controls at the proxy/LB.
Forward traffic to
MCP_HTTP_HOST:MCP_HTTP_PORT.Keep
MCP_HTTP_TLS_ENABLED=falsein this process mode.
Popular patterns include Nginx, Traefik, Envoy, ALB/NLB, or Cloudflare Tunnel in front of /mcp.
Vault Production Migration (Raft)
The repository now includes a Vault production migration scaffold under vault-production:
vault-production/config/vault.hcl: Raft-backed Vault server configuration.
vault-production/docker-compose.vault-prod.yml: Compose definition for Vault in server mode (non-dev).
vault-production/scripts/convert-dev-to-prod.sh: Script to export dev KV data, start Raft Vault, initialize/unseal, and import secrets.
vault-production/scripts/bootstrap-post-conversion.sh: Script to enable audit, write policy, configure AppRole, and emit service credentials.
scripts/vault-unseal-key.js: Script to resolve unseal key from
VAULT_UNSEAL_KEYorsrc/config/vault.unseal.key.json.vault-production/README.md: Detailed migration notes and options.
Managed unseal key flow:
VAULT_UNSEAL_KEYis optional and can be injected at runtime.If
VAULT_UNSEAL_KEYis not set,npm run vault:unseal-keyreadssrc/config/vault.unseal.key.json.If the key file is missing or empty, a 24-character key is generated and saved to
src/config/vault.unseal.key.json.Both compose stacks run a one-shot
vault-unseal-key-initservice before Vault startup to ensure key material exists.
Run the conversion:
bash vault-production/scripts/convert-dev-to-prod.sh --init-keys-out vault-production/backups/vault-init.jsonCommon options:
# Use a different KV mount
bash vault-production/scripts/convert-dev-to-prod.sh --mount secret
# Migrate infra only (skip data movement)
bash vault-production/scripts/convert-dev-to-prod.sh --skip-export --skip-import
# Use when Raft Vault is already initialized
bash vault-production/scripts/convert-dev-to-prod.sh --skip-init
# Explicitly set key file path used by convert script
bash vault-production/scripts/convert-dev-to-prod.sh --unseal-key-path src/config/vault.unseal.key.json
# Post-conversion hardening bootstrap (audit, policy, AppRole)
bash vault-production/scripts/bootstrap-post-conversion.sh --vault-token <root_or_admin_token>
# CI-friendly machine output
bash vault-production/scripts/bootstrap-post-conversion.sh \
--vault-token <root_or_admin_token> \
--output jsonVS Code Agent Structure
This repository includes a project agent structure for adapting the skeleton to additional service-backed MCP implementations:
agent/README.md: Overview of agent assets.
agent/playbooks/service-onboarding.md: Step-by-step onboarding checklist.
agent/templates/service-spec.md: Request template for describing new service integrations.
Workspace custom agent:
Use this custom agent when you want GitHub Copilot in VS Code to:
Configure new service adapters under
src/services.Register matching MCP tools in
src/mcp/server.js.Update env validation in
src/config/env.js.Preserve authorization and redaction behavior.
Add tests and documentation updates.
Test Coverage
Integration tests in tests/server.integration.test.js cover:
Healthcheck behavior
Authorization on mutating tools
Redaction behavior for secret output
HTTP transport tests in tests/http.integration.test.js cover:
Unauthorized requests are rejected
Authorized MCP initialization succeeds
Internal failures return JSON-RPC-compatible error responses
Health endpoint behavior
Vault token auth tests in tests/vault-token-auth.test.js cover:
Multi-user token index lookup by SHA-256 hash
Inactive token rejection
Scope/audience-aware authorization inputs
Production migration tests in tests/vault-production.test.js cover:
Presence of Vault production scaffold files
Raft config expectations
Non-dev Vault compose command validation
Conversion/bootstrap script help and bash syntax checks
Extend The Skeleton
Add domain services under src/services.
Register new tools in src/mcp/server.js.
Add corresponding tests under tests.
Keep mutating tools behind authorization checks.
Keep secret-bearing fields redacted by default.
Notes
docker-compose.yml now runs Vault with Raft-backed storage for local persistence.
The managed key script is an automation helper and not a Vault KMS/HSM auto-unseal backend.
The migration scaffold starts with bootstrap-friendly defaults and still requires TLS, production auth methods, and credential rotation before real production use.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceA production-ready Python template for building MCP servers with enterprise features including registry integration, configuration management, structured logging, and extensible patterns for tools, resources, and prompts.Last updatedMIT
- Alicense-qualityDmaintenanceProduction-ready MCP server starter with authentication, observability, and a plugin system for building and deploying MCP servers quickly.Last updatedMIT
- Alicense-qualityBmaintenanceA production-ready MCP server template with OAuth 2.1, RBAC, and audit logging for building secure, observable tool servers.Last updatedMIT
- Flicense-qualityDmaintenanceA starter template for building MCP servers. It provides a clean foundation for creating custom tools, resources, and prompts for AI assistants.Last updated17
Related MCP Connectors
MCP server for managing Prisma Postgres.
MCP server for interacting with the Supabase platform
An MCP server for Arcjet - the runtime security platform that ships with your AI code.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/LesterAJohn/skeleton-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server