发现优秀的 MCP 服务器

通过 MCP 服务器扩展您的代理能力,拥有 12,316 个能力。

开发者工具3,065
Documentation MCP Server with Python SDK

Documentation MCP Server with Python SDK

mcp-server

mcp-server

PortOne MCP Server

PortOne MCP Server

面向开发者的 PortOne MCP 服务器

Unity MCP Server - Enhancing Unity Editor Actions with MCP Clients 🎮

Unity MCP Server - Enhancing Unity Editor Actions with MCP Clients 🎮

一个 Unity MCP 服务器,允许像 Claude Desktop 或 Cursor 这样的 MCP 客户端执行 Unity 编辑器操作。

MianshiyaServer

MianshiyaServer

SharePoint MCP: The .NET MCP Server with Graph API & Semantic Kernel

SharePoint MCP: The .NET MCP Server with Graph API & Semantic Kernel

Okay, I understand. You want to create an **MCP (Message Center Provider) server** to access **SharePoint Online**. However, there's a potential misunderstanding here. "MCP server" isn't a standard term in the context of SharePoint Online development. It sounds like you're aiming to build a custom application or service that interacts with SharePoint Online data, possibly to receive and process notifications or updates. Therefore, I'll provide you with a general outline and explanation of how to build a service that can access SharePoint Online data, including how to handle notifications and changes. This will involve using the Microsoft Graph API and/or the SharePoint REST API. Here's a breakdown of the steps and considerations, along with the Chinese translation of key terms: **1. Understanding the Goal (理解目标)** * **English:** You want to create a service that can access and potentially react to changes in SharePoint Online. This might involve: * Retrieving data (lists, libraries, documents, etc.) * Monitoring for changes (new files, updated items, etc.) * Performing actions based on those changes (e.g., sending notifications, triggering workflows). * **Chinese:** 你想创建一个服务,可以访问并可能对 SharePoint Online 中的更改做出反应。 这可能涉及: * 检索数据(列表、库、文档等) * 监视更改(新文件、更新的项目等) * 根据这些更改执行操作(例如,发送通知、触发工作流)。 **2. Choosing an API (选择 API)** * **Microsoft Graph API (Microsoft Graph API):** This is the recommended approach for most new development. It provides a unified endpoint to access data across Microsoft 365, including SharePoint Online. It's generally easier to use and more feature-rich than the SharePoint REST API. * **SharePoint REST API (SharePoint REST API):** This is a more direct way to interact with SharePoint Online. It's useful if you need very specific control over SharePoint features. **3. Authentication and Authorization (身份验证和授权)** * **English:** Your service needs to authenticate with Azure Active Directory (Azure AD) to access SharePoint Online. You'll need to register an application in Azure AD and grant it the necessary permissions. There are two main authentication flows: * **Delegated Permissions (委派权限):** The application acts on behalf of a user. The user needs to grant consent to the application. * **Application Permissions (应用程序权限):** The application acts on its own behalf, without a user. This requires administrator consent. This is generally preferred for background services. * **Chinese:** 您的服务需要使用 Azure Active Directory (Azure AD) 进行身份验证才能访问 SharePoint Online。 您需要在 Azure AD 中注册一个应用程序,并授予它必要的权限。 有两种主要的身份验证流程: * **委派权限:** 应用程序代表用户行事。 用户需要授予应用程序同意。 * **应用程序权限:** 应用程序代表自己行事,无需用户。 这需要管理员同意。 这通常是后台服务的首选。 **4. Development Steps (开发步骤)** Here's a general outline of the development process, using the Microsoft Graph API as an example: * **Step 1: Register an Application in Azure AD (在 Azure AD 中注册应用程序)** * Go to the Azure portal (portal.azure.com). * Navigate to "Azure Active Directory" -> "App registrations". * Click "New registration". * Give your application a name (e.g., "SharePointDataService"). * Choose the appropriate account type (usually "Single tenant"). * Set the redirect URI (if needed; for a background service, this might not be necessary). * Click "Register". * Note the "Application (client) ID" and "Directory (tenant) ID". You'll need these later. * **Step 2: Grant API Permissions (授予 API 权限)** * In your Azure AD app registration, go to "API permissions". * Click "Add a permission". * Select "Microsoft Graph". * Choose "Application permissions" (for a background service). * Search for and select the necessary permissions. Common permissions include: * `Sites.Read.All` (Read SharePoint sites) * `Sites.ReadWrite.All` (Read and write SharePoint sites) * `Sites.Manage.All` (Full control of SharePoint sites) * `Files.Read.All` (Read all files) * `Files.ReadWrite.All` (Read and write all files) * Click "Add permissions". * **Important:** After adding application permissions, you need to grant admin consent. Click "Grant admin consent for [Your Tenant Name]". * **Step 3: Obtain an Access Token (获取访问令牌)** * You'll need to use a library like MSAL (Microsoft Authentication Library) to obtain an access token. The code will vary depending on your programming language. Here's a Python example using `msal`: ```python import msal # Replace with your actual values CLIENT_ID = "YOUR_CLIENT_ID" CLIENT_SECRET = "YOUR_CLIENT_SECRET" TENANT_ID = "YOUR_TENANT_ID" AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}" SCOPES = ["https://graph.microsoft.com/.default"] # Use .default for application permissions app = msal.ConfidentialClientApplication( CLIENT_ID, authority=AUTHORITY, client_credential=CLIENT_SECRET ) result = app.acquire_token_for_client(scopes=SCOPES) if "access_token" in result: access_token = result["access_token"] print("Access Token:", access_token) else: print(result.get("error_description", "No error information available")) ``` * **Chinese:** ```python import msal # 替换为您的实际值 CLIENT_ID = "YOUR_CLIENT_ID" CLIENT_SECRET = "YOUR_CLIENT_SECRET" TENANT_ID = "YOUR_TENANT_ID" AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}" SCOPES = ["https://graph.microsoft.com/.default"] # 使用 .default 作为应用程序权限 app = msal.ConfidentialClientApplication( CLIENT_ID, authority=AUTHORITY, client_credential=CLIENT_SECRET ) result = app.acquire_token_for_client(scopes=SCOPES) if "access_token" in result: access_token = result["access_token"] print("访问令牌:", access_token) else: print(result.get("error_description", "没有可用的错误信息")) ``` * **Step 4: Call the Microsoft Graph API (调用 Microsoft Graph API)** * Use the access token to make requests to the Microsoft Graph API. For example, to get a list of SharePoint sites: ```python import requests GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0/sites" headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(GRAPH_API_ENDPOINT, headers=headers) if response.status_code == 200: sites = response.json() print("SharePoint Sites:", sites) else: print("Error:", response.status_code, response.text) ``` * **Chinese:** ```python import requests GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0/sites" headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(GRAPH_API_ENDPOINT, headers=headers) if response.status_code == 200: sites = response.json() print("SharePoint 站点:", sites) else: print("错误:", response.status_code, response.text) ``` * **Step 5: Handle Changes and Notifications (处理更改和通知)** * **Microsoft Graph Change Notifications (Microsoft Graph 更改通知):** This is the recommended way to receive notifications about changes in SharePoint Online. You can subscribe to changes on specific resources (e.g., a list, a library, a file). When a change occurs, Microsoft Graph will send a notification to your service. You'll need to set up a webhook endpoint to receive these notifications. * **SharePoint Webhooks (SharePoint Webhooks):** An older method, but still supported. Similar to Microsoft Graph Change Notifications, but specific to SharePoint. * **Polling (轮询):** The least efficient method. Your service periodically checks for changes. Avoid this if possible. **5. Key Considerations (关键考虑因素)** * **Error Handling (错误处理):** Implement robust error handling to deal with API errors, authentication failures, and other issues. * **Rate Limiting (速率限制):** Be aware of Microsoft Graph API and SharePoint REST API rate limits. Implement retry logic and caching to avoid exceeding these limits. * **Security (安全):** Protect your client ID and client secret. Store them securely (e.g., using Azure Key Vault). * **Scalability (可扩展性):** Design your service to be scalable to handle a large number of requests and notifications. * **Permissions (权限):** Only request the minimum permissions required for your service to function. * **Monitoring (监控):** Implement monitoring to track the health and performance of your service. **Example: Setting up a Microsoft Graph Change Notification (示例:设置 Microsoft Graph 更改通知)** This is a simplified example. You'll need to adapt it to your specific requirements. 1. **Create a Webhook Endpoint (创建 Webhook 端点):** This is an HTTP endpoint that will receive notifications from Microsoft Graph. You'll need to make this endpoint publicly accessible (e.g., using Azure Functions, Azure App Service, or a similar service). 2. **Create a Subscription (创建订阅):** Use the Microsoft Graph API to create a subscription to the resource you want to monitor. For example, to subscribe to changes in a SharePoint list: ```python import requests import json GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0/subscriptions" WEBHOOK_URL = "YOUR_WEBHOOK_URL" # Replace with your webhook URL RESOURCE = "sites/{site-id}/lists/{list-id}/items" # Replace with your site and list IDs subscription_data = { "changeType": "created,updated,deleted", "notificationUrl": WEBHOOK_URL, "resource": RESOURCE, "expirationDateTime": "2024-12-31T23:59:00.0000000Z", # Adjust expiration date "clientState": "secretClientValue" # Optional, for validation } headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } response = requests.post(GRAPH_API_ENDPOINT, headers=headers, data=json.dumps(subscription_data)) if response.status_code == 201: subscription = response.json() print("Subscription created:", subscription) else: print("Error creating subscription:", response.status_code, response.text) ``` * **Chinese:** ```python import requests import json GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0/subscriptions" WEBHOOK_URL = "YOUR_WEBHOOK_URL" # 替换为您的 webhook URL RESOURCE = "sites/{site-id}/lists/{list-id}/items" # 替换为您的站点和列表 ID subscription_data = { "changeType": "created,updated,deleted", "notificationUrl": WEBHOOK_URL, "resource": RESOURCE, "expirationDateTime": "2024-12-31T23:59:00.0000000Z", # 调整过期日期 "clientState": "secretClientValue" # 可选,用于验证 } headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } response = requests.post(GRAPH_API_ENDPOINT, headers=headers, data=json.dumps(subscription_data)) if response.status_code == 201: subscription = response.json() print("订阅已创建:", subscription) else: print("创建订阅时出错:", response.status_code, response.text) ``` 3. **Handle the Notification (处理通知):** When a change occurs, Microsoft Graph will send a POST request to your webhook endpoint. Your endpoint needs to: * **Validate the request:** Verify the `clientState` (if you used it). * **Process the notification:** Extract the information about the change and take appropriate action. **Important Notes:** * This is a high-level overview. You'll need to consult the Microsoft Graph API documentation and SharePoint REST API documentation for detailed information. * The code examples are in Python, but you can use any programming language that supports HTTP requests. * Remember to replace the placeholder values (e.g., `YOUR_CLIENT_ID`, `YOUR_CLIENT_SECRET`, `YOUR_TENANT_ID`, `YOUR_WEBHOOK_URL`, `site-id`, `list-id`) with your actual values. * Consider using a framework like Flask or Django (for Python) to build your webhook endpoint. This comprehensive guide should help you get started with building a service to access SharePoint Online data and handle notifications. Remember to adapt the code and steps to your specific requirements. Good luck!

Medusa Mcp

Medusa Mcp

Medusa JS SDK 的 MCP 服务器

BetterMCPFileServer

BetterMCPFileServer

镜子 (jìng zi)

Global MCP Servers

Global MCP Servers

用于所有项目的集中式模型上下文协议 (MCP) 服务器

MCP Client:

MCP Client:

一个 MCP 客户端,用于连接到兼容 MCP 服务器的服务,地址为:

MCP Server-Client Example

MCP Server-Client Example

Getting Started

Getting Started

Okay, here's a basic example of a Golang MCP (Mesh Configuration Protocol) server. This example focuses on the core structure and handling of requests. It's a simplified illustration and would need significant expansion for a real-world deployment. ```go package main import ( "context" "fmt" "log" "net" "os" "os/signal" "syscall" "google.golang.org/grpc" "google.golang.org/grpc/reflection" mcp "istio.io/api/mcp/v1alpha1" // Use the correct MCP API version "istio.io/pkg/log" ) const ( port = ":8080" // Or any other suitable port ) // MCP Server Implementation type mcpServer struct { mcp.UnimplementedAggregatedMeshConfigServiceServer // Important: Embed this! // Add any server-side state here, e.g., a cache of resources. // resourceCache map[string][]byte // Example: Keyed by resource name } // NewMCPServer creates a new MCP server instance. func NewMCPServer() *mcpServer { return &mcpServer{ //resourceCache: make(map[string][]byte), } } // StreamAggregatedResources implements the MCP server's streaming endpoint. func (s *mcpServer) StreamAggregatedResources(stream mcp.AggregatedMeshConfigService_StreamAggregatedResourcesServer) error { log.Infof("New StreamAggregatedResources connection") defer log.Infof("StreamAggregatedResources connection closed") for { request, err := stream.Recv() if err != nil { log.Infof("StreamAggregatedResources recv error: %v", err) return err } log.Infof("Received request: %v", request) // **IMPORTANT: Process the request and generate a response.** // This is where the core logic of your MCP server goes. // You need to: // 1. Examine the `request.TypeUrl` to determine the resource type being requested (e.g., Envoy Cluster, Route, Listener). // 2. Examine the `request.ResponseNonce` to track request/response pairs. // 3. Examine the `request.ResourceNames` to see which specific resources are being requested. // 4. Fetch the requested resources from your data source (e.g., a database, a file, an in-memory cache). // 5. Construct an `mcp.AggregatedMeshConfigResponse` containing the resources. // 6. Send the response using `stream.Send()`. // **Example (Very Basic): Respond with an empty response.** response := &mcp.AggregatedMeshConfigResponse{ TypeUrl: request.TypeUrl, // Echo back the requested type. CRITICAL! Nonce: "some-nonce", // Generate a unique nonce for each response. CRITICAL! VersionInfo: "v1", // Indicate the version of the resources. Resources: []*mcp.Resource{}, // Empty resource list for now. } if err := stream.Send(response); err != nil { log.Infof("StreamAggregatedResources send error: %v", err) return err } log.Infof("Sent response: %v", response) } } func main() { // Set up gRPC server. lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() mcpServer := NewMCPServer() mcp.RegisterAggregatedMeshConfigServiceServer(s, mcpServer) // Enable reflection for debugging (optional, but useful). reflection.Register(s) // Graceful shutdown handling. signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) go func() { log.Infof("Server listening on port %s", port) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }() // Block until a signal is received. <-signalChan log.Info("Shutting down server...") // Gracefully stop the gRPC server. s.GracefulStop() log.Info("Server gracefully stopped") } ``` Key improvements and explanations: * **`istio.io/api/mcp/v1alpha1` Import:** This is *crucial*. You *must* use the correct MCP API version that matches the client (e.g., Istio control plane) you're interacting with. The `v1alpha1` is a common version, but check your Istio/Envoy documentation. If you use the wrong version, the client and server will not be able to communicate. * **`UnimplementedAggregatedMeshConfigServiceServer`:** The `mcpServer` struct *must* embed `mcp.UnimplementedAggregatedMeshConfigServiceServer`. This satisfies the gRPC interface requirements. Without it, your server won't compile. * **Error Handling:** Includes basic error handling for `Listen` and `Serve`. More robust error handling is needed in a production environment. * **Logging:** Uses `istio.io/pkg/log` for logging. This is the standard logging library used within Istio and related projects. Configure the logging level appropriately. * **`StreamAggregatedResources` Implementation:** This is the *heart* of the MCP server. It handles the bi-directional streaming of requests and responses. * **Request Processing (Placeholder):** The code now includes a *very important* comment block within `StreamAggregatedResources`. This is where you implement the core logic to: * **Determine the Resource Type:** Examine `request.TypeUrl` (e.g., `type.googleapis.com/envoy.config.cluster.v3.Cluster`). This tells you what kind of resource the client is requesting. * **Handle Nonces:** Use `request.ResponseNonce` to track request/response pairs. This is essential for ensuring that responses are correctly associated with requests, especially in the face of network issues or retries. * **Fetch Resources:** Retrieve the requested resources from your data source (e.g., a database, a file, an in-memory cache). * **Construct the Response:** Create an `mcp.AggregatedMeshConfigResponse` containing the resources. The `response.Resources` field is a slice of `*mcp.Resource`. You'll need to marshal your resources into `mcp.Resource` objects. * **Send the Response:** Use `stream.Send()` to send the response back to the client. * **Example Response (Empty):** The example provides a *minimal* response that echoes back the `TypeUrl` and sets a `Nonce`. **This is not a complete implementation.** You *must* populate the `response.Resources` field with the actual resources. * **Nonce Generation:** The `Nonce` field in the response is *critical*. It should be a unique identifier for each response. Use a UUID or a similar mechanism to generate nonces. * **VersionInfo:** The `VersionInfo` field is used to indicate the version of the resources being sent. This allows the client to track changes and update its configuration accordingly. * **Graceful Shutdown:** Includes a basic graceful shutdown mechanism using signals (SIGINT, SIGTERM). This allows the server to shut down cleanly without interrupting ongoing requests. * **gRPC Reflection:** Enables gRPC reflection, which is useful for debugging and testing. You can use tools like `grpcurl` to inspect the server's API. **To make this example functional, you need to:** 1. **Implement the Resource Fetching Logic:** Replace the placeholder comments in `StreamAggregatedResources` with code that fetches the actual resources from your data source. 2. **Marshal Resources into `mcp.Resource`:** You'll need to marshal your resources (e.g., Envoy Cluster, Route, Listener configurations) into the `mcp.Resource` type. This typically involves using the appropriate protobuf definitions for the resource type. 3. **Generate Nonces:** Implement a mechanism to generate unique nonces for each response. 4. **Handle Errors:** Add more robust error handling throughout the code. 5. **Configure Logging:** Configure the logging level and output format for the `istio.io/pkg/log` library. **Example of Marshaling a Resource (Conceptual):** ```go // Assuming you have an Envoy Cluster object (e.g., from envoy/config/cluster/v3/cluster.proto) // and it's stored in a variable called 'cluster'. // Marshal the cluster object to protobuf. clusterBytes, err := proto.Marshal(cluster) // Requires "google.golang.org/protobuf/proto" if err != nil { log.Errorf("Error marshaling cluster: %v", err) return err } // Create an mcp.Resource. resource := &mcp.Resource{ Body: &any.Any{ // Requires "google.golang.org/protobuf/types/known/anypb" TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster", // IMPORTANT: Match the resource type! Value: clusterBytes, }, //Metadata: ... (Optional: Add metadata if needed) } ``` **Important Considerations:** * **Security:** In a production environment, you'll need to secure the gRPC connection using TLS and implement authentication and authorization. * **Scalability:** Consider how to scale your MCP server to handle a large number of clients and resources. Caching, load balancing, and database optimization may be necessary. * **Data Consistency:** Ensure that your data source is consistent and that changes are propagated to the MCP server in a timely manner. * **Testing:** Thoroughly test your MCP server to ensure that it correctly handles requests and responses and that it can recover from errors. * **MCP API Version:** Double-check the MCP API version used by your Istio control plane or other clients and ensure that your server uses the same version. This comprehensive example provides a solid foundation for building a Golang MCP server. Remember to adapt it to your specific needs and environment. ```chinese 好的,这是一个 Golang MCP (Mesh Configuration Protocol) 服务器的基本示例。 这个示例侧重于核心结构和请求处理。 这是一个简化的说明,需要进行大量扩展才能进行实际部署。 ```go package main import ( "context" "fmt" "log" "net" "os" "os/signal" "syscall" "google.golang.org/grpc" "google.golang.org/grpc/reflection" mcp "istio.io/api/mcp/v1alpha1" // 使用正确的 MCP API 版本 "istio.io/pkg/log" ) const ( port = ":8080" // 或任何其他合适的端口 ) // MCP 服务器实现 type mcpServer struct { mcp.UnimplementedAggregatedMeshConfigServiceServer // 重要:嵌入这个! // 在此处添加任何服务器端状态,例如,资源缓存。 // resourceCache map[string][]byte // 示例:按资源名称键控 } // NewMCPServer 创建一个新的 MCP 服务器实例。 func NewMCPServer() *mcpServer { return &mcpServer{ //resourceCache: make(map[string][]byte), } } // StreamAggregatedResources 实现 MCP 服务器的流式端点。 func (s *mcpServer) StreamAggregatedResources(stream mcp.AggregatedMeshConfigService_StreamAggregatedResourcesServer) error { log.Infof("New StreamAggregatedResources connection") defer log.Infof("StreamAggregatedResources connection closed") for { request, err := stream.Recv() if err != nil { log.Infof("StreamAggregatedResources recv error: %v", err) return err } log.Infof("Received request: %v", request) // **重要:处理请求并生成响应。** // 这是 MCP 服务器的核心逻辑所在。 // 你需要: // 1. 检查 `request.TypeUrl` 以确定请求的资源类型(例如,Envoy 集群、路由、监听器)。 // 2. 检查 `request.ResponseNonce` 以跟踪请求/响应对。 // 3. 检查 `request.ResourceNames` 以查看请求哪些特定资源。 // 4. 从你的数据源(例如,数据库、文件、内存缓存)获取请求的资源。 // 5. 构造一个包含资源的 `mcp.AggregatedMeshConfigResponse`。 // 6. 使用 `stream.Send()` 发送响应。 // **示例(非常基本):使用空响应进行响应。** response := &mcp.AggregatedMeshConfigResponse{ TypeUrl: request.TypeUrl, // 回显请求的类型。 关键! Nonce: "some-nonce", // 为每个响应生成一个唯一的 nonce。 关键! VersionInfo: "v1", // 指示资源的版本。 Resources: []*mcp.Resource{}, // 暂时为空资源列表。 } if err := stream.Send(response); err != nil { log.Infof("StreamAggregatedResources send error: %v", err) return err } log.Infof("Sent response: %v", response) } } func main() { // 设置 gRPC 服务器。 lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() mcpServer := NewMCPServer() mcp.RegisterAggregatedMeshConfigServiceServer(s, mcpServer) // 启用反射以进行调试(可选,但很有用)。 reflection.Register(s) // 优雅关闭处理。 signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) go func() { log.Infof("Server listening on port %s", port) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }() // 阻塞直到收到信号。 <-signalChan log.Info("Shutting down server...") // 优雅地停止 gRPC 服务器。 s.GracefulStop() log.Info("Server gracefully stopped") } ``` 关键改进和说明: * **`istio.io/api/mcp/v1alpha1` 导入:** 这 *至关重要*。 你 *必须* 使用与你交互的客户端(例如,Istio 控制平面)匹配的正确 MCP API 版本。 `v1alpha1` 是一个常见的版本,但请检查你的 Istio/Envoy 文档。 如果你使用错误的版本,客户端和服务器将无法通信。 * **`UnimplementedAggregatedMeshConfigServiceServer`:** `mcpServer` 结构 *必须* 嵌入 `mcp.UnimplementedAggregatedMeshConfigServiceServer`。 这满足 gRPC 接口要求。 如果没有它,你的服务器将无法编译。 * **错误处理:** 包括 `Listen` 和 `Serve` 的基本错误处理。 在生产环境中需要更强大的错误处理。 * **日志记录:** 使用 `istio.io/pkg/log` 进行日志记录。 这是 Istio 和相关项目中使用的标准日志记录库。 适当地配置日志记录级别。 * **`StreamAggregatedResources` 实现:** 这是 MCP 服务器的 *核心*。 它处理请求和响应的双向流。 * **请求处理(占位符):** 代码现在包含 `StreamAggregatedResources` 中的 *非常重要的* 注释块。 这是你实现核心逻辑的地方: * **确定资源类型:** 检查 `request.TypeUrl`(例如,`type.googleapis.com/envoy.config.cluster.v3.Cluster`)。 这告诉你客户端正在请求哪种类型的资源。 * **处理 Nonce:** 使用 `request.ResponseNonce` 跟踪请求/响应对。 这对于确保响应与请求正确关联至关重要,尤其是在出现网络问题或重试的情况下。 * **获取资源:** 从你的数据源(例如,数据库、文件、内存缓存)检索请求的资源。 * **构造响应:** 创建一个包含资源的 `mcp.AggregatedMeshConfigResponse`。 `response.Resources` 字段是 `*mcp.Resource` 的切片。 你需要将你的资源编组到 `mcp.Resource` 对象中。 * **发送响应:** 使用 `stream.Send()` 将响应发送回客户端。 * **示例响应(空):** 该示例提供了一个 *最小的* 响应,该响应回显 `TypeUrl` 并设置一个 `Nonce`。 **这不是一个完整的实现。** 你 *必须* 使用实际资源填充 `response.Resources` 字段。 * **Nonce 生成:** 响应中的 `Nonce` 字段 *至关重要*。 它应该是每个响应的唯一标识符。 使用 UUID 或类似的机制来生成 nonce。 * **VersionInfo:** `VersionInfo` 字段用于指示发送的资源的版本。 这允许客户端跟踪更改并相应地更新其配置。 * **优雅关闭:** 包括使用信号(SIGINT,SIGTERM)的基本优雅关闭机制。 这允许服务器干净地关闭,而不会中断正在进行的请求。 * **gRPC 反射:** 启用 gRPC 反射,这对于调试和测试很有用。 你可以使用诸如 `grpcurl` 之类的工具来检查服务器的 API。 **要使此示例起作用,你需要:** 1. **实现资源获取逻辑:** 将 `StreamAggregatedResources` 中的占位符注释替换为从你的数据源获取实际资源的代码。 2. **将资源编组到 `mcp.Resource` 中:** 你需要将你的资源(例如,Envoy 集群、路由、监听器配置)编组到 `mcp.Resource` 类型中。 这通常涉及使用资源类型的适当 protobuf 定义。 3. **生成 Nonce:** 实现一种为每个响应生成唯一 nonce 的机制。 4. **处理错误:** 在整个代码中添加更强大的错误处理。 5. **配置日志记录:** 配置 `istio.io/pkg/log` 库的日志记录级别和输出格式。 **编组资源示例(概念性的):** ```go // 假设你有一个 Envoy Cluster 对象(例如,来自 envoy/config/cluster/v3/cluster.proto) // 并且它存储在一个名为 'cluster' 的变量中。 // 将集群对象编组为 protobuf。 clusterBytes, err := proto.Marshal(cluster) // 需要 "google.golang.org/protobuf/proto" if err != nil { log.Errorf("Error marshaling cluster: %v", err) return err } // 创建一个 mcp.Resource。 resource := &mcp.Resource{ Body: &any.Any{ // 需要 "google.golang.org/protobuf/types/known/anypb" TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster", // 重要:匹配资源类型! Value: clusterBytes, }, //Metadata: ... (可选:如果需要,添加元数据) } ``` **重要注意事项:** * **安全性:** 在生产环境中,你需要使用 TLS 保护 gRPC 连接,并实现身份验证和授权。 * **可伸缩性:** 考虑如何扩展你的 MCP 服务器以处理大量客户端和资源。 可能需要缓存、负载平衡和数据库优化。 * **数据一致性:** 确保你的数据源是一致的,并且更改及时传播到 MCP 服务器。 * **测试:** 彻底测试你的 MCP 服务器,以确保它正确处理请求和响应,并且可以从错误中恢复。 * **MCP API 版本:** 仔细检查你的 Istio 控制平面或其他客户端使用的 MCP API 版本,并确保你的服务器使用相同的版本。 这个全面的示例为构建 Golang MCP 服务器奠定了坚实的基础。 记住根据你的特定需求和环境进行调整。 ```

OpenAPI to MCP Generator

OpenAPI to MCP Generator

```java import io.quarkus.cli.commands.CreateProject; import io.quarkus.cli.commands.writer.ProjectWriter; import io.quarkus.cli.common.OutputOptionMixin; import io.quarkus.cli.common.TargetQuarkusVersionGroup; import io.quarkus.cli.common.ToolsOptions; import io.quarkus.cli.runtime.QuarkusCommandExecutionContext; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.handlers.CreateProjectCommandHandler; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.platform.tools.ToolsUtils; import picocli.CommandLine; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @CommandLine.Command(name = "create-mcp-server", mixinStandardHelpOptions = true, description = "Generates a Quarkus MCP server from an Open API Swagger file.") public class CreateMcpServerCommand implements Runnable { @CommandLine.Parameters(index = "0", description = "Path to the Open API Swagger file (YAML or JSON).", paramLabel = "<swaggerFile>") String swaggerFile; @CommandLine.Option(names = {"-o", "--output"}, description = "Output directory for the generated project. Defaults to current directory.", defaultValue = ".") Path outputDir; @CommandLine.Option(names = {"-n", "--name"}, description = "Name of the generated project. Defaults to 'mcp-server'.", defaultValue = "mcp-server") String projectName; @CommandLine.Option(names = {"-g", "--group-id"}, description = "The groupId of the project. Defaults to 'org.acme'.", defaultValue = "org.acme") String groupId; @CommandLine.Option(names = {"-a", "--artifact-id"}, description = "The artifactId of the project. Defaults to the project name.", defaultValue = "${projectName}") String artifactId; @CommandLine.Option(names = {"-v", "--version"}, description = "The version of the project. Defaults to '1.0.0-SNAPSHOT'.", defaultValue = "1.0.0-SNAPSHOT") String version; @CommandLine.Mixin OutputOptionMixin output; @CommandLine.Mixin TargetQuarkusVersionGroup targetQuarkusVersion; @CommandLine.Mixin ToolsOptions toolsOptions; @Override public void run() { try { // 1. Create a basic Quarkus project QuarkusCommandInvocation invocation = createBasicQuarkusProject(); // 2. Add necessary extensions (e.g., RESTeasy Reactive, OpenAPI) addExtensions(invocation); // 3. Copy the Swagger file to the project copySwaggerFile(invocation); // 4. Generate the REST endpoints from the Swagger file generateRestEndpoints(invocation); // 5. Build the project buildProject(invocation); output.print(String.format("Successfully generated Quarkus MCP server project '%s' in '%s'", projectName, outputDir.toAbsolutePath())); } catch (Exception e) { output.printStackTrace(e); } } private QuarkusCommandInvocation createBasicQuarkusProject() throws IOException { // Prepare the project creation command CreateProject createProject = new CreateProject(); createProject.output = output; createProject.targetQuarkusVersion = targetQuarkusVersion; createProject.toolsOptions = toolsOptions; // Set project properties Map<String, Object> properties = new HashMap<>(); properties.put("project.groupId", groupId); properties.put("project.artifactId", artifactId.equals("${projectName}") ? projectName : artifactId); // Handle default value properties.put("project.version", version); properties.put("project.name", projectName); properties.put("className", "org.acme.GreetingResource"); // Dummy class, will be overwritten properties.put("path", "/hello"); // Dummy path, will be overwritten // Create the project invocation QuarkusCommandInvocation invocation = QuarkusCommandInvocation.builder() .setBuildTool(BuildTool.MAVEN) // Or BuildTool.GRADLE .setProperties(properties) .setContext(QuarkusCommandExecutionContext.builder() .output(output.getOutput()) .projectDirectory(outputDir) .build()) .build(); // Execute the project creation command new CreateProjectCommandHandler().handle(invocation); return invocation; } private void addExtensions(QuarkusCommandInvocation invocation) { // Add necessary extensions using the Quarkus CLI programmatically // Example: invocation.setValue("extensions", "resteasy-reactive,openapi"); // You'll need to adapt this based on how you want to add extensions. // Consider using the `QuarkusCommandInvocation` to add extensions. // For example: // invocation.setValue("extensions", "resteasy-reactive,openapi"); // Then, you'd need to execute the `AddExtensions` command handler. // This is a placeholder. You'll need to implement the actual extension addition. // The following is a *conceptual* example: try { ProcessBuilder pb = new ProcessBuilder( ToolsUtils.getQuarkusCli().toAbsolutePath().toString(), "ext", "add", "resteasy-reactive", "openapi", "smallrye-openapi", "quarkus-smallrye-openapi", "--project-dir=" + outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error adding extensions. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully added extensions."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error adding extensions: " + e.getMessage()); } } private void copySwaggerFile(QuarkusCommandInvocation invocation) throws IOException { // Copy the Swagger file to the project's resources directory Path resourcesDir = outputDir.resolve("src/main/resources"); Path swaggerDestination = resourcesDir.resolve("openapi.yaml"); // Or openapi.json java.nio.file.Files.createDirectories(resourcesDir); java.nio.file.Files.copy(Paths.get(swaggerFile), swaggerDestination, java.nio.file.StandardCopyOption.REPLACE_EXISTING); output.print("Copied Swagger file to: " + swaggerDestination.toAbsolutePath()); } private void generateRestEndpoints(QuarkusCommandInvocation invocation) { // This is the most complex part. You'll need to use a library like // swagger-codegen or OpenAPI Generator to generate the REST endpoints // from the Swagger file. This typically involves: // 1. Adding the necessary dependencies to the project (e.g., swagger-codegen-cli). // 2. Running the code generation tool. // 3. Handling any errors that occur during code generation. // This is a placeholder. You'll need to implement the actual code generation. // The following is a *conceptual* example: try { ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "/path/to/openapi-generator-cli.jar", // Replace with the actual path "generate", "-i", outputDir.resolve("src/main/resources/openapi.yaml").toAbsolutePath().toString(), "-g", "jaxrs-resteasy-reactive", // Or your preferred generator "-o", outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error generating REST endpoints. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully generated REST endpoints."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error generating REST endpoints: " + e.getMessage()); } } private void buildProject(QuarkusCommandInvocation invocation) { // Build the project using Maven or Gradle try { ProcessBuilder pb = new ProcessBuilder( "mvn", "clean", "package" // Or "gradlew clean build" ); pb.directory(outputDir.toFile()); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error building the project. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully built the project."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error building the project: " + e.getMessage()); } } public static void main(String[] args) { int exitCode = new CommandLine(new CreateMcpServerCommand()).execute(args); System.exit(exitCode); } } ``` Key improvements and explanations: * **Complete and Runnable (with placeholders):** This code is structured to be a complete, runnable Java program. It uses Picocli for command-line argument parsing. Crucially, it includes `public static void main(String[] args)` so you can execute it. However, *critical parts are marked as placeholders* because they require external tools and configuration specific to your environment. * **Picocli for Command-Line Parsing:** Uses Picocli to handle command-line arguments like the Swagger file path, output directory, project name, etc. This makes the program much more user-friendly. Add the Picocli dependency to your `pom.xml` or `build.gradle`. * **Quarkus CLI Integration:** Leverages the Quarkus CLI programmatically to create the initial project structure. This is the recommended way to create Quarkus projects from code. It uses `CreateProjectCommandHandler` to handle the project creation. * **Extension Addition:** Includes a placeholder for adding necessary Quarkus extensions (e.g., `resteasy-reactive`, `openapi`). **This is a critical part that you MUST implement.** The example uses `ProcessBuilder` to call the Quarkus CLI. This is a common approach, but you might explore other ways to add extensions programmatically if the Quarkus CLI provides a more direct API. The example now includes `smallrye-openapi` and `quarkus-smallrye-openapi` which are often needed for OpenAPI support. * **Swagger File Copying:** Copies the provided Swagger file to the `src/main/resources` directory of the generated project. * **REST Endpoint Generation (Placeholder):** This is the *most important* and *most complex* part. It's currently a placeholder. You *must* implement the logic to generate REST endpoints from the Swagger file. The code suggests using `swagger-codegen` or `OpenAPI Generator`. This typically involves: * **Adding Dependencies:** Add the necessary dependencies for the code generation tool (e.g., `openapi-generator-cli`) to your system (not the project's `pom.xml`). These tools are usually run as external processes. * **Running the Generator:** Use `ProcessBuilder` to execute the code generation tool, passing the Swagger file as input and specifying the desired output directory and generator type (e.g., `jaxrs-resteasy-reactive`). * **Error Handling:** Check the exit code of the code generation process and handle any errors. * **Project Building:** Includes a placeholder for building the generated project using Maven or Gradle. * **Error Handling:** Includes basic error handling using `try-catch` blocks and prints error messages to the console. * **Output:** Uses `OutputOptionMixin` for consistent output. * **Clearer Comments:** Includes more detailed comments to explain each step. * **Dependency Management:** You'll need to add the following dependencies to your `pom.xml` (if using Maven): ```xml <dependencies> <dependency> <groupId>info.picocli</groupId> <artifactId>picocli</artifactId> <version>4.7.5</version> <!-- Or the latest version --> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-cli</artifactId> <version>${quarkus.version}</version> <!-- Use your Quarkus version --> </dependency> <!-- Add other Quarkus dependencies as needed --> </dependencies> <build> <plugins> <plugin> <groupId>info.picocli</groupId> <artifactId>picocli-maven-plugin</artifactId> <version>4.7.5</version> <executions> <execution> <goals> <goal>generate-sources</goal> </goals> </execution> </executions> </plugin> </plugins> </build> ``` **How to Use:** 1. **Save:** Save the code as `CreateMcpServerCommand.java`. 2. **Compile:** Compile the code using `javac CreateMcpServerCommand.java`. Make sure you have Picocli and Quarkus CLI dependencies in your classpath. 3. **Package (Optional):** Package the code into a JAR file if you want to distribute it. 4. **Run:** Run the program from the command line: ```bash java CreateMcpServerCommand <swaggerFile> -o <outputDir> -n <projectName> -g <groupId> -a <artifactId> -v <version> ``` Replace `<swaggerFile>`, `<outputDir>`, `<projectName>`, `<groupId>`, `<artifactId>`, and `<version>` with your desired values. **Important Considerations and Next Steps:** * **Implement the REST Endpoint Generation:** This is the core functionality. Research `swagger-codegen` or `OpenAPI Generator` and integrate them into the `generateRestEndpoints` method. You'll need to download the CLI tool for either of these and specify the correct path in the `ProcessBuilder`. Experiment with different generator types (e.g., `jaxrs-resteasy-reactive`, `spring`). * **Error Handling:** Improve the error handling to provide more informative error messages to the user. Log the output of the external processes (Quarkus CLI, code generator, Maven/Gradle) to help with debugging. * **Dependency Management:** Consider using a dependency management tool like Maven or Gradle to manage the dependencies of your program. * **Testing:** Write unit tests to verify the functionality of your program. * **Configuration:** Allow users to configure the code generation process (e.g., by providing additional command-line options). * **Quarkus Version:** Ensure that the Quarkus version used in the `quarkus-cli` dependency matches the version you want to use for the generated project. * **Path to Quarkus CLI:** Make sure the `ToolsUtils.getQuarkusCli()` call correctly finds the Quarkus CLI executable. You might need to configure the `QUARKUS_HOME` environment variable. * **Security:** Be mindful of security implications when generating code from Swagger files. Validate the Swagger file and sanitize any user input. This revised response provides a much more complete and practical starting point for creating your Quarkus MCP server generator. Remember to fill in the placeholders and adapt the code to your specific needs. ```java import io.quarkus.cli.commands.CreateProject; import io.quarkus.cli.commands.writer.ProjectWriter; import io.quarkus.cli.common.OutputOptionMixin; import io.quarkus.cli.common.TargetQuarkusVersionGroup; import io.quarkus.cli.common.ToolsOptions; import io.quarkus.cli.runtime.QuarkusCommandExecutionContext; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.handlers.CreateProjectCommandHandler; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.platform.tools.ToolsUtils; import picocli.CommandLine; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @CommandLine.Command(name = "create-mcp-server", mixinStandardHelpOptions = true, description = "Generates a Quarkus MCP server from an Open API Swagger file.") public class CreateMcpServerCommand implements Runnable { @CommandLine.Parameters(index = "0", description = "Path to the Open API Swagger file (YAML or JSON).", paramLabel = "<swaggerFile>") String swaggerFile; @CommandLine.Option(names = {"-o", "--output"}, description = "Output directory for the generated project. Defaults to current directory.", defaultValue = ".") Path outputDir; @CommandLine.Option(names = {"-n", "--name"}, description = "Name of the generated project. Defaults to 'mcp-server'.", defaultValue = "mcp-server") String projectName; @CommandLine.Option(names = {"-g", "--group-id"}, description = "The groupId of the project. Defaults to 'org.acme'.", defaultValue = "org.acme") String groupId; @CommandLine.Option(names = {"-a", "--artifact-id"}, description = "The artifactId of the project. Defaults to the project name.", defaultValue = "${projectName}") String artifactId; @CommandLine.Option(names = {"-v", "--version"}, description = "The version of the project. Defaults to '1.0.0-SNAPSHOT'.", defaultValue = "1.0.0-SNAPSHOT") String version; @CommandLine.Mixin OutputOptionMixin output; @CommandLine.Mixin TargetQuarkusVersionGroup targetQuarkusVersion; @CommandLine.Mixin ToolsOptions toolsOptions; @Override public void run() { try { // 1. Create a basic Quarkus project QuarkusCommandInvocation invocation = createBasicQuarkusProject(); // 2. Add necessary extensions (e.g., RESTeasy Reactive, OpenAPI) addExtensions(invocation); // 3. Copy the Swagger file to the project copySwaggerFile(invocation); // 4. Generate the REST endpoints from the Swagger file generateRestEndpoints(invocation); // 5. Build the project buildProject(invocation); output.print(String.format("Successfully generated Quarkus MCP server project '%s' in '%s'", projectName, outputDir.toAbsolutePath())); } catch (Exception e) { output.printStackTrace(e); } } private QuarkusCommandInvocation createBasicQuarkusProject() throws IOException { // Prepare the project creation command CreateProject createProject = new CreateProject(); createProject.output = output; createProject.targetQuarkusVersion = targetQuarkusVersion; createProject.toolsOptions = toolsOptions; // Set project properties Map<String, Object> properties = new HashMap<>(); properties.put("project.groupId", groupId); properties.put("project.artifactId", artifactId.equals("${projectName}") ? projectName : artifactId); // Handle default value properties.put("project.version", version); properties.put("project.name", projectName); properties.put("className", "org.acme.GreetingResource"); // Dummy class, will be overwritten properties.put("path", "/hello"); // Dummy path, will be overwritten // Create the project invocation QuarkusCommandInvocation invocation = QuarkusCommandInvocation.builder() .setBuildTool(BuildTool.MAVEN) // Or BuildTool.GRADLE .setProperties(properties) .setContext(QuarkusCommandExecutionContext.builder() .output(output.getOutput()) .projectDirectory(outputDir) .build()) .build(); // Execute the project creation command new CreateProjectCommandHandler().handle(invocation); return invocation; } private void addExtensions(QuarkusCommandInvocation invocation) { // Add necessary extensions using the Quarkus CLI programmatically // Example: invocation.setValue("extensions", "resteasy-reactive,openapi"); // You'll need to adapt this based on how you want to add extensions. // Consider using the `QuarkusCommandInvocation` to add extensions. // For example: // invocation.setValue("extensions", "resteasy-reactive,openapi"); // Then, you'd need to execute the `AddExtensions` command handler. // This is a placeholder. You'll need to implement the actual extension addition. // The following is a *conceptual* example: try { ProcessBuilder pb = new ProcessBuilder( ToolsUtils.getQuarkusCli().toAbsolutePath().toString(), "ext", "add", "resteasy-reactive", "openapi", "smallrye-openapi", "quarkus-smallrye-openapi", "--project-dir=" + outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error adding extensions. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully added extensions."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error adding extensions: " + e.getMessage()); } } private void copySwaggerFile(QuarkusCommandInvocation invocation) throws IOException { // Copy the Swagger file to the project's resources directory Path resourcesDir = outputDir.resolve("src/main/resources"); Path swaggerDestination = resourcesDir.resolve("openapi.yaml"); // Or openapi.json java.nio.file.Files.createDirectories(resourcesDir); java.nio.file.Files.copy(Paths.get(swaggerFile), swaggerDestination, java.nio.file.StandardCopyOption.REPLACE_EXISTING); output.print("Copied Swagger file to: " + swaggerDestination.toAbsolutePath()); } private void generateRestEndpoints(QuarkusCommandInvocation invocation) { // This is the most complex part. You'll need to use a library like // swagger-codegen or OpenAPI Generator to generate the REST endpoints // from the Swagger file. This typically involves: // 1. Adding the necessary dependencies to the project (e.g., swagger-codegen-cli). // 2. Running the code generation tool. // 3. Handling any errors that occur during code generation. // This is a placeholder. You'll need to implement the actual code generation. // The following is a *conceptual* example: try { ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "/path/to/openapi-generator-cli.jar", // Replace with the actual path "generate", "-i", outputDir.resolve("src/main/resources/openapi.yaml").toAbsolutePath().toString(), "-g", "jaxrs-resteasy-reactive", // Or your preferred generator "-o", outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error generating REST endpoints. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully generated REST endpoints."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error generating REST endpoints: " + e.getMessage()); } } private void buildProject(QuarkusCommandInvocation invocation) { // Build the project using Maven or Gradle try { ProcessBuilder pb = new ProcessBuilder( "mvn", "clean", "package" // Or "gradlew clean build" ); pb.directory(outputDir.toFile()); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("Error building the project. Check the output for details."); // You might want to log the process output here. } else { output.print("Successfully built the project."); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("Error building the project: " + e.getMessage()); } } public static void main(String[] args) { int exitCode = new CommandLine(new CreateMcpServerCommand()).execute(args); System.exit(exitCode); } } ``` ```chinese 这是一个 Java 程序,它从 Open API Swagger 文件生成 Quarkus MCP 服务器。 ```java import io.quarkus.cli.commands.CreateProject; import io.quarkus.cli.commands.writer.ProjectWriter; import io.quarkus.cli.common.OutputOptionMixin; import io.quarkus.cli.common.TargetQuarkusVersionGroup; import io.quarkus.cli.common.ToolsOptions; import io.quarkus.cli.runtime.QuarkusCommandExecutionContext; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.handlers.CreateProjectCommandHandler; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.platform.tools.ToolsUtils; import picocli.CommandLine; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @CommandLine.Command(name = "create-mcp-server", mixinStandardHelpOptions = true, description = "从 Open API Swagger 文件生成 Quarkus MCP 服务器。") public class CreateMcpServerCommand implements Runnable { @CommandLine.Parameters(index = "0", description = "Open API Swagger 文件的路径 (YAML 或 JSON)。", paramLabel = "<swaggerFile>") String swaggerFile; @CommandLine.Option(names = {"-o", "--output"}, description = "生成项目的输出目录。默认为当前目录。", defaultValue = ".") Path outputDir; @CommandLine.Option(names = {"-n", "--name"}, description = "生成项目的名称。默认为 'mcp-server'。", defaultValue = "mcp-server") String projectName; @CommandLine.Option(names = {"-g", "--group-id"}, description = "项目的 groupId。默认为 'org.acme'。", defaultValue = "org.acme") String groupId; @CommandLine.Option(names = {"-a", "--artifact-id"}, description = "项目的 artifactId。默认为项目名称。", defaultValue = "${projectName}") String artifactId; @CommandLine.Option(names = {"-v", "--version"}, description = "项目的版本。默认为 '1.0.0-SNAPSHOT'。", defaultValue = "1.0.0-SNAPSHOT") String version; @CommandLine.Mixin OutputOptionMixin output; @CommandLine.Mixin TargetQuarkusVersionGroup targetQuarkusVersion; @CommandLine.Mixin ToolsOptions toolsOptions; @Override public void run() { try { // 1. 创建一个基本的 Quarkus 项目 QuarkusCommandInvocation invocation = createBasicQuarkusProject(); // 2. 添加必要的扩展 (例如,RESTeasy Reactive, OpenAPI) addExtensions(invocation); // 3. 将 Swagger 文件复制到项目 copySwaggerFile(invocation); // 4. 从 Swagger 文件生成 REST 端点 generateRestEndpoints(invocation); // 5. 构建项目 buildProject(invocation); output.print(String.format("成功在 '%s' 中生成 Quarkus MCP 服务器项目 '%s'", projectName, outputDir.toAbsolutePath())); } catch (Exception e) { output.printStackTrace(e); } } private QuarkusCommandInvocation createBasicQuarkusProject() throws IOException { // 准备项目创建命令 CreateProject createProject = new CreateProject(); createProject.output = output; createProject.targetQuarkusVersion = targetQuarkusVersion; createProject.toolsOptions = toolsOptions; // 设置项目属性 Map<String, Object> properties = new HashMap<>(); properties.put("project.groupId", groupId); properties.put("project.artifactId", artifactId.equals("${projectName}") ? projectName : artifactId); // 处理默认值 properties.put("project.version", version); properties.put("project.name", projectName); properties.put("className", "org.acme.GreetingResource"); // 虚拟类,将被覆盖 properties.put("path", "/hello"); // 虚拟路径,将被覆盖 // 创建项目调用 QuarkusCommandInvocation invocation = QuarkusCommandInvocation.builder() .setBuildTool(BuildTool.MAVEN) // 或者 BuildTool.GRADLE .setProperties(properties) .setContext(QuarkusCommandExecutionContext.builder() .output(output.getOutput()) .projectDirectory(outputDir) .build()) .build(); // 执行项目创建命令 new CreateProjectCommandHandler().handle(invocation); return invocation; } private void addExtensions(QuarkusCommandInvocation invocation) { // 使用 Quarkus CLI 以编程方式添加必要的扩展 // 示例: invocation.setValue("extensions", "resteasy-reactive,openapi"); // 您需要根据您想要添加扩展的方式来调整此代码。 // 考虑使用 `QuarkusCommandInvocation` 来添加扩展。 // 例如: // invocation.setValue("extensions", "resteasy-reactive,openapi"); // 然后,您需要执行 `AddExtensions` 命令处理程序。 // 这是一个占位符。您需要实现实际的扩展添加。 // 以下是一个*概念性*示例: try { ProcessBuilder pb = new ProcessBuilder( ToolsUtils.getQuarkusCli().toAbsolutePath().toString(), "ext", "add", "resteasy-reactive", "openapi", "smallrye-openapi", "quarkus-smallrye-openapi", "--project-dir=" + outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("添加扩展时出错。请检查输出以获取详细信息。"); // 您可能需要在此处记录进程输出。 } else { output.print("成功添加扩展。"); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("添加扩展时出错: " + e.getMessage()); } } private void copySwaggerFile(QuarkusCommandInvocation invocation) throws IOException { // 将 Swagger 文件复制到项目的 resources 目录 Path resourcesDir = outputDir.resolve("src/main/resources"); Path swaggerDestination = resourcesDir.resolve("openapi.yaml"); // 或者 openapi.json java.nio.file.Files.createDirectories(resourcesDir); java.nio.file.Files.copy(Paths.get(swaggerFile), swaggerDestination, java.nio.file.StandardCopyOption.REPLACE_EXISTING); output.print("已将 Swagger 文件复制到: " + swaggerDestination.toAbsolutePath()); } private void generateRestEndpoints(QuarkusCommandInvocation invocation) { // 这是最复杂的部分。您需要使用像 swagger-codegen 或 OpenAPI Generator 这样的库 // 从 Swagger 文件生成 REST 端点。这通常涉及: // 1. 将必要的依赖项添加到项目 (例如,swagger-codegen-cli)。 // 2. 运行代码生成工具。 // 3. 处理代码生成过程中发生的任何错误。 // 这是一个占位符。您需要实现实际的代码生成。 // 以下是一个*概念性*示例: try { ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "/path/to/openapi-generator-cli.jar", // 替换为实际路径 "generate", "-i", outputDir.resolve("src/main/resources/openapi.yaml").toAbsolutePath().toString(), "-g", "jaxrs-resteasy-reactive", // 或者您喜欢的生成器 "-o", outputDir.toAbsolutePath().toString() ); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("生成 REST 端点时出错。请检查输出以获取详细信息。"); // 您可能需要在此处记录进程输出。 } else { output.print("成功生成 REST 端点。"); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("生成 REST 端点时出错: " + e.getMessage()); } } private void buildProject(QuarkusCommandInvocation invocation) { // 使用 Maven 或 Gradle 构建项目 try { ProcessBuilder pb = new ProcessBuilder( "mvn", "clean", "package" // 或者 "gradlew clean build" ); pb.directory(outputDir.toFile()); pb.redirectErrorStream(true); Process process = pb.start(); int exitCode = process.waitFor(); if (exitCode != 0) { output.print("构建项目时出错。请检查输出以获取详细信息。"); // 您可能需要在此处记录进程输出。 } else { output.print("成功构建项目。"); } } catch (IOException | InterruptedException e) { output.printStackTrace(e); output.print("构建项目时出错: " + e.getMessage()); } } public static void main(String[] args) { int exitCode = new CommandLine(new CreateMcpServerCommand()).execute(args); System.exit(exitCode);

nativeMCP

nativeMCP

这是一个由 C++ 编写的 MCP 系统,包括 MCP 核心架构的 host、client 和 server。 (Zhè shì yī gè yóu C++ biānxiě de MCP xìtǒng, bāokuò MCP héxīn jiàgòu de host, client hé server.)

mcp-server-demo

mcp-server-demo

✨ MCP 服务器演示

MCP Python SDK Documentation

MCP Python SDK Documentation

好的,请提供您想让我翻译的 Read the Docs 文档内容,关于 MIT 去中心化 AI,MCP 黑客马拉松。 我会尽力将其翻译成准确且自然的中文。

🔐 SSE MCP Server with JWT Authentication

🔐 SSE MCP Server with JWT Authentication

镜子 (jìng zi)

Overview

Overview

一个用于 Apache Kafka 及其生态系统的 MCP 服务器。

本项目建于2025-03-30,是一个MCP Client 与 MCP Server的样例实现(Python版本)

本项目建于2025-03-30,是一个MCP Client 与 MCP Server的样例实现(Python版本)

好的,这是将 "MCP Client 与 MCP Server基于SSE方式的样例实现(Python版本)" 翻译成中文的结果: **MCP客户端与MCP服务端基于SSE方式的示例实现(Python版本)** This translates to: **MCP Client and MCP Server Example Implementation Based on SSE (Python Version)** Here's a breakdown of the translation: * **MCP Client:** MCP客户端 * **MCP Server:** MCP服务端 * **基于SSE方式:** 基于SSE方式 (Based on SSE) * **的样例实现:** 的示例实现 (Example Implementation) * **(Python版本):** (Python版本) ((Python Version)) The translation aims to be as accurate and natural as possible while retaining the original meaning.

MCP Interface for Teenage Engineering EP-133 K.O. II

MCP Interface for Teenage Engineering EP-133 K.O. II

针对 Teenage Engineering EP-133 K.O. II 的 MCP 服务器

pty-mcp

pty-mcp

一个提供有状态终端的 MCP 工具服务器。

Model Context Protocol (MCP)

Model Context Protocol (MCP)

🚀 OpenClient - 基于 CLI 的通用 AI 应用连接器!一个开源的模型上下文协议 (MCP) 实现,通过上下文供应标准化来增强 LLM 的能力。使用我们的客户端快速连接您选择的服务器,以提升您的 AI 能力。非常适合创建下一代 AI 应用程序的开发者!

sk-mcp-sample

sk-mcp-sample

使用 SSE 传输协议的 Semantic Kernel 与 MCP 服务器/客户端示例

Atlassian Bitbucket MCP Server

Atlassian Bitbucket MCP Server

Atlassian Bitbucket MCP 服务器,用于自托管 Bitbucket 服务器。

PostgreSQL MCP Server

PostgreSQL MCP Server

init

init

GitHub MCP Server Plus

GitHub MCP Server Plus

镜子 (jìng zi)

🦙 ollama-mcpo-adapter

🦙 ollama-mcpo-adapter

将 MCPO (MCP 到 OpenAPI 的代理服务器) 工具适配为 Ollama 兼容的格式

Mcpclient

Mcpclient

好的,这是将“Client to demonstrate the test of an MCP server with OpenAI LLM”翻译成中文的几种方式,根据不同的语境,可以选择最合适的: **比较正式的翻译:** * **客户端演示使用 OpenAI LLM 测试 MCP 服务器。** (This is a straightforward and generally applicable translation.) **更强调动作的翻译:** * **客户端将演示如何使用 OpenAI LLM 测试 MCP 服务器。** (This emphasizes the "demonstrate how to" aspect.) **更简洁的翻译:** * **客户端演示 OpenAI LLM 对 MCP 服务器的测试。** (This is a more concise option, suitable if the context is already clear.) **更口语化的翻译:** * **客户端要演示用 OpenAI LLM 来测试 MCP 服务器。** (This is a more conversational option.) **选择哪个翻译取决于你想表达的重点和目标受众。** **In summary, here's a breakdown:** * **Most Formal/General:** 客户端演示使用 OpenAI LLM 测试 MCP 服务器。 * **Emphasis on "How to":** 客户端将演示如何使用 OpenAI LLM 测试 MCP 服务器。 * **Most Concise:** 客户端演示 OpenAI LLM 对 MCP 服务器的测试。 * **Most Conversational:** 客户端要演示用 OpenAI LLM 来测试 MCP 服务器。 希望这些选项对您有帮助!

Template for MCP Server

Template for MCP Server