I used to think I should convert every API I needed into an MCP server. When I wanted to integrate JIRA into my agent workflows, that mindset led me straight into a classic learning experience.
JIRA already has solid, stable REST APIs. But I saw an MCP server for it and thought, "Why not try the new standard?" I plugged in my JIRA URL, username, and API token, started the server, and it just worked. The LLM could browse issues, update tickets, create new ones, smooth and magical for a single-user setup.
Then reality hit when I considered multiple users.
the multi-user wall
Different people on the team have different projects, roles, and permissions. With most open-source JIRA MCP servers, credentials get baked into the server process at startup. That meant one user equals one MCP server instance, complete with their own token, port, and management overhead. Spinning up, monitoring, securing, and rotating secrets for each person was a total pain.
Meanwhile, I already knew Atlassian's 3-legged OAuth (3LO) flow. I could let each user consent once, securely store and refresh their tokens on my backend, construct the proper JWT or Bearer headers, and make direct API calls that naturally respect their exact permissions. No per-user servers. Clean, scalable, and auditable.
That moment made me step back and think: "Why am I forcing MCP here when I own the APIs and can just call them directly?" It led me to believe the whole MCP story was broken.
But it's not broken. It's just not the right tool for every job.
direct tool calling, by default
Direct tool and function calling remains my default choice in most situations, especially when:
- I own or fully control the APIs.
- The interfaces are stable and well-documented.
- I'm building for a specific product, internal tool, or multi-tenant system where I already handle auth (OAuth, JWT, service accounts).
- I care about latency, simplicity, debugging, and full control over rate limits and error handling.
I define a clean JSON schema, hand it to the model, it emits arguments, I execute, and I'm done. No extra protocol, no discovery layer, no additional moving parts.
where MCP earns its keep
MCP shines when I need true composability: plug-and-play tools that work across different LLMs, clients, and vendors without rewriting glue code every time. Long-running agents, dynamic discovery, stateful sessions, and ecosystems where third parties can drop in tools like plugins. That's where it earns its keep.
the auth story is catching up
The protocol, especially the 2025-11-25 spec and the ongoing 2026 roadmap, has been aggressively addressing exactly the multi-user pain I ran into.
- OAuth 2.1 with PKCE is now standard for remote MCP servers, along with Protected Resource Metadata, better scope handling, and Dynamic Client Registration.
- Atlassian's own Rovo MCP Server uses proper OAuth 2.1 consent flows. Users authorize once through the browser, and it respects their existing JIRA permissions. No static tokens. No per-user server instances. Exactly the fix I needed.
Active proposals and improvements focus on:
- Tool-level authorization, so one server can safely serve many users with different scopes.
- On-Behalf-Of token exchange and finer-grained least-privilege controls.
- Enterprise features like SSO integration, audit logging, and Cross-App Access patterns.
These changes close the gaps fast, especially when the service provider (like Atlassian) hosts the MCP endpoint themselves.
my rule of thumb
- I own the APIs and they're stable? Direct tool calling wins. Lower overhead, easier to secure, full control. My JIRA experience proved it.
- I need plug-and-play across models and clients, or I'm building an open ecosystem? MCP becomes compelling.
- The provider ships a strong hosted MCP server with real OAuth? Take the win. Standardization with almost zero extra work.
- Multi-user or enterprise scale? Check the latest auth story for that specific MCP server. The ecosystem is catching up.
MCP isn't a universal hammer. It's a powerful standardization layer that's maturing in the right places. The LLM's real value is still the reasoning, deciding when and why to call something. Whether that call goes through a clean tool schema or a polished MCP server is mostly an engineering choice.
Choose what fits the job, not the hype. In my case, for JIRA and most owned APIs, direct calls are still the smarter, simpler path, and I'm glad I learned that before over-engineering with MCP.
If you're wrestling with a similar decision right now, I'd love to hear the details. I've walked this exact path more than once.