The answer was to flatten these ridiculous hierarchies iteratively as an alternative of recursively. SwiftText now handles arbitrarily deep nesting with out breaking a sweat.
The Phrase Doc Downside
I wished brokers to provide editable paperwork that non-Apple individuals may truly use. HTML isn’t actually editable, and PDFs are static printouts. However DOCX? That’s the lingua franca of the enterprise world.
Behind the scenes, DOCX is only a strict XML dialect in a ZIP archive — conceptually just like HTML. So I carried out the conversion (#5):
swifttext render doc.md -o doc.docx
The output matches the PDF renderer’s styling: Helvetica Neue physique textual content, sized headings with backside borders, code blocks as single-cell tables with correct padding. Good to have this feature accessible for the long run…
SwiftMail
SwiftMail sparked extra group curiosity than I anticipated. Contributors discovered bugs, recommended enhancements, and submitted PRs. The library noticed heavy use in Submit, which meant each edge case in my mail circulate turned a possible bug report.
The Threading Nightmare
Message-IDs seem in every single place in electronic mail: the Message-ID header, In-Reply-To, References. They’re all alleged to be within the format , however SwiftMail saved them as uncooked strings with inconsistent angle-bracket dealing with (#122).
This induced refined bugs in Submit’s reply drafting — threading headers would generally have double angle brackets, generally none. The repair was to introduce a correct MessageID worth kind:
let id = MessageID(localPart: "abc", area: "instance.com")
print(id.description) // ""
Now angle brackets are dealt with appropriately in every single place, and threading headers simply work. And we unified this between SMTP and IMAP, in order that the identical kind will be spherical tripped. I went by way of hundreds of emails in my archive and couldn’t discover a single message ID that didn’t adhere to the usual.
The Buffer Restrict Downside
Reasonably than forcing callers to handle batch sizes manually, I made chunking automated and clear. Request 10,000 messages? SwiftMail splits it into manageable chunks internally. The API stays clear.
The Calendar Invite Downside
ICS recordsdata have been being handled as textual content our bodies as an alternative of attachments. This meant calendar invitations from Outlook customers weren’t correctly extracted by Submit’s mail-room. The repair? Accurately classify textual content/calendar elements as attachments (#126) and provides them a default invite.ics filename when none is specified.
The Linux SSE Downside
SwiftMCP’s SSE shopper didn’t work on Linux. It used URLSession.bytes(for:), which isn’t accessible in FoundationNetworking. The runtime simply threw unsupportedPlatform.
The repair was a URLSessionDataDelegate that streams incoming bytes into an AsyncStream, feeding the identical SSE parser used on Apple platforms. Identical conduct, totally different plumbing. Now SwiftMCP purchasers work identically on macOS and Linux.
Submit
Submit matured from a working prototype to one thing I truly depend on each day. The mail-room ability kinds my invoices, archives newsletters, routes GitHub notifications to Discord, and marks spam that my server-side filter missed. Getting right here meant fixing quite a lot of stability points.
A consumer – a buddy 😇 – tried to fetch their total mailbox — hundreds of messages — and SwiftMail crashed. The FETCH command line was too lengthy, exceeding NIO’s buffer limits (#118). So we added some inside batching to keep away from this drawback.
The Connection Race
The unique structure used two persistent IMAP connections per server: one for IDLE (watching for brand spanking new mail) and one for fetching. The fetch connection wanted periodic NOOP instructions to remain alive — roughly each 17 minutes. However servers timeout connections after about 26-27 minutes.
See the issue? The NOOP interval races with the server timeout. Generally the NOOP arrives too late, the connection dies, and restoration takes 60 seconds with a bunch of log noise (#3). I tasked an AI with analyzing mail.app’s connection logs and piece collectively the IMAP idle methods for GMAIL in addition to Dovecot. This knowledgeable the brand new technique for SwiftMail.
The answer was easier than I anticipated: make fetch connections ephemeral. Create them on-demand when new mail arrives, reuse them if nonetheless alive, dispose if useless. No extra NOOP heartbeat. No extra races. The IDLE connection stays persistent (the IDLE protocol naturally retains it alive), and fetch connections are short-lived by design.
The SIGPIPE Downside
This one was sneaky. If a hook script crashed whereas postd was nonetheless writing JSON to its stdin, the OS would kill the daemon with SIGPIPE. Not “log an error and proceed” — full daemon dying.
The repair was one line: explicitly ignore SIGPIPE. Now Submit logs “Damaged pipe” and retains working.
The Zero-Config Downside
The unique setup required a ~/.publish.json config file even when all of your credentials have been within the keychain. That’s friction I didn’t want.
Now Submit auto-discovers servers from the keychain (#1). One command is all you want:
publish keychain add private --host imap.gmail.com --port 993
postd begin # discovers "private" robotically
SwiftMCP
The MCP framework went from 1.1.0 to 1.4.0 in two weeks. That’s not model inflation — every launch addressed actual wants from my shopper mission.
Right here’s the factor about MCP: it’s an incredible protocol for APIs basically, not simply AI brokers. You get formalized infrastructure for bidirectional messaging — the server can push to the shopper, not simply reply to requests. And since SwiftMCP generates Swift code for either side, you don’t have to consider the wire protocol. Outline your @MCPServer, and the shopper proxy comes without cost.
Whereas implementing shopper and servers for an enormous mission I’m engaged on today, I discovered – and eradicated – many extra tough edges and lacking options.
From Logs to Structured Notifications
Initially, I used to be piggy-backing standing updates into regular log notifications. The server would emit a log message like “Queue: 3 jobs working, 0 errors” and the shopper would parse it. That felt silly.
The MCP spec permits customized notifications with arbitrary structured knowledge. So I made that attainable in SwiftMCP. Now my daemon broadcasts well being standing as a correct typed notification:
TRACE: [SwiftMCP] Acquired JSON-RPC message: {
"jsonrpc": "2.0",
"methodology": "notifications/healthChanged",
"params": {
"concurrencyLimit": 4,
"errorCount": 0,
"runningJobs": 0,
"uptimeSeconds": 210.67,
"model": "0.1.0"
}
}
The shopper defines a Codable struct and will get compile-time kind security:
struct HealthStatus: Codable {
let concurrencyLimit: Int
let errorCount: Int
let runningJobs: Int
let uptimeSeconds: Double
}
extension MyClient: MCPServerProxyNotificationHandling {
func handleNotification(_ methodology: String, params: HealthStatus) async {
if params.errorCount > 0 {
logger.warning("Server reporting (params.errorCount) errors")
}
}
}
Useful resource Subscriptions
MCP has an idea of “sources” recognized by URI. I wanted purchasers to look at particular person queue objects — submit a job, get a URI again, monitor its progress.
Now there’s full help for useful resource subscriptions. The shopper calls subscribeResource(uri:), and when that useful resource adjustments, the server broadcasts an replace to all subscribers. On the server facet, you simply name broadcastResourceUpdated(uri:) at any time when state adjustments. SwiftMCP handles the subscription monitoring and fan-out.
This turned my queue system from polling-based to push-based. A lot cleaner.
The File Measurement Downside
My shopper mission wanted to add paperwork to an MCP server. Base64 encoding works for small recordsdata, however falls aside rapidly for something substantial — the JSON payload balloons, you hit message measurement limits, and every thing grinds to a halt (#73).
The brand new structure makes use of CID-based uploads: purchasers ship cid: placeholders in instrument arguments, add recordsdata to POST /mcp/uploads/{cid} concurrently, and the server delivers the information to your instrument operate transparently. There’s even progress notifications throughout add. Opting in is one protocol conformance:
@MCPServer
struct MyServer: MCPFileUploadHandling { }
The following steps listed below are being a bit smarter about reminiscence on the server facet. As a substitute of retaining all of it in RAM a number of occasions, I’m pondering to stream the binary knowledge straight to recordsdata and to make use of memory-mapped Knowledge as an alternative. Additionally there must be a binary file obtain performance that bypasses the MCP base64 method. Nonetheless considering greatest do this.
The mDNSResponder Downside
Submit’s daemon makes use of Bonjour for native MCP discovery. In the future it simply stopped working. The logs confirmed: “DNS Error: ServiceNotRunning.”
Seems macOS’s mDNSResponder had restarted (which occurs extra typically than you’d assume — community adjustments, sleep/wake, system updates), and my Bonjour listener died with it (#77).
The repair was a generation-based state machine with exponential backoff. When mDNSResponder dies, SwiftMCP retries: 1s → 2s → 4s → 8s → as much as 60s max. When it comes again, the listener recovers robotically. No extra 1-second retry spam, no extra orphaned duties.
SwiftMCP Meets Xcode
And now for the shock: Xcode now exposes an MCP server. You possibly can allow it underneath Settings → Intelligence → “Enable exterior brokers to make use of Xcode instruments.”
Right here’s what you see if you happen to take a look at it with Claude Code:

Including it to Claude was fast and painless — however my first intuition was to generate a SwiftMCP shopper proxy so I may remote-control Xcode from any Swift app:
swift run SwiftMCPUtility generate-proxy
--command "/Purposes/Xcode-beta.app/Contents/Developer/usr/bin/mcpbridge"
That’s when issues acquired attention-grabbing. Xcode by no means confirmed the approval dialog. After some debugging, I found the proxy generator wasn’t sending the notifications/initialized notification after the initialize handshake. The MCP spec requires this, and Xcode’s server is strict about it (#91).
Whereas fixing that, I additionally added shopper id — Xcode shows the shopper identify and model in its approval dialog:

The proxy generator now robotically derives the shopper identify from the MCP server’s marketed identify. For xcode-tools, you get an XcodeTools enum namespace with a Shopper actor inside — matching the construction you’d get from @MCPServer(generateClient: true).

The generator produces typed response structs for all 19 instruments, full with all of the documentation that the MCP instrument has within the schema.

And the Shopper actor with auto-derived naming:

You possibly can see the full generated XcodeTools.swift on GitHub Gist.
I’ve to say, Apple did a pleasant job right here. The MCP schema is nicely fleshed out — they’ve structured response sorts for every thing. BuildProjectResponse tells you precisely what you get again: success standing, construct log path, errors and warnings as typed arrays. Identical for RunTestsResponse, GetBuildLogResponse, and the remainder. It’s clear somebody thought in regards to the developer expertise. My one gripe? A lot of the struct sorts lack documentation feedback, despite the fact that the MCP spec helps descriptions for each area. A missed alternative — however the sorts themselves are self-explanatory sufficient.
Oh and the opposite gripe: you could have open any mission you need to work together with. You want tab IDs for nearly all operations. However it’s an incredible and really shocking initiative from Apple!
Earlier than all this works although, it’s important to additionally allow the “Enable exterior brokers to make use of Xcode instruments” swap discovered underneath Intelligence.

Conclusion
RL (“actual life”) work drives probably the most attention-grabbing enhancements to my open supply tasks. When one thing feels off then I simply need to repair it instantly. Or reasonably, have an agent repair it instantly.
An enormous shopper mission pushed me to shine SwiftMCP to be used as API, and my curiosity within the Xcode MCP instruments benefitted the shopper proxy elements of SwiftMCP. I used to be pondering if it is perhaps attention-grabbing to auto-generate a CLI instrument for Xcode Instruments. This is perhaps an incredible instance for utilizing the MCP utility….
The opposite enhancements have been pushed principally by me engaged on my OpenClaw’s capacity to learn and mange my inboxes. Increasingly more I’m utilizing the options to draft me a electronic mail responses. For these my agent can get the markdown illustration of a HTML electronic mail and craft a markdown response interleaving the > quoted questions of the e-mail being replied to. And naturally threading headers get preserved to. The following step there’s so as to add the characteristic of truly additionally sending such drafts.
Busy occasions!
Associated
Classes: Updates
