REVISED ANSWER
With the latest tokcycle package features, one does not need an explicit terminator to the token cycle. Rather, the cycle can peek ahead to see if an end-of-group/environment is next in the input stream and terminate accordingly.
Furthermore, I have created a generic command \MakeDeclarationOf which takes syntax such as
\MakeDeclarationOf\MakeUppercase\UppercaseIt
\MakeDeclarationOf\bang\Foo
to create the declaration \UppercaseIt to make subsequent things uppercase or \Foo to make subsequent things operated on by \bang.
When \MakeDeclarationOf\MakeUppercase\UppercaseIt is invoked, it makes a tokencycle environment with the name \UppercaseIt. An auxiliary command, \testendgroup is used by the tokencycle to check for end-of group/environment tokens in the input stream and, finding one, to insert the tokcycle universal terminator \endtokcycraw in the input stream.
Thus, \UppercaseIt can be terminated with \endUppercaseIt, with a }, with an \egroup, with an \endgroup, or with an \end (if at the current environment depth).
When terminated, the tokencycle takes the collected tokens of the input stream and applies a wrapper consisting of the first argument that had been supplied to \MakeDeclarationOf. Thus, the net result of having something like {\UppercaseIt abc} is that the following tokens are executed: \MakeUppercase{abc}.
The following MWE makes two such declarative commands, to demonstrate that multiple declarations don't interfere with each other.
\documentclass{article}
\usepackage{tokcycle}
\newcounter{envlevel}
\newcommand\MakeDeclarationOf[2]{
\xtokcycleenvironment#2
{\addcytoks{####1}\testendgroup}
{\processtoks{####1}\testendgroup}
{\trackenvs{####1}\addcytoks{####1}\testendgroup}
{\addcytoks{####1}\testendgroup}
{\setcounter{envlevel}{0}}
{\cytoks\expandafter{\expandafter#1\expandafter{\the\cytoks}}}%
}
\newcommand\trackenvs[1]{%
\ifx\begin#1\stepcounter{envlevel}\else
\ifx\end#1\addtocounter{envlevel}{-1}\fi\fi
}
\newcommand\testendgroup{\tcpeek\z
\ifx\egroup\z\tcpush{\empty\endtokcycraw}\else
\ifx\endgroup\z\tcpush{\empty\endtokcycraw}\else
\ifx\end\z\ifnum\value{envlevel}=0 \tcpush{\empty\endtokcycraw}\fi\fi
\fi\fi
}
\newcommand\bang[1]{!#1!}
\begin{document}
\MakeDeclarationOf\MakeUppercase\UppercaseIt
\MakeDeclarationOf\bang\Foo
Here is {\Foo declaration test} to see \textbackslash bang
This is a test \UppercaseIt of finding endUppercaseIt
\endUppercaseIt
This is a test {\UppercaseIt of finding right brace}
continuing...
This is a test \bgroup\UppercaseIt of finding egroup\egroup
continuing...
This is a test \begingroup\UppercaseIt of finding endgroup
\endgroup continuing...
Test \Foo of \begin{itshape}terminating at\end{itshape}
the proper \textbackslash end
\end{document}

\itshapetells TeX to just change the font, while\MakeUppercase, which uses\uppercase, has to have an argument. You can do some hacking, like here, but it won't work exactly the same way – Phelype Oleinik Mar 04 '20 at 20:17\textitand\itshapeare two different ways of changing a font.\Uppercaseit, to be parallel with\itshape, would require that you have an all-uppercase font. – barbara beeton Mar 04 '20 at 20:17\UppercaseItwhich makes lowercase-characters active and defines them to expand to their uppercase-pendants. (But this will break macros which check for character tokens with specific character codes and category codes rather than just character codes. It will also not work with macros that expand to non-active lowercase character tokens. Therefore probably a mechanism is preferable where uppercasing takes place when all expansion-work is done. I think that's why people usually stick to\MakeUppercase. The textcase package might also be of interest.) – Ulrich Diez Mar 06 '20 at 11:07\textit{\catcode`\A=13 A}the secondAis not active. With{\itshape\catcode`\A=13 A}the secondAis active. – Ulrich Diez Mar 06 '20 at 11:17