Making my AI agents default to MCP for Plane
I run my own Plane instance for issue tracking, and most of my work on it now goes through AI agents - create an issue, move it to In Progress, drop a comment, close it out. The problem was that the agents could not agree on how to talk to Plane.
Sometimes an agent called the Model Context Protocol (MCP) tools. Sometimes it wrote a quick curl against the REST API with my workspace key. Same operation, two completely different paths, and the choice depended on whatever the model felt like in the moment. That inconsistency is what I wanted to fix.
Why direct API calls are a problem
Plane ships an official MCP server. When an agent uses it, every operation goes through one defined contract: typed tools, known parameter names, structured errors. When an agent skips that and hits the REST API directly, I lose all of it.
- Schema drift. The MCP server knows that creating an issue needs
name, that states are UUIDs, that labels are an array of UUIDs. A hand-rolledcurlguesses, and the guesses rot when the API changes. - Auth sprawl. Direct calls mean the workspace API key shows up inline in commands and shell history. The MCP server holds the credential once and the agent never sees it.
- No shared error handling. When MCP fails, it fails the same way every time and I can reason about it. Fifteen different
curlone-liners fail fifteen different ways. - Auditability. “Use MCP for Plane” is a rule I can actually check. “Use whatever works” is not.
None of this is about the REST API being bad. It is about wanting one default path so the agents behave predictably and I can debug them when they do not.
The rule
I added a single rule to my agent instruction files (the equivalent of an AGENTS.md, plus the Cursor rules and the Claude Code project config):
Use the Plane MCP tools for all Plane operations. Do not call the REST API directly unless I explicitly authorize it.
The “unless I explicitly authorize it” half matters as much as the first half. A flat ban would be a lie, because I have real cases where the MCP path does not work or is too slow, and I would rather name those exceptions than pretend they do not exist.
Where I still bypass MCP
Three exceptions, each with a concrete reason.
Search is broken. The MCP server’s search tool calls Plane’s advanced-search endpoint, and that endpoint returns 403 You do not have permission to perform this action for my API key. It never returns results. So any agent that needs to find an issue by keyword has to fall back to listing issues over the REST API and filtering client-side. This one is not a preference, it is a defect I route around.
Performance-critical skills. One of my most-used agent skills lists “what should I work on next” for a project. The MCP version made four or five round-trips, paginated with a cursor, and wrote intermediate files that occasionally tripped permission prompts. A single REST call with explicit field selection does the same job in about two seconds. For a skill I run several times a day, that gap is worth the exception. The key detail: always request a narrow fields set, because the full issue payload includes HTML descriptions with control characters that bloat the response and break JSON parsing.
A client-side MCP bug. I hit this during my Linear-to-Plane migration. Cursor’s MCP client expects a parameter called title for issue creation, but Plane’s server correctly exposes name. The mismatch makes creates fail validation through that client even though the server schema is right. The workaround is to create issues over the REST API with the X-Api-Key header, the same approach my migration script already used. Everything else stays on MCP.
All three are authorized in writing, in the same rules file that sets the default. The agent is not improvising; it is following an exception I documented.
Reflection
- A default plus named exceptions beats an absolute ban. If the rule contradicts what I actually do, the agents learn to ignore it.
- MCP is a contract between three parties: the server, the client, and the model. When the client is picky or the server has a broken endpoint, direct HTTP is still a valid integration, not a rule violation.
- The win is consistency, not purity. I do not care that every byte goes through MCP. I care that an agent’s first move is always the same, and that the times it does something else are written down.
- Write the rule where the agent reads it. A preference in my head does nothing; a line in the project’s instruction file shapes every session.
Related reading
Cursor Tips: Optimize Your Workflow
Explore essential tips for using the Cursor IDE to enhance your development workflow, from organizing chats to using AI effectively.
Watching Claude work: VS Code in a cmux browser pane
Why I stopped juggling terminals for AI edits, how I run VS Code for the web beside Claude Code in cmux, and the config that ties it together.
The trailing blank lines EditorConfig did not fix
Cursor kept padding the end of my files with blank lines. I reached for EditorConfig, learned it does not actually solve that problem, and found the pre-commit hook that does.
Ready to Transform Your Career?
Let's work together to unlock your potential and achieve your professional goals.