Kubernetes的OpenAPI MCP服务器
一个轻量级的MCP(模型上下文协议)服务器,运行在您的Kubernetes集群内,通过Kubernetesneneneba API抓取您的服务和端点,自动检测公开的OpenAPI规范,并构建整个微服务表面区域的实时可查询索引。它对每个规范进行规范化(解列、合并、修复不一致),跟踪版本,并将整个内容作为MCP工具公开,以便代理可以直接在集群网络中内省、列出和调用端点,从而将您的微服务转变为分布式、自描述的功能注册表。
特性
- 自动发现:在Kubernetes命名空间中发现服务
- OpenAPI解析:获取并解析OpenAPI/Swagger规范
- MCP集成:通过模型上下文协议公开工具
- 嵌入式数据库:使用Apache Derby(不需要外部数据库)
- 计划刷新:可配置的自动刷新(默认值:每10分钟一次)
状态
| 功能 | 状态 |
|---|---|
| 通过K8s API发现服务 | ✅ 完成 |
| OpenAPI 3.x规范获取和解析 | ✅ 完成 |
| 嵌入式Derby中的持久性 | ✅ 完成 |
| 基本MCP工具(列表、获取、调用) | ✅ 完成 |
| 速率限制和指数回退 | ✅ 完成 |
| 可配置的URL模板 | ✅ 完成 |
| OpenAPI 2.0/Swagger支持 | 🚧 计划中 |
| 目标服务的身份验证 | 🚧 计划中 |
| MCP身份验证/基于角色的访问 | 🚧 计划中 |
| 最小状态UI | 💭 也许以后吧 |
建筑
┌────────────────────────────────────────────────────────────────┐
│ MCP Server │
├────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ K8s Discovery│ │OpenAPI Parser│ │ MCP Tools Layer │ │
│ │ Service │──│ Service │──│ │ │
│ └──────────────┘ └──────────────┘ │ - list_services │ │
│ │ │ │ - get_operations │ │
│ ▼ ▼ │ - invoke_endpoint │ │
│ ┌──────────────────────────────┐ │ - get_op_details │ │
│ │ Derby (Embedded) │ └────────────────────┘ │
│ │ - discovered_services │ │
│ │ - openapi_specifications │ │
│ └──────────────────────────────┘ │
│ ▲ │
│ ┌──────────────┐ │
│ │ Scheduler │ ← Refresh every 10 minutes │
│ └──────────────┘ │
└───────────────────────────────────────────────────────────────-┘需求
- Java 21+
- Docker(用于运行测试)
- Kubernetes集群访问(kubeconfig或集群内)
快速开始
构建
mvn clean package跑
# With local kubeconfig
java -jar target/openapi-mcp-server-*.jar
# With custom config
KUBECONFIG=/path/to/config java -jar target/openapi-mcp-server-*.jar码头工人
docker build -t openapi-mcp-server .
docker run -v ~/.kube/config:/root/.kube/config:ro openapi-mcp-serverKubernetes部署
这 k8s/ 目录包含在Kubernetes集群内部署MCP服务器所需的所有清单。
先决条件
- Kubernetes集群(1.24+)
kubectl配置了群集访问权限- 容器注册表访问(推/拉映像)
构建和推送图像
# Build the image
docker build -t your-registry/openapi-mcp-server:latest .
# Push to your registry
docker push your-registry/openapi-mcp-server:latest部署到Kubernetes
# Create namespace and RBAC
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/rbac.yaml
# Create configuration
kubectl apply -f k8s/configmap.yaml
# Deploy the server
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml或者一次性全部应用:
kubectl apply -f k8s/清单概述
| 文件 | 描述 |
|---|---|
namespace.yaml | 创建 openapi-mcp 命名空间 |
rbac.yaml | ServiceAccount、ClusterRole和ClusterRoleBinding用于服务发现 |
configmap.yaml | 环境配置(命名空间、路径、调度程序) |
deployment.yaml | 带有健康检查的主服务器部署 |
service.yaml | 用于内部访问的ClusterIP服务 |
RBAC权限
服务器需要以下权限才能发现服务:
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list"]配置
更新ConfigMap以自定义行为:
# k8s/configmap.yaml
data:
K8S_IN_CLUSTER: "true"
K8S_NAMESPACE_FILTER: "production,staging" # Filter specific namespaces
OPENAPI_URL_TEMPLATE: "http://{service-name}.{namespace}.svc.cluster.local/v3/api-docs"
SCHEDULER_INTERVAL_MS: "300000" # 5 minutes更新图像参考
编辑 k8s/deployment.yaml 要使用容器注册表,请执行以下操作:
containers:
- name: openapi-mcp-server
image: your-registry/openapi-mcp-server:latest验证部署
# Check pod status
kubectl get pods -n openapi-mcp
# View logs
kubectl logs -n openapi-mcp -l app.kubernetes.io/name=openapi-mcp-server
# Check service discovery is working
kubectl exec -n openapi-mcp deploy/openapi-mcp-server -- curl -s localhost:8080/health集群内DNS解析
在群集中运行时,使用基于DNS的URL模板进行可靠的服务发现:
# Kubernetes internal DNS pattern
OPENAPI_URL_TEMPLATE=http://{service-name}.{namespace}.svc.cluster.local/v3/api-docs这允许MCP服务器使用Kubernetes DNS解析服务端点,而不需要外部路由。
配置
环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
DERBY_DB_PATH | ./data/openapi_mcp | Derby数据库的路径 |
K8S_NAMESPACE_FILTER | _(全部)_ | 按命名空间筛选服务 |
OPENAPI_PATH | /v3/api-docs | 默认OpenAPI规范路径 |
OPENAPI_URL_TEMPLATE | _(无)_ | OpenAPI发现的自定义URL模板 |
DISCOVERY_LABEL | _(无)_ | 用于发现的标签选择器 |
K8S_IN_CLUSTER | false | 在集群模式下运行 |
KUBECONFIG | ~/.kube/config | kubeconfig的路径 |
SCHEDULER_ENABLED | true | 启用自动刷新 |
SCHEDULER_INTERVAL_MS | 600000 | 刷新间隔(10分钟) |
OPENAPI_MAX_CONCURRENT_REQUESTS | 10 | 最大并发OpenAPI获取请求数 |
OPENAPI_BACKOFF_MAX_FAILURES | 3 | 应用回退前失败 |
OPENAPI_BACKOFF_BASE_SECONDS | 60 | 基本回退持续时间(每次失败加倍) |
OPENAPI_BACKOFF_MAX_SECONDS | 3600 | 最长回退时间(1小时上限) |
扩展到大型集群(200+服务)
对于大型集群,服务器包括内置的保护机制:
速率限制:将并发HTTP请求限制到OpenAPI端点,以避免淹没网络或服务。配置为 OPENAPI_MAX_CONCURRENT_REQUESTS.
指数退避:重复失败的服务将暂时跳过。之后 OPENAPI_BACKOFF_MAX_FAILURES 如果连续失败,服务将进入退避模式。每次出现额外故障,回退持续时间都会加倍,从 OPENAPI_BACKOFF_BASE_SECONDS 上限为 OPENAPI_BACKOFF_MAX_SECONDS.
500服务集群的示例配置:
# k8s/configmap.yaml
data:
OPENAPI_MAX_CONCURRENT_REQUESTS: "20" # More parallelism
OPENAPI_BACKOFF_MAX_FAILURES: "5" # More tolerant
OPENAPI_BACKOFF_BASE_SECONDS: "120" # 2 min base backoff
OPENAPI_BACKOFF_MAX_SECONDS: "7200" # 2 hour max backoff
SCHEDULER_INTERVAL_MS: "300000" # Refresh every 5 minOpenAPI URL模板
默认情况下,服务器使用集群IP和端口获取OpenAPI规范: http://{cluster-ip}:{port}/{openapi-path}.
您可以使用占位符用自定义URL模板覆盖此内容:
OPENAPI_URL_TEMPLATE=http://{service-name}.svc.example.com/{service-name}/v3/api-docs支持的占位符:
| 占位符 | 描述 |
|---|---|
{service-name} | Kubernetes服务名称 |
{namespace} Kubernetes 命名空间 | |
{cluster-ip} | 服务集群IP |
{port} | 服务端口 |
示例:
# DNS-based discovery
OPENAPI_URL_TEMPLATE=http://{service-name}.{namespace}.svc.cluster.local/v3/api-docs
# Custom domain with service name in path
OPENAPI_URL_TEMPLATE=http://{service-name}.svc.example.com/{service-name}/v3/api-docs
# External gateway
OPENAPI_URL_TEMPLATE=https://api.example.com/{namespace}/{service-name}/v3/api-docsKubernetes服务注释
标记您的OpenAPI发现服务:
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
openapi.mcp.io/enabled: "true" # Enable discovery
openapi.mcp.io/path: "/v3/api-docs" # Custom OpenAPI path
spec:
ports:
- port: 8080
name: http # Port named 'http' is preferred要禁用发现,请执行以下操作:
annotations:
openapi.mcp.io/enabled: "false"使用MCP
MCP服务器应该首先部署在Kubernetes集群中。然后通过端口转发或入口将本地AI工具连接到它。
步骤1:部署到Kubernetes
kubectl apply -f k8s/步骤2:连接到MCP服务器
选项A:集群内(推荐)
如果您的AI代理在同一集群内运行,请使用内部DNS:
http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp选项B:入口(外部访问)
通过外部AI工具的入口公开服务:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openapi-mcp-server
namespace: openapi-mcp
spec:
rules:
- host: openapi-mcp.your-cluster.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: openapi-mcp-server
port:
number: 80方案C:港口远期(当地开发)
kubectl port-forward -n openapi-mcp svc/openapi-mcp-server 8080:80
# Then use http://localhost:8080/mcp步骤3:配置您的AI工具
克劳德代码(CLI)
# External access
claude mcp add openapi-k8s --url http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp
# Or in-cluster
claude mcp add openapi-k8s --url http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp或编辑 .claude/settings.json:
{
"mcpServers": {
"openapi-k8s": {
"url": "http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp"
}
}
}克劳德桌面版
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json 视窗: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"openapi-k8s": {
"url": "http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp"
}
}
}VS Code
添加到您的 settings.json 或 .vscode/mcp.json:
{
"mcp.servers": {
"openapi-k8s": {
"url": "http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp"
}
}
}光标
macOS: ~/.cursor/mcp.json 视窗: %USERPROFILE%\.cursor\mcp.json
{
"mcpServers": {
"openapi-k8s": {
"url": "http://openapi-mcp-server.openapi-mcp.svc.cluster.local/mcp"
}
}
}验证连接
配置后,您可以要求AI:
- “列出所有发现的服务”
- “显示用户服务的操作”
- “调用用户服务上的GET/users端点”
MCP工具
list_services
列出所有发现的微服务。
请求:
{
"namespace": "production"
}答复:
{
"services": [
{
"id": "production/user-service",
"name": "user-service",
"namespace": "production",
"status": "ACTIVE",
"operationCount": 12
},
{
"id": "production/order-service",
"name": "order-service",
"namespace": "production",
"status": "ACTIVE",
"operationCount": 8
}
]
}get_operations
从服务获取所有操作。
请求:
{
"service_id": "production/user-service",
"tag": "users"
}答复:
{
"operations": [
{
"operationId": "getUsers",
"method": "GET",
"path": "/api/users",
"summary": "List all users",
"tags": ["users"]
},
{
"operationId": "getUserById",
"method": "GET",
"path": "/api/users/{id}",
"summary": "Get user by ID",
"tags": ["users"]
},
{
"operationId": "createUser",
"method": "POST",
"path": "/api/users",
"summary": "Create a new user",
"tags": ["users"]
}
]
}get_operation_details
获取有关操作的详细信息,包括参数和请求正文架构。
请求:
{
"service_id": "production/user-service",
"operation_id": "createUser"
}答复:
{
"operationId": "createUser",
"method": "POST",
"path": "/api/users",
"summary": "Create a new user",
"description": "Creates a new user in the system",
"tags": ["users"],
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" },
"role": { "type": "string", "enum": ["admin", "user"] }
},
"required": ["name", "email"]
}
}
}
}
}invoke_endpoint
通过集群内网络直接调用微服务端点。
请求:
{
"service_id": "production/user-service",
"operation_id": "createUser",
"body": {
"name": "John Doe",
"email": "john@example.com",
"role": "user"
}
}答复:
{
"status": 201,
"headers": {
"content-type": "application/json",
"x-request-id": "abc-123"
},
"body": {
"id": "usr_abc123",
"name": "John Doe",
"email": "john@example.com",
"role": "user",
"createdAt": "2024-01-15T10:30:00Z"
}
}使用路径和查询参数:
{
"service_id": "production/order-service",
"operation_id": "getOrdersByUser",
"path_params": {
"userId": "usr_abc123"
},
"query_params": {
"status": "pending",
"limit": 10
}
}项目结构
co.fanki.openapimcp/
├── domain/ # Domain layer (DDD)
│ ├── model/ # Entities & Value Objects
│ │ ├── ServiceId.java
│ │ ├── ClusterAddress.java
│ │ ├── DiscoveredService.java
│ │ ├── OpenApiSpecification.java
│ │ └── Operation.java
│ ├── repository/ # Repositories (JDBI)
│ │ ├── DiscoveredServiceRepository.java
│ │ ├── DiscoveredServiceRowMapper.java
│ │ └── OpenApiSpecificationRowMapper.java
│ └── service/ # Domain services
│ ├── OpenApiParser.java
│ └── EndpointInvoker.java
├── application/ # Application layer
│ ├── command/ # Write operations
│ ├── query/ # Read operations
│ └── service/ # Application services
├── infrastructure/ # Infrastructure layer
│ ├── kubernetes/ # K8s client
│ ├── http/ # HTTP clients
│ ├── mcp/ # MCP tools
│ └── scheduling/ # Refresh scheduler
└── config/ # Spring configuration测试
# Run all tests (unit + integration)
mvn test测试总结
| 类型 | 计数 | 时间 |
|---|---|---|
| 单元测试 | 40 | ~0.1秒 |
| 集成测试 | 3 | ~33s |
| 总计 | 43 | ~35秒 |
集成测试使用带有k3s的测试容器来:
- 启动一个真正的Kubernetes集群
- 使用OpenAPI部署测试服务
- 验证服务发现
- 测试
/api/do-ping端点返回“pong”
数据库
默认情况下,服务器使用ApacheDerby作为嵌入式数据库(不需要外部数据库)。数据存储在 DERBY_DB_PATH.
使用不同的数据库
通过更新配置,您可以切换到任何兼容JDBC的数据库(PostgreSQL、MySQL等)。
PostgreSQL示例
- 将PostgreSQL驱动程序添加到
pom.xml:
org.postgresql
postgresql
runtime
- 更新
application.yml:
spring:
datasource:
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:openapi_mcp}
username: ${DB_USER:postgres}
password: ${DB_PASSWORD:changeme}
driver-class-name: org.postgresql.Driver- 在Kubernetes中设置环境变量:
# k8s/configmap.yaml
data:
DB_HOST: "postgres.openapi-mcp.svc.cluster.local"
DB_PORT: "5432"
DB_NAME: "openapi_mcp"
DB_USER: "postgres"
# Use a Secret for the password- 重建和部署:
mvn clean package -DskipTests
docker build -t your-registry/openapi-mcp-server:latest .
docker push your-registry/openapi-mcp-server:latest
kubectl rollout restart deployment/openapi-mcp-server -n openapi-mcpFlyway将在启动时自动运行迁移。该模式与数据库无关,因此它适用于任何兼容JDBC的数据库。
模式
CREATE TABLE discovered_services (
id VARCHAR(255) PRIMARY KEY,
namespace VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
cluster_ip VARCHAR(45) NOT NULL,
cluster_port INTEGER NOT NULL,
openapi_path VARCHAR(255) NOT NULL,
status VARCHAR(50) NOT NULL,
discovered_at TIMESTAMP NOT NULL,
last_checked_at TIMESTAMP
);
CREATE TABLE openapi_specifications (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
service_id VARCHAR(255) REFERENCES discovered_services(id),
title VARCHAR(500),
version VARCHAR(100),
raw_json CLOB NOT NULL,
operations_json CLOB NOT NULL,
fetched_at TIMESTAMP NOT NULL
);技术栈
| 组件 | 技术 |
|---|---|
| 语言 | Java 21 |
| 框架 | Spring Boot 3.2 |
| 数据库访问 | JDBI 3 |
| 数据库 | Apache Derby(嵌入式) |
| K8s客户端 | Kubernetes客户端Java 20 |
| OpenAPI解析器 | Swagger解析器2.1 |
| 迁徙 | Flyway |
| 测试 | JUnit5,测试容器,k3s |
安全考虑
此服务器旨在运行 在Kubernetes集群内 并提供调用微服务端点的直接访问。请考虑以下几点:
网络隔离
- 在具有受限网络策略的专用命名空间中部署
- 服务器只能从可信来源(其他集群内服务或通过经过身份验证的入口)访问
- 使用
K8S_NAMESPACE_FILTER限制服务器可以发现的命名空间
最小特权原则
# Restrict to specific namespaces
K8S_NAMESPACE_FILTER: "production,staging"
# Avoid exposing internal/system namespaces
# Never include: kube-system, kube-public, cert-manager, etc.invoke_endpoint风险
这 invoke_endpoint 该工具允许AI代理调用任何发现的端点。这很强大,但有潜在的危险:
- 尚未通过身份验证:服务器将端点作为自身调用(服务到服务),而不是作为原始用户调用
- 对调用没有速率限制:代理理论上可以向端点发送垃圾邮件
- 完全请求主体控制:代理构建请求有效负载
建议
- 从只读命名空间开始:使用只有GET端点的命名空间进行测试
- 使用网络策略:限制MCP服务器可以访问哪些服务
- 监控使用情况:记录全部
invoke_endpoint要求审计 - 身份验证计划:未来版本将支持MCP客户端的基于令牌的访问控制
计划安全功能
| 功能 | 状态 |
|---|---|
| MCP客户端身份验证 | 🚧 计划中 |
| 根据工具授权(读与写) | 🚧 计划中 |
| 端点分配列表/块列表 | 🚧 计划中 |
| 请求签名/审核日志 | 🚧 计划中 |
许可证
麻省理工学院
______________________________________________________________________
@作者waabox(埃米利亚诺·范基\[dot\]公司)
