创建自己的MCP Server

本节我们从无到有,创建一个自己的MCP Server,它可以执行本地的shell,并返回结果。我们将全程使用cursor,不用写任何代码。

创建项目

先对cursor做下配置,把MCP相关的文档加载到index,这样生成代码的时候会更加准确。

在右上角点击设置,然后在features部分,找到Docs,点击Add new doc:

image-20250421211430882

分别添加下面两个地址:

https://modelcontextprotocol.io/introduction

https://github.com/modelcontextprotocol/python-sdk

添加时,为它命名,例如MCP

image-20250421211508530

添加完成后,cursor很快索引了82个文档页面:

image-20250421211535890

添加第二个文档,同样为它命名:

image-20250421211618467

这次有6000多个page被索引:

image-20250421211630575

添加完这两个文件之后,我们就可以进行代码生成了。

生成代码并运行

创建一个项目及文件:

mkdir mcp-demo
cd mcp-demo
touch server.py

然后在cursor里输入如下prompt:

image-20250421211956224

这个prompt非常简单,cursor会自动帮我们生成MCP server的代码,代码如下(每次生成的代码都有不同结果,如果运行有问题可以参考以下的代码):

from typing import Any
from mcp.server.fastmcp import FastMCP
import subprocess
import shlex
import os

# Initialize FastMCP server
mcp = FastMCP("ShellExecutor")

# List of allowed commands (for security)
ALLOWED_COMMANDS = {
    'ls': True,
    'pwd': True,
    'echo': True,
    'cat': True,
    'grep': True,
    'find': True,
    'date': True,
    'whoami': True,
    'uname': True,
    'df': True,
    'du': True,
    'ps': True,
    'top': True,
    'free': True,
    'uptime': True,
    'netstat': True,
    'ifconfig': True,
    'ping': True,
    'traceroute': True,
    'dig': True,
    'nslookup': True,
    'curl': True,
    'wget': True,
    'git': True,
    'docker': True,
    'kubectl': True,
}

def is_command_allowed(command: str) -> bool:
    """Check if the command is in the allowed list."""
    cmd = shlex.split(command)[0]
    return cmd in ALLOWED_COMMANDS

@mcp.tool()
async def execute_command(command: str) -> dict[str, Any]:
    """
    Execute a shell command and return the result.
    
    Args:
        command: The shell command to execute
        
    Returns:
        A dictionary containing:
        - success: bool indicating if the command executed successfully
        - output: str containing the command output
        - error: str containing any error message
    """
    if not is_command_allowed(command):
        return {
            "success": False,
            "output": "",
            "error": f"Command '{command.split()[0]}' is not allowed"
        }
    
    try:
        # Execute the command with a timeout of 30 seconds
        result = subprocess.run(
            command,
            shell=True,
            capture_output=True,
            text=True,
            timeout=30
        )
        
        return {
            "success": True,
            "output": result.stdout,
            "error": result.stderr
        }
    except subprocess.TimeoutExpired:
        return {
            "success": False,
            "output": "",
            "error": "Command execution timed out after 30 seconds"
        }
    except Exception as e:
        return {
            "success": False,
            "output": "",
            "error": str(e)
        }

if __name__ == "__main__":
    # Run the MCP server
    mcp.run(transport='stdio')

可以看到,上面生成的代码有简单的安全加固,它只允许执行一部分命令。

在cursor中配置MCP:

image-20250421213000499

为这个server命名为command,然后写好对应的python文件路径:

image-20250421212104947

配置完成后,回到原来的页面,发现检查正常。并且看到它的描述是Execute a shell command and return the result

image-20250421212129056

此时我们在cursor中可以跟自己的系统交互了,比如查看根目录下的文件:

image-20250421212244457

比如执行kubectl指令,它返回了7个节点:

image-20250421212342369

我们试图执行个不被允许的指令,例如创建文件:

image-20250421213415350

发现没有通过检查,执行失败。