MacDonald’s heroics wrecked Jambos boss Jim Jefferies’ dream of repeating his Hampden success of 1998.
Hearts had won eight of their previous nine Scottish Premier League games and substitute David Obua spurned their best chance under pressure from close range before Saints struck.
MacDonald, who came on 11 minutes from time, took advantage of uncertainty in the hosts’ defence to tuck into the bottom corner after 86 minutes to send the visitors through.
Hearts’ first defeat since the 3-0 loss to Kilmarnock in October ended Jefferies’ hopes of adding to the Scottish Cup win he secured in his first spell as boss over a decade ago.
Ten days after the cacophony of noise of the Edinburgh derby, the atmosphere was somewhat different with Saints welcomed by a half-full stadium after a ticket-pricing dispute between the clubs led Hearts to close the Wheatfield Stand.
Illness had afflicted the Hearts camp since the win over Hibs and they lacked their usual energy in a scrappy first half.
The hosts were also without influential midfielder Rudi Skacel, who won the cup with Hearts in 2006 but has been carrying a calf injury.
Saints, though, were buoyed following the late win over Inverness and absorbed early Hearts pressure as the hosts struggled to test Peter Enckelman in the Saints goal.
Ryan Stevenson shot wide, Kevin Kyle had an effort blocked, Arvydas Novikovas shot wide across goal and Marius Zaliukas headed off target in the opening 25 minutes.
Kyle, Hearts’ match-winner against Hibs, headed wide and was unable to reach a Stephen Elliott cross before Saints’ first half-chance came two minutes before the interval.
Sam Parkin volleyed wide, but soon after Jamie MacDonald was called upon to save Collin Samuel’s header after Hearts failed to deal with Chris Millar’s cross.
Zaliukas then had a shot blocked which ran away from Kyle in the area with the striker through unopposed.
After 53 minutes Dave MacKay headed across goal from Jody Morris’ free-kick only for the ball to evade everyone.
Saints captain Morris was then booked for a foul on Stevenson as Hearts countered.
Black’s free-kick was directed towards Ismael Bouzid and Danny Grainger headed over and Saints scrambled away the resulting corner.
Obua replaced Kyle after 57 minutes with the striker apparently limping.
Jamie MacDonald saved from Samuel after the Saints striker had latched onto Millar’s ball over the top, Bouzid doing well to make the angle more difficult.
Black was then replaced by David Templeton, with Jefferies adopting a more attacking approach.
Obua then spurned a terrific chance from close range after Ruben Palazuelos and Elliott had combined on the left, lifting the ball over the bar under pressure from Michael Duberry and Enckelman.
Steven May, on in place of Samuel, made space for himself but shot two yards wide of Jamie MacDonald’s goal.
With 14 minutes remaining, Calum Elliot came on for Novikovas, but despite Hearts’ ultra attacking play, Saints then enjoyed a spell of forward pressure.
Duberry had a headed chance and May was foiled by a good challenge by Eggert Jonsson.
Both sides won their most recent league games in the final five minutes and it was Saints who repeated the feat.
Peter MacDonald took advantage of indecision in the Hearts defence from Bouzid, Zaliukas and Hearts goalkeeper Jamie MacDonald to toe poke the ball in.
Enckelman was at full stretch to save from Elliott in stoppage time as Saints survived to progress and Hearts were left to focus on the league.