Merge remote-tracking branch 'origin/master' into fix/wrong-report
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m59s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 2m9s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m23s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 3m6s
Project CI / Frontend tests (pull_request) Successful in 3m31s
Project CI / Repository checks (pull_request) Successful in 3m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m57s
Project CI / Backend tests (pull_request) Successful in 6m48s
Project CI / Native shell tests (pull_request) Successful in 7m29s

# Conflicts:
#	docs/project-memory/shared-memory/pitfalls.md
This commit is contained in:
2026-10-02 15:01:38 +08:00
8 changed files with 909 additions and 5 deletions
@@ -2,6 +2,7 @@ use super::*;
use axum::extract::DefaultBodyLimit;
use axum::extract::State as AxumState;
use axum::http::{HeaderMap, StatusCode};
use axum::response::IntoResponse;
use axum::routing::post;
use axum::Json;
use axum::Router;
@@ -2090,7 +2091,7 @@ async fn handle_external_mcp_http_request(
AxumState(state): AxumState<ExternalMcpHttpState>,
headers: HeaderMap,
Json(request): Json<Value>,
) -> Result<Json<Value>, StatusCode> {
) -> Result<axum::response::Response, StatusCode> {
if !external_mcp_authorized(&headers, &state.token) {
return Err(StatusCode::UNAUTHORIZED);
}
@@ -2107,6 +2108,13 @@ async fn handle_external_mcp_http_request(
.in_flight
.try_acquire()
.map_err(|_| StatusCode::TOO_MANY_REQUESTS)?;
// JSON-RPC 通知(没有 `id`)没有响应体:MCP 客户端在 `initialize` 之后一定会发
// `notifications/initialized`,按错误回 400 会被判成握手失败,整个服务器就被标记
// 成 `failed`、一个工具都不广告(真实案例:2026-10-02 的 cc DirectProject 因此
// 拿到 0 个工具)。规范要求的应答是 202 Accepted(空体)。
if request.get("id").is_none() {
return Ok(StatusCode::ACCEPTED.into_response());
}
let response = EXTERNAL_MCP_BRIDGE_URL
.scope(
state.bridge_url.clone(),
@@ -2114,7 +2122,7 @@ async fn handle_external_mcp_http_request(
)
.await
.ok_or(StatusCode::BAD_REQUEST)?;
Ok(Json(response))
Ok(Json(response).into_response())
}
pub(crate) async fn start_external_mcp_loopback(