yaml-mcp-server
🔐 MCP gateway with declarative YAML tools and a pluggable approval system for safe model actions.

🇷🇺 俄语版本: README_RU.md
yaml-mcp-server 是用于读取YAML‑DSL以定义工具和资源的集群的单个MCP服务器, 执行审批者链,并返回严格结构化的响应。
🎯 想法和动机
服务器启用 安全执行 通过要求 通过可插入的审批者(HTTP/Shell/limits)进行明确批准。
✅ 主要特点
- MCP服务器(HTTP/stdio),带有从YAML‑DSL创建的工具。
- 每个工具的订购批准链(限制→ 外壳→ HTTP等)。
- 带有webhook回调的HTTP执行器(同步/异步)。
- 可选的幂等性缓存,用于重复调用。
- 严格响应合同:
status,decision,reason,correlation_id. - 健康终点:
/healthz,/readyz. - 启动前使用env检查进行YAML模板化。
🔗 相关存储库
telegram-approver--审批流程电报审批人:https://github.com/codex-k8s/telegram-approvercodexctl--用于环境和Codex工作流的CLI编排器:https://github.com/codex-k8s/codexctlproject-example--带有现成清单的Kubernetes项目示例:https://github.com/codex-k8s/project-example
📦 安装
去 >= 1.25.5 是必需的(参见 go.mod).
go install github.com/codex-k8s/yaml-mcp-server/cmd/yaml-mcp-server@latest🚀 快速开始
export YAML_MCP_CONFIG=/path/to/config.yaml
export YAML_MCP_LANG=en
export YAML_MCP_LOG_LEVEL=info
yaml-mcp-server默认MCP HTTP端点: http://localhost:8080/mcp.
嵌入式配置
使用从以下位置嵌入的配置 configs/,通过:
yaml-mcp-server --embedded-config github_secrets_postgres_k8s.yaml
yaml-mcp-server --embedded-config github_review.yaml
yaml-mcp-server --embedded-config telegram_feedback.yaml带有预配置配置的Docker镜像发布在GitHub容器注册表中(请参阅 docker/mcp-secrets-postgres-k8s.Dockerfile 和 docker/mcp-github-review.Dockerfile)例如 ghcr.io/codex-k8s/yaml-mcp-server-secrets-postgres-k8s:v1.2.0.
🔌 连接到Codex(CLI/IDE)
Codex将MCP配置存储在 ~/.codex/config.toml。您还可以按项目范围使用 .codex/config.toml 对于值得信赖的项目。CLI和IDE扩展共享相同的配置。
选项1——通过CLI
codex mcp add github_secrets_postgres_k8s_mcp --url http://localhost:8080/mcp
codex mcp list添加后,请确保设置 tool_timeout_sec 在 config.toml 因此,食品法典委员会不会终止漫长的审批流程 客户端(秒)。
选项2——通过config.toml
[mcp_servers.github_secrets_postgres_k8s_mcp]
url = "http://localhost:8080/mcp"
tool_timeout_sec = 3600如果服务器部署在群集中,请使用入口/端口转发URL(或服务DNS)。
您还可以附加内置的审核工作流配置:
[mcp_servers.github_review_mcp]
url = "http://localhost:8080/mcp"
tool_timeout_sec = 600🧩 YAML‑DSL(简称)
YAML定义了服务器设置、工具和资源。看 configs/.
服务器
server:
name: github_secrets_postgres_k8s_mcp
version: "0.1.0"
transport: "http" # http | stdio
shutdown_timeout: "10s"
idempotency_cache:
enabled: true
ttl: "24h"
max_entries: 2000
key_strategy: "auto"
startup_hooks:
- timeout: "10s"
command: |
command -v gh >/dev/null
command -v kubectl >/dev/null
- timeout: "30s"
command: |
printf %s "$YAML_MCP_GH_PAT" | gh auth login --with-token
http:
host: "127.0.0.1"
port: 8080
path: "/mcp"
read_timeout: "1h"
write_timeout: "1h"
idle_timeout: "1h"
approval_webhook_url: "http://yaml-mcp-server.local/approvals/webhook" # optional, async HTTP approvers
executor_webhook_url: "http://yaml-mcp-server.local/executors/webhook" # optional, async HTTP executorsserver.http.host 是必需的。对于本地测试,您可以使用 0.0.0.0, 但这是 不安全 --只能在孤立的环境中使用。
幂等性
如果 server.idempotency_cache 启用后,服务器将返回缓存的响应 用于重复的工具调用。缓存密钥来源于 correlation_id/request_id (如果提供)或从参数哈希中提取。
工具
使用 snake_case 带有服务前缀的工具名称(例如, github_* 或 k8s_*) 以避免与其他MCP服务器发生冲突。
tools:
- name: github_create_env_secret_k8s
title: "Create GitHub secret and K8s secret"
description: |
Creates a GitHub environment secret and injects it into Kubernetes after approval.
Input fields:
- secret_name: secret name (uppercase, digits, underscores).
- environment: target environment, allowed values: ai-staging or staging.
- namespace: Kubernetes namespace for secret injection.
- k8s_secret_name: Kubernetes Secret name (kebab-case).
- justification: required; write in language "{{ envOr "YAML_MCP_LANG" "en" }}".
- approval_request: required; concise action summary in the same language.
- risk_assessment: required; describe possible risks/side-effects in the same language.
- correlation_id (optional): provide a stable id to enable idempotent responses.
- links_to_code (optional): list of code references (text/url).
Notes:
- GitHub repository is fixed by server configuration.
- The secret value is generated by the server, do NOT provide secret_value.
annotations:
read_only_hint: false
destructive_hint: true
idempotent_hint: false
open_world_hint: true
title: "Create GitHub env secret + K8s secret"
requires_approval: true
timeout: "1h"
timeout_message: "approval timeout"
input_schema:
type: object
additionalProperties: false
required: ["secret_name", "environment", "namespace", "k8s_secret_name", "justification", "approval_request", "risk_assessment"]
properties:
correlation_id: { type: string }
secret_name: { type: string, pattern: "^[A-Z0-9_]+$" }
environment: { type: string, enum: ["ai-staging", "staging"] }
namespace: { type: string, pattern: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" } # DNS-1123
k8s_secret_name: { type: string, pattern: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" } # DNS-1123
justification: { type: string, minLength: 10, maxLength: 500 }
approval_request: { type: string, minLength: 10, maxLength: 500 }
risk_assessment: { type: string, minLength: 10, maxLength: 500 }
links_to_code:
type: array
maxItems: 5
items:
type: object
additionalProperties: false
required: ["text", "url"]
properties:
text: { type: string }
url: { type: string }
approvers:
- type: limits
fields:
secret_name: { regex: "^[A-Z0-9_]+$" }
environment: { regex: "^(ai-staging|staging)$" }
namespace: { regex: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" }
k8s_secret_name: { regex: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" }
justification: { min_length: 10, max_length: 500 }
approval_request: { min_length: 10, max_length: 500 }
risk_assessment: { min_length: 10, max_length: 500 }
- type: shell
timeout: "1m"
command: |
repo="{{ env "YAML_MCP_GITHUB_REPO" }}"
if gh secret list -R "$repo" | awk '{print $1}' | grep -qx "{{ "{{ .Args.secret_name }}" }}"; then
echo "secret already exists"; exit 1; fi
executor:
type: shell
timeout: "1h"
command: |
secret_value="$(head -c 32 /dev/urandom | base64)"
repo="{{ env "YAML_MCP_GITHUB_REPO" }}"
gh api -X PUT "repos/$repo/environments/{{ "{{ .Args.environment }}" }}" >/dev/null
gh secret set {{ "{{ .Args.secret_name }}" }} -R "$repo" --env {{ "{{ .Args.environment }}" }} --body "$secret_value"
kubectl -n {{ "{{ .Args.namespace }}" }} create secret generic {{ "{{ .Args.k8s_secret_name }}" }} \
--from-literal={{ "{{ .Args.secret_name }}" }}="$secret_value" \
--dry-run=client -o yaml | kubectl apply -f -
echo "secret {{ "{{ .Args.secret_name }}" }} created in $repo env {{ "{{ .Args.environment }}" }} and injected into {{ "{{ .Args.namespace }}" }}/{{ "{{ .Args.k8s_secret_name }}" }}"资源
resources:
- name: Welcome
uri: static:welcome
description: Welcome message
mime_type: text/plain
text: "Hello from yaml-mcp-server"🔄 端到端数据库流(github \_create_env_secret_k8s→ k8s_create_postgres_db)
- 该模型请求以下机密:
PG_USER和PG_PASSWORD通过
github_create_env_secret_k8s (两个单独的电话)。 秘密是在GitHub和 立即注射 进入Kubernetes。
- 模型调用
k8s_create_postgres_db,只传递秘密名称和密钥:
- k8s_pg_user_secret_name / pg_user_secret_name - k8s_pg_password_secret_name / pg_password_secret_name
- 该工具从K8s secrets中读取值,并在PostgreSQL pod中创建数据库。
这种方法的好处
- 模型永远看不到秘密值,但仍然可以执行已批准的工作流。
- 秘密立即可用 通过Kubernetes Secret访问服务。
- 统一审批链和审核 通过yaml mcp服务器。
k8s_create_postgres.db请求示例
{
"correlation_id": "corr-...",
"tool": "k8s_create_postgres_db",
"arguments": {
"namespace": "project-ai-staging",
"db_name": "billing",
"k8s_pg_user_secret_name": "db-credentials",
"pg_user_secret_name": "PG_USER",
"k8s_pg_password_secret_name": "db-credentials",
"pg_password_secret_name": "PG_PASSWORD",
"justification": "New database required for billing service",
"approval_request": "Create a DB and set the owner using Kubernetes secrets.",
"risk_assessment": "May create an extra DB if the name is wrong; requires careful review."
}
}响应示例
{
"status": "success",
"decision": "approve",
"reason": "database billing created in namespace project-ai-staging",
"correlation_id": "corr-..."
}🧪 审批人
支持的审批人:
limits--速率限制和字段验证(正则表达式、最小/最大、长度)。shell--基于shell命令的批准。http--通过外部HTTP服务进行审批。
顺序与YAML中的完全相同。 链条首先停止 deny.
对于 http 您可以设置: async (真/假), markup (markdown/html), webhook_url 以(权力)否决
markup: markdown 用途 MarkdownV2 (电报)。
HTTP审批人:请求
HTTP审批人可以是 任何 实现下面合同的服务。 您可以通过Telegram建立审批人(请参阅 telegram-approver: https://github.com/codex-k8s/telegram-approver), 或者通过Mattermost/Slack或更复杂的Jira工作流。
{
"correlation_id": "corr-...",
"tool": "github_create_env_secret_k8s",
"arguments": {
"secret_name": "POSTGRES_PASSWORD",
"environment": "ai-staging",
"namespace": "project-ai-staging",
"k8s_secret_name": "db-credentials"
},
"justification": "Need a new password for the billing service.",
"approval_request": "Create a secret and inject it into Kubernetes.",
"risk_assessment": "May affect DB access if the new secret is misused.",
"links_to_code": [
{ "text": "PR #42", "url": "https://github.com/org/repo/pull/42" }
],
"lang": "en",
"markup": "markdown",
"timeout_sec": 3600,
"callback": {
"url": "http://yaml-mcp-server.codex-system.svc.cluster.local/approvals/webhook"
}
}领域:
justification,approval_request,risk_assessment:10–500个字符(必需的).links_to_code:最多5个链接(text,url).lang:ru/en.markup:markdown/html.
HTTP审批人:响应
{ "decision": "approve", "reason": "ok" }decision 是: approve | deny | error (对于异步, pending 也允许)。
HTTP审批者(异步)
如果 approver.async: true,审批人可以返回:
{ "decision": "pending", "reason": "queued" }然后,它会向发送一个webhook server.approval_webhook_url:
{
"correlation_id": "corr-...",
"decision": "deny",
"reason": "Not enough context"
}⚠️ 安全性:webhook没有共享密钥。在网络级别限制访问 (Kubernetes网络策略,服务网格/mTLS,私有服务+无公共入口)。
📡 工具响应协议
{
"status": "success|denied|error",
"decision": "approve|deny|error",
"reason": "secret POSTGRES_PASSWORD created in owner/repo env ai-staging and injected into project-ai-staging/db-credentials",
"correlation_id": "corr-..."
}🔧 YAML模板
可用模板功能:
env,envOr,default,ternary,join,lower,upper,trimPrefix,trimSuffix,replace.
服务器检查所有引用的env变量是否存在 之前 启动。
⚠️ 重要提示:配置已呈现 启动时.任何 {{ .Args.* }} 表达式必须是 逃脱 因此,它们是在工具调用时进行评估的,而不是在启动期间。 使用嵌套表达式:
{{ "{{ .Args.secret_name }}" }}❤️ 健康终点
GET /healthz--活性GET /readyz--准备就绪
⚙️ 环境变量
YAML_MCP_CONFIG--YAML配置的路径(默认config.yaml).YAML_MCP_GITHUB_REPO--GitHub仓库owner/name格式(适用于具有固定仓库的工具)。YAML_MCP_APPROVAL_WEBHOOK_URL--异步回调的外部URL(当使用异步HTTP审批器时)。YAML_MCP_EXECUTOR_WEBHOOK_URL--异步回调的外部URL(当使用异步HTTP执行器时)。YAML_MCP_LOG_LEVEL—debug|info|warn|error.YAML_MCP_LANG—en(默认)或ru.YAML_MCP_SHUTDOWN_TIMEOUT--优雅关机超时。
嵌入式配置环境和秘密
配置/github_secrets_postgres_k8s.yaml
- 必修的:
YAML_MCP_GH_PAT,YAML_MCP_GITHUB_REPO,YAML_MCP_APPROVER_URL,YAML_MCP_APPROVAL_WEBHOOK_URL - 可选:
YAML_MCP_LANG,YAML_MCP_LOG_LEVEL,YAML_MCP_POSTGRES_POD_SELECTOR
configs/github视图.yaml
- 必修的:
YAML_MCP_GH_PAT,YAML_MCP_GITHUB_REPO,YAML_MCP_GH_USERNAME - 可选:
YAML_MCP_LANG,YAML_MCP_LOG_LEVEL
配置/电报_反馈.yaml
- 必修的:
YAML_MCP_EXECUTOR_URL,YAML_MCP_EXECUTOR_WEBHOOK_URL - 可选:
YAML_MCP_LANG,YAML_MCP_LOG_LEVEL
📄 例子
configs/github_secrets_postgres_k8s.yaml
(包含两个工具:github create_env_secret_k8s和k8s_create_postgres.db)
configs/github_review.yaml
(用于确定性PR审查/评论工作流程的工具)
configs/telegram_feedback.yaml
(工具 telegram_request_feedback 通过异步HTTP执行器执行)
🧷 安全说明
yaml-mcp-server 是一个 通用MCP网关 将风险操作与模型隔离开来,只允许执行 通过明确批准。GitHub秘密流只是一个例子:模型不知道令牌或秘密值, 但可以通过批准的流请求创建。
有 还没有内置访问控制。在本地或具有严格网络访问权限的群集中运行服务 限制 yaml-mcp-server.
