apache/shardingsphere · error · MCPTransportSecurityException
Session attribution does not match this MCP session.
Error message
Session attribution does not match this MCP session.
What it means
Thrown by the HTTP transport security validator when the session-attribution identity resolved from the current request's headers does not equal the identity that was bound to the MCP session when it was created (subject, source, and attributes must all match). It protects session hijacking/pinning: a session id issued to one client cannot be reused by another origin, user, or token. The server returns HTTP 400 with category CATEGORY_SESSION_ATTRIBUTION_MISMATCH. Validation is skipped when the resolver is disabled or the session id is unknown, so this error only fires on an existing session whose header-derived attribution drifted.
Source
Thrown at mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/validator/ShardingSphereServerTransportSecurityValidator.java:69
originHeaderConstraint.validate(getFirstHeaderValue(headers, "Origin"));
String sessionId = getSessionId(headers);
if (sessionId.isBlank() || !sessionManager.hasSession(sessionId)) {
return;
}
validateSessionIdentity(headers, sessionId);
protocolVersionHeaderConstraint.validate(getFirstHeaderValue(headers, HttpHeaders.PROTOCOL_VERSION));
}
private void validateSessionIdentity(final Map<String, List<String>> headers, final String sessionId) throws ServerTransportSecurityException {
if (!sessionAttributionResolver.isEnabled()) {
return;
}
Optional<MCPSessionIdentity> boundSessionIdentity = sessionManager.findSessionIdentity(sessionId);
if (boundSessionIdentity.isEmpty()) {
return;
}
if (!isSameAttribution(boundSessionIdentity.get(), sessionAttributionResolver.resolve(headers, sessionId))) {
throw new MCPTransportSecurityException(400, "Session attribution does not match this MCP session.",
MCPTransportSecurityException.CATEGORY_SESSION_ATTRIBUTION_MISMATCH);
}
}
private boolean isSameAttribution(final MCPSessionIdentity expected, final MCPSessionIdentity actual) {
return expected.getSubject().equals(actual.getSubject()) && expected.getSource().equals(actual.getSource()) && expected.getAttributes().equals(actual.getAttributes());
}
private String getSessionId(final Map<String, List<String>> headers) {
return headers.entrySet().stream()
.filter(entry -> HttpHeaders.MCP_SESSION_ID.equalsIgnoreCase(entry.getKey()) && !entry.getValue().isEmpty()).findFirst()
.map(optional -> Objects.toString(optional.getValue().getFirst(), "")).orElse("");
}
private String getFirstHeaderValue(final Map<String, List<String>> headers, final String headerName) {
return headers.entrySet().stream()
.filter(entry -> headerName.equalsIgnoreCase(entry.getKey()) && !entry.getValue().isEmpty()).findFirst().map(optional -> Objects.toString(optional.getValue().getFirst(), "").trim())
.orElse("");View on GitHub (pinned to e952770a21)
Solutions
- Start a new MCP session (re-run initialize) with the current identity headers and use the new session id for all subsequent calls.
- Verify the client sends exactly the same identity/attribution headers on every request of a session (check proxy or middleware that mutates them).
- If session pinning to identity is not wanted in your deployment, disable the session attribution resolver (sessionAttributionResolver.isEnabled() returns false skips the check).
- Check server logs for which of subject/source/attributes diverged and align the client's headers.
Example fix
// before: initialize with token A, then reuse session id with token B initialize -> sessionId=S1 (Authorization: Bearer tokenA) call tool with S1 (Authorization: Bearer tokenB) // 400 attribution mismatch // after: re-initialize whenever credentials change initialize (Authorization: Bearer tokenB) -> sessionId=S2 call tool with S2 (Authorization: Bearer tokenB)
Defensive patterns
Strategy: validation
Validate before calling
// Re-initialize when identity inputs change, and pin headers per session
function identityFingerprint(headers) {
return JSON.stringify([headers['authorization'], headers['x-forwarded-user'], headers['x-mcp-source']]);
}
const session = { id: null, fingerprint: null };
function ensureSession(initHeaders) {
const fp = identityFingerprint(initHeaders);
if (session.id === null || session.fingerprint !== fp) {
session.id = mcp.initialize(initHeaders).sessionId;
session.fingerprint = fp;
session.headers = initHeaders; // reuse EXACT same headers afterwards
}
return session;
} Try / catch
try {
await mcp.request('tools/call', params, sessionHeaders);
} catch (e) {
if (e.status === 400 && e.category === 'SESSION_ATTRIBUTION_MISMATCH') {
session.id = null; // force re-initialize with current identity
return retryAfterReinitialize(params);
}
throw e;
} Prevention
- Send byte-identical identity headers on every request of a session.
- Re-run initialize after any credential change or re-login.
- Never share a session id between clients authenticated as different subjects.
- Log which header (subject/source/attributes) diverged when the error appears.
When it happens
Trigger: Calling any MCP HTTP endpoint with a valid Mcp-Session-Id header while the attribution headers (e.g. authenticated subject, source, or attribute headers consumed by SessionAttributionResolver.resolve) differ from those present at Initialize time. Typical: replaying a session id from a different bearer token, a different proxy that rewrites identity headers, or a client that adds/removes an identity header between requests.
Common situations: Token rotation mid-session (new subject claim), a gateway that forwards different headers per request, multiple tabs/agents sharing a session id with different auth, or a changed issuer/attribute set after re-login while reusing an old session id.
Related errors
- Completion request limit of %d per minute exceeded for MCP s
- Session does not exist.
- MCP session exceeded the maximum tool call quota of %d.
- Statement is banned by the MCP contract.
- Can not support type `%s`.
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/e7349d9303f36c0f.
Report an issue: GitHub.