Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

MCP Toolset headers are static — impossible to pass per-user JWT in multi-tenant scenarios

未关闭
#1,382 3 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@hemasekhar-p 已经在做这个了。

开始于 2026年7月30日。

评估

这个 Issue 还没有评估数据。

描述

needs review

** Please make sure you read the contribution guide and file the issues in the right place. **
Contribution guide.

🔴 Required Information

Please ensure all items in this section are completed to allow for efficient
triaging. Requests without complete information may be rejected / deprioritized.
If an item is not applicable to you - please mark it as N/A

Is your feature request related to a specific problem?

In a multi-user application (e.g. Spring Boot serving multiple authenticated users), each user has their own JWT token that must be forwarded to an MCP server requiring authentication.

Currently, SseServerParameters.headers() returns an ImmutableMap<String, Object> and StreamableHttpServerParameters.headers is a final Map<String, String>. Both are set at construction time and frozen for the lifetime of the toolset.

This means in a typical Spring Boot setup:

// At app startup — no user context available
SseServerParameters params = SseServerParameters.builder()
.url("https://mcp-server.example.com")
.headers(Map.of("Authorization", "Bearer ???")) // No token yet!
.build();
McpToolset toolset = new McpToolset(params);

When User A (with JWT-A) and User B (with JWT-B) both call the agent, the MCP server always receives the same frozen token (or none). There is no way to inject per-request authentication headers.

Describe the Solution You'd Like
  • Root cause

    In DefaultMcpTransportBuilder, the asyncHttpRequestCustomizer is called per-request but always reads from the same frozen parameters object:

    .asyncHttpRequestCustomizer(
    (requestBuilder, method, uri, body, context) -> {
    streamableParams.headers() // ← always the same frozen map
    .forEach((key, value) -> requestBuilder.header(key, value));
    return Mono.just(requestBuilder);
    });

    The context parameter is available but never used for dynamic header resolution.

  • Proposed solution

    Support a Supplier<Map<String, String>> (or similar functional interface) for headers, evaluated at each request:

    SseServerParameters params = SseServerParameters.builder()
    .url("https://mcp-server.example.com")
    .headersProvider(() -> {
    String jwt = SecurityContextHolder.getContext()
    .getAuthentication().getCredentials().toString();
    return Map.of("Authorization", "Bearer " + jwt);
    })
    .build();

    This would allow frameworks like Spring Security to inject the current user's token on every MCP call, without creating a new toolset per request.

Impact on your work

We are building a multi-tenant Spring Boot application where multiple authenticated users interact with ADK agents concurrently. Each user's request must be forwarded to MCP servers that enforce JWT-based authorization.

Currently, we have to create a new McpToolset instance per request to inject the user's token, which is inefficient (new connection per call) and defeats the purpose of connection pooling and session reuse. This is a blocker for any production multi-user deployment that relies on authenticated MCP servers.

Timeline: We are targeting a production release in Q4 2026. A fix or accepted workaround by then would be ideal.

Willingness to contribute

Are you interested in implementing this feature yourself or submitting a PR?
Yes — we are willing to submit a PR for this. We have already identified the affected files and a viable approach (see Proposed API below).


🟡 Recommended Information

Describe Alternatives You've Considered

Create a new McpToolset per request — Works but creates a new transport/connection for every call. No session reuse, poor performance under load

Proposed API / Implementation

Add a headersProvider option alongside the existing static headers:

// SseServerParameters / StreamableHttpServerParameters
@Nullable
public abstract Supplier<Map<String, String>> headersProvider();

// DefaultMcpTransportBuilder — evaluate per-request instead of once
.asyncHttpRequestCustomizer(
(requestBuilder, method, uri, body, context) -> {
Supplier<Map<String, String>> provider = params.headersProvider();
if (provider != null) {
provider.get().forEach(requestBuilder::header);
}
return Mono.just(requestBuilder);
});

Usage with Spring Security:
SseServerParameters params = SseServerParameters.builder()
.url("https://mcp-server.example.com")
.headersProvider(() -> {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return Map.of("Authorization", "Bearer " + auth.getCredentials());
})
.build();

This is backward-compatible — existing headers(Map) usage continues to work unchanged.

Additional Context

The asyncHttpRequestCustomizer in DefaultMcpTransportBuilder already receives a context parameter per-request but currently ignores it — the infrastructure for dynamic behavior is partially in place.

主要语言
Java
星标
1.7k
派生
433
平均合并
3 天 13 小时
30 天内合并 PR
42

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

google/adk-java 的其他 Issue

查看 google/adk-java 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。