Skip to main content

Command Palette

Search for a command to run...

将 Kubernetes 服务注册为 MCP Tools

Updated
2 min read

前些天看到阿里云的一篇文章《Nacos 发布 MCP Registry,实现存量应用接口“0改动”升级到 MCP 协议》,深受启发,用服务注册发现结合网关设施,将存量服务转换为 MCP 工具的玩法,能非常有效地将存量服务装进 MCP 的新瓶子。那么按照我之前发表的《MCP 是一座桥》一文的思路,是不是可以更进一步,去除对特定厂商的依赖,用更通用的方式实现 MCP 的快速上车呢?下面讲讲我的尝试。

太长不看

总体流程如下图所示:

总的说来,就是利用 Kubernetes Service 的标签和注解进行标识,MCP Server 读取 Service 信息,将其作为 Tools 暴露给 MCP Client。

注册发现的实现

MCP 规范中,提供了 Tools 列表和调用的接口,在 Python SDK 里,通常对 Tools 的实现都是使用如下代码:

import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("My App")


@mcp.tool()
def calculate_bmi(weight_kg: float, height_m: float) -> float:
    """Calculate BMI given weight in kg and height in meters"""
    return weight_kg / (height_m**2)

在我们这个场景中,Tools 是动态刷新的,因此不能用这种硬编码的形式来声明,Python SDK 提供了低阶的 Server,便于我们进行更细致的能力实现。源码(lowlevel/server.py)中提供了创建实例、实现能力直到运行的简单介绍,例如:

@server.list_prompts()
async def handle_list_prompts() -> list[types.Prompt]:
   # Implementation

@server.get_prompt()
async def handle_get_prompt(
   name: str, arguments: dict[str, str] | None
) -> types.GetPromptResult:
   # Implementation

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
   # Implementation

@server.call_tool()
async def handle_call_tool(
   name: str, arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
   # Implementation

字面意思上看,只要实现 list_toolcall_tool,就能动态注册工具并执行了。例如官方 README 中介绍的代码:

from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions

# Create a server instance
server = Server("example-server")


@server.list_prompts()
async def handle_list_prompts() -> list[types.Prompt]:
...

@server.get_prompt()
async def handle_get_prompt(
    name: str, arguments: dict[str, str] | None
...

async def run():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="example",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )


if __name__ == "__main__":
    import asyncio

    asyncio.run(run())

可以看到,低阶 MCP Server 实现中,需要自行处理原语的列表、读取和执行操作。如此看来在我们的场景中,只需要实现 list_tools 即可,例如使用如下的伪代码,查找被标记的 Service,并从 Annotation 中读取 MCP 工具定义,从而生成 MCP Tools:

try:
    kubeconfig_path = os.path.expanduser("/Users/dummy/.kube/config")
    namespace = "default"

    fetcher = kubernetes_tools.KubernetesToolsFetcher(kubeconfig_path)
    try:
        k8s_tools = fetcher.get_all_mcp_tools(namespace)
        for tool in k8s_tools:
            missing_fields = [field for field in ("name", "description", "inputSchema") if field not in tool]
            if missing_fields:
                logger.error(f"Kubernetes 工具定义缺失字段: {missing_fields},内容: {tool}")
                continue
            result.append(types.Tool(
                name=tool["name"],
                description=tool["description"],
                inputSchema=tool["inputSchema"]
            ))
        logger.info(f"从 Kubernetes 加载了 {len(k8s_tools)} 个工具")
    finally:
        fetcher.close()
except Exception as e:
    logger.error(f"从 Kubernetes 加载工具时出错: {e}")

根据如上代码编写的 MCP Server,可以在 Client 配置中加入如下内容启动:

{
  "mcpServers": {
    "Demo": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "mcp[cli]",
        "--with",
        "pyyaml",
        "--with",
        "kubernetes",
        "[somewhere]/main.py"
      ]
    }
  },
  "globalShortcut": ""
}

创建几个 Service,加上必要的标签和注解,例如:

apiVersion: v1
kind: Service
metadata:
  name: mcp-demo-service-1
  namespace: default
  labels:
    mcp: "true"
  annotations:
    mcptool: |
      [
        {
          "name": "echo",
          "description": "Echo back the input text",
          "inputSchema": {
            "type": "object",
            "required": ["message"],
            "properties": {
              "message": {
                "type": "string",
                "description": "The message to echo"
              }
            }
          }
        }
      ]
spec:
  selector:
    app: mcp-demo-1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

创建 Kubernetes 服务后,启动 MCP 客户端,例如 Claude.app,可以看到 Kubernetes 服务已经出现,如下图所示:

还不能调用

前文贴的代码里,已经展示了 call_tool 的能力,下一步应该就是调用了,这方面会稍显复杂,要涉及到通信、认证、加解密、封装等问题,各种 API 网关、或者 ZTM 这样的应用层产品,应该能辅助解决这类问题。

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts