How do you construct a grep & command to match a number of patterns depending on how many are provided at runtime?

You can leverage the printf builtin.

mo1 () {
  for file in *.txt; do
    grep -n -C1 "$(printf "%s.*" "$@")" "$file"
  done
}

This simple version inserts .* after the last element. It doesn't matter for this specific use case, but in other cases (e.g. grep -o) you may need to strip off the extra .* at the end.

mo1 () {
  pattern=$(printf "%s.*" "$@")
  pattern=${pattern%??}
  for file in *.txt; do
    grep -n -C1 "$pattern" "$file"
  done
}

In bash, you can put the printf output directly in a variable, which is slightly faster than using a command substitution (but this is unlikely to ever matter, even on Cygwin where subshells are slow).

mo1 () {
  printf -v pattern "%s.*" "$@"
  pattern=${pattern%??}
  for file in *.txt; do
    grep -n -C1 "$pattern" "$file"
  done
}

If you wanted to insert a single character between the positional parameters, you could set IFS to that character and use "$@". But that doesn't work if the separator is more than one character. In ksh and bash, if there's a character that doesn't appear in the pattern, you can use that for joining and then perform a replacement. For example, here, it wouldn't make sense for patterns to contain newlines, so:

mo1 () {
  typeset IFS=$'\n'
  typeset pattern="$*"
  pattern=${pattern//$'\n'/.*}
  for file in *.txt; do
    grep -n -C1 "$pattern" "$file"
  done
}

In zsh, of course, there's a direct way.

mo1 () {
  for file in *.txt; do
    grep -n -C1 ${(j:.*:)@} $file
  done
}