Projects

What I build, and the tools I reach for. Most of my open-source work lives on GitHub.

Software Engineering & FinTech

I work as a software engineer in the Open Banking space, where the systems I build move real money and real financial data. In that world, correctness, reliability, and security aren’t features you add later — they’re the baseline you start from. My work runs the full lifecycle: writing the plan and the system design, building the services, and owning them in production.

Most of my time goes into designing and operating microservices: a mix of Java / Spring Boot and Python services that talk over REST APIs and an event-driven backbone on RabbitMQ, all behind API gateways that handle routing, authentication, and rate limiting. Storage is split across PostgreSQL, Redis, and MongoDB, chosen per service depending on whether the job needs relational integrity, fast caching, or flexible documents — and a lot of the work is making systems that aggregate and make sense of financial data flowing in from many different banks.

The interesting problems live in the details. Money operations have to be idempotent and atomic — a retried request can never become a double charge, and a balance check and its deduction have to happen as a single, race-proof step. Every integration with an external or banking system is treated as untrusted input: validate every response, and design for the partner that’s slow, flaky, or simply down. I’ve written more about this kind of thinking in The Vulnerabilities That Don’t Break Anything.

I also own a good part of the road to production. All of it runs on Kubernetes across AWS and Oracle Cloud, deployed through Helm and GitOps. I write the CI/CD pipelines in Jenkins that build, test, and ship each service, with SonarQube quality gates keeping the code clean and secure before anything reaches an environment. When something misbehaves, I’m in there too — watching and debugging pods on Kubernetes, digging through logs, and tracing what actually happened. I lean hard on observability with Prometheus and Grafana, because in a regulated environment, “we think something broke” isn’t an answer. You need to know exactly what happened, when, and to whom.

The through-line across all of it: clean services, careful integrations, and production that stays up under real load.

Open Source

SpringBoost

The Laravel Boost equivalent for Spring Boot — an MCP (Model Context Protocol) server that gives AI coding assistants (Claude Code, Cursor, Codex, Gemini CLI) real, structured context about a Spring Boot application instead of letting them guess. Published on Maven Central (io.github.mhadiahmed:spring-boost), usable either as a standalone stdio MCP server registered against any project, or embedded directly as a Maven/Gradle dependency for deeper runtime introspection.

What it gives an AI assistant: 9 core MCP tools at exact parity with Laravel Boost — application info, database connections/schema/query, log reading, endpoint URL resolution — plus Spring-specific extensions (SpEL “Tinker” execution, endpoint listing, Actuator inspection) that Laravel Boost has no equivalent for. On top of that, an AI Guidelines and Agent Skills system mirrors Boost’s split: broad, always-loaded conventions per framework version, and focused, on-demand patterns for tasks like Spring Data JPA, Testcontainers, or Spring Security — auto-detected and published based on what a project’s pom.xml/build.gradle actually depends on, not a blanket dump of every guideline the tool ships with.

The interesting engineering problem wasn’t the tool integrations — it was making the stdio MCP connection itself reliable. Every failed connection looked like a JVM cold-start problem (Spring context boot is a few seconds, and AI editors have tight connection timeouts), and speed fixes kept “improving” the numbers while the connection kept failing anyway. Tracing actual bytes on the wire — not just logs — found the real cause: a JSON-RPC response was leaking extra, spec-illegal fields through Jackson’s default bean introspection (any isXxx() method gets serialized as a field whether you meant it to or not), and a strict client silently discarded the whole message as malformed rather than erroring loudly. The fix was a one-line annotation; finding it required refusing to trust “it’s probably just slow” and instead verifying, byte by byte, what a real client actually received. Solved properly with a shared background daemon architecture on top, so repeat AI editor sessions connect in well under a second instead of paying JVM+Spring boot cost every time.

k8s-log-explorer

A tool for exploring and analyzing Kubernetes pod logs, with advanced search across pods and namespaces.

Real-Time Chat

A real-time chat application built with Django Channels and WebSockets — async messaging over a persistent connection.

E-commerce Platform

A full e-commerce platform built with Django — product catalog, cart, checkout, and order flow.

More on my GitHub.