Mathematically, an ES256 (ECDSA over the curve P256R1) signature is a pair of numbers (r,s) between 1 and an upper bound which is very slightly less than 2^256. There are two common representations for this signature. JWA uses the “raw” representation: two big-endian numbers represented each with exactly 32 bytes, concatenated together. mbedtls_ecdsa_write_signature uses the ASN.1 DER representation, which as you noticed represents each number in a type+length+value format.
The DER format removes leading zeros from the number, then adds a leading 0 bit to each number which is a sign bit (the numbers in an ECDSA signature are always positive, but DER can also represent negative numbers). Therefore each number has a roughly 1/2 chance of using 33 value bytes with a leading 0 byte (1 sign bit + 7 value bits, all 0), a 63/128 chance of using 32 value bytes, and a 1/128 chance of using 31 value bytes or less because the 7 most significant bits of the number were 0. A shorter number in an ECDSA signature is not invalid, it's a 1/128 chance (independently for each of r and s).
To get the signature in raw format with Mbed TLS, the easiest way is to use the PSA API, where the output of psa_sign_hash() for ECDSA is the raw format. With the classic Mbed TLS API, the easiest way is to call mbedtls_ecdsa_sign() or mbedtls_ecdsa_sign_det_ext() to get r and s as bignums, then use mbedtls_mpi_write_binary() to write r and s with their exact size into the output buffer. You can find an example in the internal function psa_ecdsa_sign(): https://github.com/ARMmbed/mbedtls/blob/mbedtls-2.24.0/library/psa_crypto.c#...
Hope this helps,