googleapis/mcp-toolbox · error · NewHeaderMismatchedError

Mcp-Name header value '%s' does not match body value '%s'

Error message

Mcp-Name header value '%s' does not match body value '%s'

What it means

After verifying Mcp-Method, validateHeader also checks that the `Mcp-Name` header matches the entity name in the request body (e.g. the tool name in a tools/call request). A mismatch is treated as a potential header-injection or routing integrity problem and rejected with a HeaderMismatchedError (internal/server/mcp/v20260728/method.go:117).

Source

Thrown at internal/server/mcp/v20260728/method.go:117

// validateHeader checks the header of every requests
// Toolbox do not check for `Mcp-Param-{Name}` header since we are not
// implementing custom headers from parameters
// Do not need to check for Base64-encoding or invalid characters since we are
// only checking `mcp-method` and `mcp-name`
func validateHeader(id jsonrpc.RequestId, header http.Header, method, name string) (any, error) {
	// stdio transport will not have header
	if header == nil {
		return nil, nil
	}
	headerMethod := header.Get("mcp-method")
	if headerMethod != method {
		err := fmt.Errorf("Mcp-Method header value '%s' does not match body value '%s'", headerMethod, method)
		return jsonrpc.NewHeaderMismatchedError(id, err), err
	}
	headerName := header.Get("mcp-name")
	if headerName != name {
		err := fmt.Errorf("Mcp-Name header value '%s' does not match body value '%s'", headerName, name)
		return jsonrpc.NewHeaderMismatchedError(id, err), err
	}
	return nil, nil
}

// getResultMetadata append the resultMetaObject on existing metadata
func getResultMetadata(ctx context.Context, curMeta map[string]any) (map[string]any, error) {
	v, err := util.ToolboxVersionFromContext(ctx)
	if err != nil {
		return nil, err
	}

	resMetaObj := ResultMetaObject{
		ServerInfo: Implementation{
			BaseMetadata: BaseMetadata{
				Name: SERVER_NAME,
			},
			Version: v,

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Set Mcp-Name to exactly the tool (or prompt) name in the request params for each call.
  2. Ensure the header is generated per-request from the same value used in the body, not cached.
  3. Confirm the tool name in your client matches the tool's current name in the toolbox config (tool names are snake_case).
  4. If a proxy strips/rewrites headers, add Mcp-Name to its passthrough list.

Example fix

// before
headers.Set("Mcp-Name", "list_tables")
body := `{"method":"tools/call","params":{"name":"run_query"}}`
// after
headers.Set("Mcp-Name", "run_query")
body := `{"method":"tools/call","params":{"name":"run_query"}}`
Defensive patterns

Strategy: validation

Validate before calling

function validateMcpNameHeader(headers, body) {
  const parsed = JSON.parse(body);
  if (parsed.method === 'tools/call' && headers.get('Mcp-Name') !== parsed.params.name) {
    throw new Error(`Mcp-Name header '${headers.get('Mcp-Name')}' != params.name '${parsed.params.name}'`);
  }
}

Try / catch

try {
  const res = await callTool(name, args);
  if (res.error && res.error.message.includes('Mcp-Name header')) {
    // rebuild headers from current tool name and retry once
    return callTool(name, args);
  }
} catch (e) { console.error('tools/call failed:', e); }

Prevention

When it happens

Trigger: A tools/call request where the `Mcp-Name` header does not equal `params.name` in the body (e.g. header says `my_tool` but body calls `my_tool_v2`). Also triggered by prompts/get with mismatched prompt name; other handlers pass an empty name which always matches.

Common situations: Clients caching headers from a previous call and reusing them; wrappers around the MCP client that set Mcp-Name once at startup; renaming a tool in the toolbox config without updating the calling application; proxies injecting or rewriting the header.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/112665c0314a2620. Report an issue: GitHub.