RESTful MCP服务器

基于Spring Boot的RESTful API服务器,实现Model Context Protocol (MCP),支持流式HTTP响应和JSON-RPC 2.0,适用于AI代理工具交互场景。

  • by shivanshuy
  • Java
  • 本地部署
  • 更新于
在 GitHub 查看 shivanshuy/mcp-restify

使用说明

🚀 MCP恢复

Spring Boot REST API服务器实现具有可流化HTTP支持的模型上下文协议(MCP)


📋 目录


🎯 概述

MCP恢复 是一个可用于生产的SpringBoot应用程序,它公开了实现 模型上下文协议(MCP)它为AI代理提供了一个无状态的HTTP接口,用于与工具和服务进行交互。

主要亮点

  • ✅ JSON-RPC 2.0 顺从的
  • ✅ 可流式传输的HTTP 支持(分块回复)
  • ✅ 无状态 操作(云就绪)
  • ✅ 工具发现 通过 @McpTool 注释
  • ✅ Outlook集成 用于电子邮件操作

✨ 特性

  • 🔌 RESTful MCP服务器 -基于HTTP的MCP协议实现
  • 📡 可流式传输的HTTP -支持分块JSON响应
  • 🛠️ 工具管理 -MCP工具的自动发现和注册
  • 📧 Outlook集成 -从Microsoft Outlook读取电子邮件
  • 🔍 JSON-RPC 2.0 -完全符合协议要求
  • 🚀 生产就绪 -基于Spring Boot构建,具有全面的错误处理功能

📦 先决条件

在开始之前,请确保已安装以下内容:

  • Java 17或更高版本
  • Maven 3.6+

验证安装

java -version
# Should show: openjdk version "17" or higher

mvn -version
# Should show: Apache Maven 3.6.0 or higher

🔧 安装

  1. 克隆或导航到项目目录:
cd mcp-restify
  1. 无需额外安装 -所有依赖项都由Maven管理,并将在构建过程中自动下载。

🏗️ 构建

使用Maven构建项目:

mvn clean package

此命令将:

  • ✅ 清理以前的构建工件
  • ✅ 编译所有源代码
  • ✅ 运行单元测试
  • ✅ 将应用程序打包到JAR文件中

输出: target/mcp-restify-1.0.0.jar

编译选项

在构建过程中跳过测试:

mvn clean package -DskipTests

使用详细输出进行构建:

mvn clean package -X

🚀 启动服务器

选项1:使用Maven(开发)

mvn spring-boot:run

选项2:使用JAR文件(生产)

java -jar target/mcp-restify-1.0.0.jar

选项3:使用自定义配置文件运行

java -jar target/mcp-restify-1.0.0.jar --spring.profiles.active=prod

服务器状态

服务器将于启动 http://localhost:9092

您应该看到类似于以下内容的输出:

Tomcat started on port 9092 (http) with context path ''
Started McpRestifyApplication in X.XXX seconds
Registered MCP tools: 3

📡 MCP端点文档

MCP服务器公开了一个处理所有MCP协议方法的REST端点:

POST http://localhost:9092/mcp

所有请求必须遵循 JSON-RPC 2.0 规范。


请求头

对MCP端点的每个请求都必须包含以下标头:

标题 值 必填 描述
Content-Type application/json ✅ Yes 指定请求正文格式
Accept application/json, text/event-stream ✅ 是 指定可接受的响应格式

标题示例:

Content-Type: application/json
Accept: application/json, text/event-stream

注: 当 Accept: text/event-stream 如果包含,服务器将返回一个可流式传输的HTTP响应 Transfer-Encoding: chunked.


初始化

初始化MCP协议连接并检索服务器功能。

请求有效载荷:

{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "mcp-client",
      "version": "1.0.0"
    }
  },
  "id": 1
}

答复:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {}
    },
    "serverInfo": {
      "name": "mcp-restify",
      "version": "1.0.0"
    }
  }
}

列出工具

检索所有可用MCP工具的列表。

请求有效载荷:

{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "params": {},
  "id": 2
}

答复:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "hello",
        "description": "A simple hello tool that returns hello world string.",
        "inputSchema": {
          "type": "object",
          "properties": {},
          "required": []
        }
      },
      {
        "name": "readOutlookEmails",
        "description": "Read emails from Outlook mailbox. Can retrieve a list of emails with optional filtering.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "maxResults": {
              "type": "integer",
              "description": "Maximum number of emails to retrieve (default: 10)"
            },
            "folderId": {
              "type": "string",
              "description": "Mail folder ID (default: 'inbox')"
            }
          },
          "required": ["maxResults"]
        }
      },
      {
        "name": "readOutlookEmailById",
        "description": "Read a specific email from Outlook by its message ID.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "messageId": {
              "type": "string",
              "description": "The ID of the message to retrieve"
            }
          },
          "required": ["messageId"]
        }
      }
    ]
  }
}

呼叫工具

使用提供的参数执行特定的MCP工具。

请求有效载荷:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "hello",
    "arguments": {},
    "_meta": {
      "progressToken": 2
    }
  },
  "id": 3
}

请求参数:

字段 类型 必填 描述
name string ✅ 是 要调用的工具的名称
arguments object ✅ 是 特定于工具的参数(可以为空 {})
_meta.progressToken number ⚠️ 可选 用于进度跟踪的令牌

答复:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "hello world"
      }
    ]
  }
}

📤 响应格式

所有响应均遵循JSON-RPC 2.0规范:

成功响应

{
  "jsonrpc": "2.0",
  "id": <request_id>,
  "result": <result_data>
}

错误响应

{
  "jsonrpc": "2.0",
  "id": <request_id>,
  "error": {
    "code": <error_code>,
    "message": "<error_message>",
    "data": "<additional_error_data>"
  }
}

错误代码

代码 含义 描述
-32600 无效请求 发送的JSON不是有效的Request对象
-32601 找不到方法 该方法不存在/不可用
-32602 无效参数 无效方法参数
-32603 内部错误 内部JSON-RPC错误

🛠️ 可用工具

工具名称 描述 参数
hello 返回一个简单的“hello world”问候语 无
readOutlookEmails 从Outlook邮箱读取电子邮件 maxResults (整数), folderId (字符串,可选)
readOutlookEmailById 通过邮件ID读取特定电子邮件 messageId (字符串)

💡 示例

示例1:初始化(cURL)

curl -X POST http://localhost:9092/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": {},
      "clientInfo": {
        "name": "mcp-client",
        "version": "1.0.0"
      }
    },
    "id": 1
  }'

示例2:列表工具(cURL)

curl -X POST http://localhost:9092/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/list",
    "params": {},
    "id": 2
  }'

示例3:调用Hello工具(cURL)

curl -X POST http://localhost:9092/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "hello",
      "arguments": {},
      "_meta": {
        "progressToken": 2
      }
    },
    "id": 3
  }'

示例4:PowerShell

$headers = @{
    "Content-Type" = "application/json"
    "Accept" = "application/json, text/event-stream"
}

$body = @{
    jsonrpc = "2.0"
    method = "tools/call"
    params = @{
        name = "hello"
        arguments = @{}
        _meta = @{
            progressToken = 2
        }
    }
    id = 3
} | ConvertTo-Json -Depth 10

$response = Invoke-RestMethod -Uri "http://localhost:9092/mcp" `
    -Method Post `
    -Body $body `
    -Headers $headers

$response | ConvertTo-Json -Depth 10

示例5:Python

import requests
import json

url = "http://localhost:9092/mcp"
headers = {
    "Content-Type": "application/json",
    "Accept": "application/json, text/event-stream"
}

payload = {
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
        "name": "hello",
        "arguments": {},
        "_meta": {
            "progressToken": 2
        }
    },
    "id": 3
}

response = requests.post(url, headers=headers, json=payload)
print(json.dumps(response.json(), indent=2))

示例6:JavaScript(Node.js)

const fetch = require('node-fetch');

const url = 'http://localhost:9092/mcp';
const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json, text/event-stream'
};

const payload = {
    jsonrpc: '2.0',
    method: 'tools/call',
    params: {
        name: 'hello',
        arguments: {},
        _meta: {
            progressToken: 2
        }
    },
    id: 3
};

fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(err => console.error('Error:', err));

⚙️ 配置

配置通过以下方式管理 src/main/resources/application.properties:

# Server Configuration
server.port=9092
spring.application.name=mcp-restify

# Outlook/Microsoft Graph Configuration (Optional)
outlook.client-id=${OUTLOOK_CLIENT_ID:}
outlook.client-secret=${OUTLOOK_CLIENT_SECRET:}
outlook.tenant-id=${OUTLOOK_TENANT_ID:}

# Logging Configuration
logging.level.com.restify.mcp=DEBUG
logging.level.org.springframework=INFO

环境变量

对于Outlook集成,请设置以下环境变量:

export OUTLOOK_CLIENT_ID=your-client-id
export OUTLOOK_CLIENT_SECRET=your-client-secret
export OUTLOOK_TENANT_ID=your-tenant-id

🔍 故障排除

端口已在使用中

如果端口9092已在使用中,请将其更改为 application.properties:

server.port=9093

服务器未启动

  1. 验证Java版本:

    java -version
    # Should be 17 or higher
    
  2. 检查Maven安装:

    mvn -version
    
  3. 查看服务器日志 有关特定错误消息

  4. 检查端口冲突:

    # Windows
    netstat -ano | findstr :9092
    
    # Linux/Mac
    lsof -i :9092
    

400错误请求错误

  • ✅ 确保请求正文是有效的JSON
  • ✅ 验证 Content-Type: application/json 标题已设置
  • ✅ 验证 Accept: application/json, text/event-stream 标题已设置
  • ✅ 检查JSON-RPC格式是否正确(jsonrpc: "2.0" 是必需的)
  • ✅ 确保 method 字段是以下字段之一: initialize, tools/list, tools/call

空响应

  • ✅ 检查服务器日志是否有错误
  • ✅ 验证工具名称是否存在(使用 tools/list 检查)
  • ✅ 确保工具参数与工具的输入模式匹配

MCP检验员测试

对于交互式测试,请使用MCP检查器:

npx @modelcontextprotocol/inspector

然后将其配置为连接到:

http://localhost:9092/mcp

🧪 测试

运行所有测试

mvn test

运行特定测试

# Test HelloTool
mvn test -Dtest=HelloToolTest

# Test MCP Server Integration
mvn test -Dtest=McpServerIntegrationTest

覆盖测试

mvn test jacoco:report

📚 额外资源


📝 许可证

该项目根据MIT许可证获得许可。


🤝 贡献

欢迎投稿!请随时提交拉取请求。


由...制作❤️ 使用Spring Boot