My MCP Server's Two API Helpers Had Zero except Blocks. Every Bad Call Crashed With a Raw urllib Traceback. A developer discovered that two API helper functions in their MCP server's claude -p wrapper, _gh() for GitHub and _dev() for DEV.to, lacked any exception handling, causing raw urllib tracebacks to propagate to the MCP client on errors like 404, 401, 422, and 429. The developer fixed this by adding consistent error handling to return 'ERROR:' prefixed strings, matching the pattern already used in the _claude() function. I've spent the last few weeks hardening one function in my MCP server's claude -p wrapper. First a timeout fix. Then it turned out the timeout fix didn't cover a non-zero exit code. Then it turned out that fix still didn't cover a missing binary. Three separate posts, three separate except clauses, all on the same six-line try block, until claude finally had a clean, consistent failure path: catch everything plausible, return a string prefixed ERROR: , never let a raw exception reach the MCP client. While going back through the rest of server.py to see if that pattern had actually spread anywhere else, I found the two functions that call an external API on almost every tool invocation — gh for GitHub, dev for DEV.to — had never gotten it at all. Zero try , zero except , in either one. python def gh path, method="GET", data=None : if method = "GET": raise ValueError f" gh is read-only — got method={method r}" req = urllib.request.Request f"https://api.github.com{path}", method=method req.add header "Authorization", f"token {os.environ 'GITHUB TOKEN' }" req.add header "Accept", "application/vnd.github.v3+json" with urllib.request.urlopen req, timeout=30 as r: return json.loads r.read def dev path, method="GET", data=None : req = urllib.request.Request f"https://dev.to/api{path}", method=method req.add header "api-key", os.environ "DEV TO API" req.add header "Content-Type", "application/json" req.add header "User-Agent", DEV UA if data: req.data = json.dumps data .encode with urllib.request.urlopen req, timeout=30 as r: return json.loads r.read Every one of this server's tools except generate commit message goes through one of these two functions: list articles , create article , update article , get article stats , get github profile , list repos , get repo stats . Seven tools, one shared blind spot. A wrong article id on update article gets a 404. An expired GITHUB TOKEN gets a 401. Too many tags on create article gets a 422. A burst of calls gets a 429. urllib.request.urlopen turns every one of those into an HTTPError exception, and with no except anywhere in either function, it just propagates straight out. I checked what that actually looks like on the wire, since "propagates out" undersells it if you haven't watched an MCP client eat a stack trace. Stubbed urlopen to always raise a 404 and called the tools directly: === calling update article article id=999999 === UNCAUGHT HTTPError propagated to caller: