Skip to content

SSE方式接入高德MCP报错 #2758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
chiefleo opened this issue Apr 16, 2025 · 24 comments
Open

SSE方式接入高德MCP报错 #2758

chiefleo opened this issue Apr 16, 2025 · 24 comments
Labels

Comments

@chiefleo
Copy link

Bug description
SSE方式接入高德MCP报错,同样的SSE配置在cursor里面运行是没有问题的
高德SSE参考文档:https://lbs.amap.com/api/mcp-server/gettingstarted#s2

application.properties配置:
spring.ai.mcp.client.enabled=true
spring.ai.mcp.client.request-timeout=20s
spring.ai.mcp.client.sse.connections.server1.url=https://mcp.amap.com/sse?key=xxx

报错信息:
[alsc.sales_data_center^^A47F9B75ACA3410330606ECA34F91A86|1744771227656][1] -2025-04-16 10:40:27.656 ERROR 16815 --- [HttpClient-1-Worker-2] i.m.c.t.WebFluxSseClientTransport : Fatal SSE error, not retrying: 200 OK from GET https://mcp.amap.com/sse, but response failed with cause: java.io.IOException: http1_0 content, bytes received: 81,[traceId:]
[alsc.sales_data_center^^A47F9B75ACA3410330606ECA34F91A86|1744771227656][1] -2025-04-16 10:40:27.659 ERROR 16815 --- [HttpClient-1-Worker-2] reactor.core.publisher.Operators : Operator called default onErrorDropped
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET https://mcp.amap.com/sse, but response failed with cause: java.io.IOException: http1_0 content, bytes received: 81
Caused by: org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET https://mcp.amap.com/sse, but response failed with cause: java.io.IOException: http1_0 content, bytes received: 81
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:337) ~[spring-webflux-6.2.5.jar:6.2.5]
at org.springframework.web.reactive.function.client.DefaultClientResponse.lambda$createException$1(DefaultClientResponse.java:214) ~[spring-webflux-6.2.5.jar:6.2.5]
Caused by: java.io.IOException: http1_0 content, bytes received: 81
at java.net.http/jdk.internal.net.http.common.Utils.wrapWithExtraDetail(Utils.java:391) ~[java.net.http:na]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ Body from GET https://mcp.amap.com/sse [DefaultClientResponse]
Original Stack Trace:
at java.net.http/jdk.internal.net.http.common.Utils.wrapWithExtraDetail(Utils.java:391) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.Http1Response$BodyReader.onReadError(Http1Response.java:676) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.checkForErrors(Http1AsyncReceiver.java:302) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.flush(Http1AsyncReceiver.java:268) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:182) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) ~[java.net.http:na]
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:207) ~[java.net.http:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.net.SocketException: Connection reset
at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:401) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:434) ~[na:na]

@leadhow
Copy link

leadhow commented Apr 16, 2025

是有这个问题,我换了stdio方式配置才能正常运行。

@majian159
Copy link

majian159 commented Apr 16, 2025

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。

直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

@SuperWuYou
Copy link

你自己用官方demo写一个mcp server 然后使用mcp client连接 ,启动时是好的 过两分钟一样。现在急着用的话就自己初始化那个客户端,用完关了 ,下一次请求来了继续初始化 用完继续关

@luckygqx
Copy link

@leadhow 高德的mcp服务,可以用stdio模式?

@luckygqx
Copy link

@leadhow 我一直理解stdio为本地模式,是如何可以链接到高德这种外部mcp服务的?

@chiefleo
Copy link
Author

嗯嗯 stdio模式我在本地环境跑通了;但是部署到预发/生产服务器上,还需要装npx,服务器上没法这样自由,还是sse方式更方便点。

@luckygqx
Copy link

@chiefleo 能方便描述下是如何部署本地高德mcp服务吗(stdio协议的)?我在想,即便部署在本地了,那需要把地址转换为经纬度时,难道部署的mcp服务内部会再去访问高德api吗?

@dyrnq
Copy link

dyrnq commented Apr 17, 2025

stare

@chiefleo
Copy link
Author

本地挺简单的,只要mcp-servers-config.json配置一下下面内容,然后先命令行执行下npx -y @amap/amap-maps-mcp-server ,然后启动Application就好了。
{
"mcpServers": {
"amap-maps": {
"command": "npx",
"args": [
"-y",
"@amap/amap-maps-mcp-server"
],
"env": {
"AMAP_MAPS_API_KEY": "你的key"
}
}
}
}

@chiefleo 能方便描述下是如何部署本地高德mcp服务吗(stdio协议的)?我在想,即便部署在本地了,那需要把地址转换为经纬度时,难道部署的mcp服务内部会再去访问高德api吗?

@luckygqx
Copy link

本地挺简单的,只要mcp-servers-config.json配置一下下面内容,然后先命令行执行下npx -y @amap/amap-maps-mcp-server ,然后启动Application就好了。 { "mcpServers": { "amap-maps": { "command": "npx", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "你的key" } } } }

@chiefleo 能方便描述下是如何部署本地高德mcp服务吗(stdio协议的)?我在想,即便部署在本地了,那需要把地址转换为经纬度时,难道部署的mcp服务内部会再去访问高德api吗?

谢谢~

@seethefruture
Copy link

官网的sample上面只有stdio的,怎么都没有sse的?照着那个配置做的sse的好像有问题,是这个模块还在孵化阶段吗?
The official website's sample only has stdio, and there's nothing about SSE. I followed that configuration for SSE, but it seems to have issues. Is this module still in the incubation stage?

[spring-ai-demo] [onPool-worker-1] i.m.c.t.HttpClientSseClientTransport     : Error sending message: 404
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mcpSyncClients' defined in class path resource [org/springframework/ai/mcp/client/autoconfigure/McpClientAutoConfiguration.class]: Failed to instantiate [java.util.List]: Factory method 'mcpSyncClients' threw exception with message: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 3000ms in 'source(MonoCreate)' (and no fallback has been configured)

@Danny0802
Copy link

官网的样本上面只有stdio的,怎么都没有sse的?照着那个配置做的sse的好像有问题,这个模块还在孵化阶段吗?官网的 样本只有stdio,没有SSE的东西。我遵循了 SSE 的配置,但它似乎有问题。这个模块还处于孵化阶段吗?

[spring-ai-demo] [onPool-worker-1] i.m.c.t.HttpClientSseClientTransport : Error sending message: 404
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mcpSyncClients' defined in class path resource [org/springframework/ai/mcp/client/autoconfigure/McpClientAutoConfiguration.class]: Failed to instantiate [java.util.List]: Factory method 'mcpSyncClients' threw exception with message: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 3000ms in 'source(MonoCreate)' (and no fallback has been configured)

请问这个问题解了吗?

@seethefruture
Copy link

官网的样本上面只有stdio的,怎么都没有sse的?照着那个配置做的sse的好像有问题,这个模块还在孵化阶段吗?官网的 样本只有stdio,没有SSE的东西。我遵循了 SSE 的配置,但它似乎有问题。这个模块还处于孵化阶段吗?
[spring-ai-demo] [onPool-worker-1] i.m.c.t.HttpClientSseClientTransport : Error sending message: 404
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mcpSyncClients' defined in class path resource [org/springframework/ai/mcp/client/autoconfigure/McpClientAutoConfiguration.class]: Failed to instantiate [java.util.List]: Factory method 'mcpSyncClients' threw exception with message: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 3000ms in 'source(MonoCreate)' (and no fallback has been configured)

请问这个问题解了吗?

解决了,但是会出现另一个issus(2740)里面的另一个问题,每两分钟就会断连,可能需要自己处理client和保持连接吧
resloved,but here's will be another problem refer(issue 2740), lost connect every 2m, maybe we need use manual config and handle the client's connection ourself

@Danny0802
Copy link

官网的样本上面只有stdio的,怎么都没有sse的?照着那个配置做的sse的好像有问题,这个模块还在孵化阶段吗?官网的 样本只有stdio,没有SSE的东西。我遵循了 SSE 的配置,但它似乎有问题。这个模块还处于孵化阶段吗?
[spring-ai-demo] [onPool-worker-1] i.m.c.t.HttpClientSseClientTransport : Error sending message: 404
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mcpSyncClients' defined in class path resource [org/springframework/ai/mcp/client/autoconfigure/McpClientAutoConfiguration.class]: Failed to instantiate [java.util.List]: Factory method 'mcpSyncClients' threw exception with message: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 3000ms in 'source(MonoCreate)' (and no fallback has been configured)

请问这个问题解了吗?

解决了,但是会出现另一个issus(2740)里面的另一个问题,每两分钟就会断连,可能需要自己处理client和保持连接吧 resloved,but here's will be another problem refer(issue 2740), lost connect every 2m, maybe we need use manual config and handle the client's connection ourself

请问如何解决的呢,我的工程启动时,也会报同样的错误

@ReloadingPeace
Copy link

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。

直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过
McpClientTransport transport = HttpClientSseClientTransport
.builder("https://mcp.amap.com")
.sseEndpoint("/sse?key=xxxxxx")
.objectMapper(objectMapper)
.build();

@seethefruture
Copy link

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的引入后我排查到是在建立连接时的url不正确,我猜测可能是目前yml的配置方式不支持这种,使用目前只能手动写。另外高德的链接使用endpoint建立后会在2分钟左右断连,spring没有做自动切换恢复。可能国外的sse跟高德的不太一样?先自己实现吧,可以做心跳重连,但是目前的心跳好像没有比较好的方法,试试看有没有什么断开回调吧,不行就只能每次使用都是实例化sseclient了

@ReloadingPeace
Copy link

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的引入后我排查到是在建立连接时的url不正确,我猜测可能是目前yml的配置方式不支持这种,使用目前只能手动写。另外高德的链接使用endpoint建立后会在2分钟左右断连,spring没有做自动切换恢复。可能国外的sse跟高德的不太一样?先自己实现吧,可以做心跳重连,但是目前的心跳好像没有比较好的方法,试试看有没有什么断开回调吧,不行就只能每次使用都是实例化sseclient了

保持连接我没有尝试过,我是每次调用完后,手动关闭,调用close方法的

@chiefleo
Copy link
Author

多谢大家,目前各种尝试下来的结论大致是这样的:
1、spring-ai默认的starter,构造的HttpClientSseClientTransport http client version为2.0,跟高德的1.x版本不兼容。
解决方案:参考 @ReloadingPeace 的解法,不用starter里面的bean,自己重写McpClientTransport 实现。

附:
报错文案:Caused by: java.io.IOException: http1_0 content, bytes received: 5324
根因分析:spring-ai-autoconfigure-mcp-client jar包,SseHttpClientTransportAutoConfiguration#mcpHttpClientTransports,transport用到了一个废弃new HttpClientSseClientTransport有参构造方法,该方法底层会调用new HttpClientImpl,version为默认的HttpClient.Version.HTTP_2;自己重写mcpHttpClientTransports实现之后,HttpClientSseClientTransport.builder默认用HttpClient.Version.HTTP_1_1,跟高德SSE是兼容的。

2、SSE连接之后,运行个2分钟左右就挂了且稳定重现,猜测高德服务端可能有定时机制自动断开长链接。
临时解决方案:client服务器开启本机定时任务,对于高德server,每分钟ping一次保活。
采用临时方案后,目前效果是MCP可以较稳定运行比较久的一段时间。但是偶发还会出现404 Not Found from POST https://mcp.amap.com/mcp/message,这种情况暂时只好重启机器了。

  @Autowired
   private List<McpAsyncClient> mcpAsyncClients;

 @Scheduled(cron = "20 * * * * ?")
    public void schedulerPingMcpServer() {
        
        for (McpAsyncClient mcpAsyncClient : mcpAsyncClients) {
            if (!"amap-sse-serve".equals(mcpAsyncClient.getServerInfo().name())) {
                continue;
            }
            mcpAsyncClient.ping().doOnError(error -> {
                LogUtils.error(LOGGER, error, "【MCP】ping失败。 clientName={0}, serverInfo={1}",
                    mcpAsyncClient.getClientInfo(), mcpAsyncClient.getServerInfo());
            }).subscribe();
        }
    }

3、stdio本地测试demo很容易就跑通了,为啥服务器上线要这样痛苦地尝试走SSE而不是stdio方案?主要有下面两个原因:
①、stdio方案要求每接入一个MCP都安装一个本地server,成本太高,不利于长期可持续发展。而SSE无需机器安装任何命令,比较通用且轻量级。
②、我们生产服务器不能随意安装命令,操作系统是alios 7u,最大支持node16,某些npx命令必须要node18+才支持,因为某些特殊原因,alios还不能升级。

最后,以上解法都不够完美且很浪费时间,期待官方可以尽快优化支持。

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

@luckygqx
Copy link

我这边发现即便是重新了mcpClientTransport,依然会出现sse断开链接

    @Bean
    public List<NamedClientMcpTransport> mcpClientTransport() {
        McpClientTransport transport = HttpClientSseClientTransport
                .builder("https://mcp.amap.com")
                .sseEndpoint("/sse?key=you key")
                .objectMapper(new ObjectMapper())
                .build();

        return Collections.singletonList(new NamedClientMcpTransport("amap", transport));
        //return transport;
    }

@luckygqx
Copy link

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的这么配置可以,高德给出的地址是https://mcp.amap.com/see?key= youkey,但spring ai好像访问的时候会变成https://mcp.amap.com/see/see,后面又给加了一个see,导致404。具体需要调试下代码了

  ai:
    mcp:
      client:
        toolcallback:
          enabled: true
        enabled: true
        sse:
          connections:
            server1:
              url: https://mcp.amap.com?key= youkey

@jingbio
Copy link

jingbio commented Apr 22, 2025

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的这么配置可以,高德给出的地址是https://mcp.amap.com/see?key= youkey,但spring ai好像访问的时候会变成https://mcp.amap.com/see/see,后面又给加了一个see,导致404。具体需要调试下代码了

ai:
mcp:
client:
toolcallback:
enabled: true
enabled: true
sse:
connections:
server1:
url: https://mcp.amap.com?key= youkey

你确定?我的还是404啊

@seethefruture
Copy link

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的引入后我排查到是在建立连接时的url不正确,我猜测可能是目前yml的配置方式不支持这种,使用目前只能手动写。另外高德的链接使用endpoint建立后会在2分钟左右断连,spring没有做自动切换恢复。可能国外的sse跟高德的不太一样?先自己实现吧,可以做心跳重连,但是目前的心跳好像没有比较好的方法,试试看有没有什么断开回调吧,不行就只能每次使用都是实例化sseclient了

保持连接我没有尝试过,我是每次调用完后,手动关闭,调用close方法的

那长期的chat怎么保持session呢。高德这个看起来会自己主动关闭的

@chiefleo
Copy link
Author

目前已经联系到高德同学协助排查了,等问题fix之后会在这里同步。

一样,我使用spring ai的mcp server实现了高德的api,集成到mcp client,目前没啥问题。
直接对接官方的sse,SYNC模式我没成功过。ASYNC模式一开始正常,但是运行段时间就挂了。

编程式sync是可以的,yml形式我没成功过 McpClientTransport transport = HttpClientSseClientTransport .builder("https://mcp.amap.com") .sseEndpoint("/sse?key=xxxxxx") .objectMapper(objectMapper) .build();

yml的引入后我排查到是在建立连接时的url不正确,我猜测可能是目前yml的配置方式不支持这种,使用目前只能手动写。另外高德的链接使用endpoint建立后会在2分钟左右断连,spring没有做自动切换恢复。可能国外的sse跟高德的不太一样?先自己实现吧,可以做心跳重连,但是目前的心跳好像没有比较好的方法,试试看有没有什么断开回调吧,不行就只能每次使用都是实例化sseclient了

保持连接我没有尝试过,我是每次调用完后,手动关闭,调用close方法的

那长期的chat怎么保持session呢。高德这个看起来会自己主动关闭的

@wangzr622
Copy link

对于sse连接增加参数,mcp java sdk在0.9版本后做了修复。spring AI如果集成高德SSE可以自定义client:

Image
这种情况,不需要加spring相关配置。
也可以直接使用spring ai相关配置,代码改动如下:

Image
但是这种情况仅限于自己测试用,实际生产环境中是无法避免服务端也就是高德侧主动断开连接的情况,这种配置都是一次性连接。所以暂时我想了一种方案:

Image
创建一个切面,在调用mcpclient的方法前建立连接,调用之后释放连接。类似于httpclient的建立连接释放连接原理
实际使用方法如下:

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests