MCP for AI Agents: Safer, More Composable Tools
Learn how to design MCP tools for AI agents with clearer API boundaries, safer defaults, and a practical split between agent reasoning and reliable workflows.

What Building Co-op Translator MCP Taught Me About Agent Tool Design
Turning a command-line tool into an MCP server sounds like a simple interface swap: take what you already built, expose it as tools, and let an agent call them. In practice, it dodges the real question. A command designed for a person and an API designed for an agent serve different users - even if they end up doing the same job.
Co-op Translator started as a CLI for translating Markdown files, Jupyter notebooks, and text inside images. A person runs one command and expects the tool to discover files, translate the content, update paths, and write the results. An agent working inside a project behaves differently: it gathers context, picks a small action, checks what happened, and decides what to do next. That changes what "good" looks like in an agent-facing API.
Building Co-op Translator MCP made a few design choices hard to ignore: break broad workflows into composable operations, make workspace-changing actions safe by default, and split document-language work from document-handling work. Here's how those choices shaped the tools - and where the approach runs out.
Why are CLI tools and agent APIs designed differently?
A CLI is usually built around a human goal. A developer decides what they want, runs a command, and expects the tool to handle the steps end to end. An agent-facing API is part of a decision loop. The agent needs to know what each operation changes, what it returns, and what it should do next.
That difference changes the right level of abstraction. A command like translate -l "ko" -md -nb -img can be a perfectly reasonable interface for translating a repository. It can find files, translate text, choose output locations, rewrite links, update metadata, and clean up old assets. The user asked for an outcome, not a tour of the implementation.
But if you expose that "all-in-one" operation as the only agent tool, the results can be hard to interpret. Did the text translate but the link rewrite fail? Did the tool write files and then stop halfway? Should the agent retry the whole workflow - or only the part that failed? The more responsibilities a tool bundles, the harder it is for the agent to reason about partial completion and recovery.
Convenience and control are different design goals
This isn't an argument that broad tools are always bad. A project-level operation can still be useful because it gives humans (and agents) a complete, repeatable workflow. The key is that it shouldn't be the only interface the agent can use when it needs to inspect or control individual steps.
A useful distinction is:
- Human-facing interfaces optimize for convenience and finishing a whole task.
- Agent-facing interfaces should make scope, inputs, side effects, and outputs obvious.
- Shared lower-level operations should do one narrow job and be easy to test and reuse.
You can share code between those layers without forcing the same "shape" on the interface. The CLI can orchestrate the broad workflow, while the MCP server exposes smaller operations for situations where the agent needs control.
The practical test: can the agent recover?
When a tool feels "too broad," don't just look at the happy path. Ask what the agent can actually learn when the operation partially succeeds, times out, or produces something unexpected. If the only recovery option is "rerun the command and hope it doesn't rewrite more of the project than you intended," the boundary is probably too coarse.
What you're aiming for isn't "turn every function into a tool." That usually creates an API surface the agent can't navigate. The goal is a small set of operations with clear responsibilities and effects. Good boundaries let an agent inspect, act, and recover without guessing what happened.
How should you decompose an agent-facing workflow?
Start by looking at what the existing workflow hides. In Co-op Translator, translation isn't only "turn English into Korean." The tool also has to preserve document structure, decide where output belongs, rewrite paths, reconstruct notebooks, and normalize translated content.
Those steps don't need to live inside the same operation. The API can split content transformation from project orchestration. For example, Co-op Translator defines separate operations for translating Markdown content, rewriting Markdown paths, and running the full translation workflow:
translate_markdown_content(document, language_code, options)handles document translation.rewrite_markdown_paths(content, source_path, target_path, policy)updates links when the source and destination are known.run_translation(...)coordinates a full project-level job.
The exact names matter less than the explicit division of responsibility. With this split, the caller can translate content without asking the tool to decide where a file should be written. It can rewrite links only after it knows the destination. Or it can use the orchestrated operation when it truly wants a complete repository-level run.
Separate decisions that happen at different times
A clean boundary often shows up when the system gains information - or has to make a decision. Path rewriting depends on both the source and target paths. If you bundle path rewriting into the content-translation step, the operation either has to guess those paths, accept extra coupled inputs, or take ownership of decisions that should really stay with the caller.
Separate steps and the data flow becomes easier to understand:
- Prepare or translate the content.
- Establish the source and destination context.
- Apply path changes using an explicit policy.
- Decide whether to write the result or keep reviewing it.
This pattern applies beyond translation. Any agent workflow that edits code, updates records, or generates reports works better when analysis, transformation, and persistence are clearly separated. If the agent can check an intermediate result before a consequential action, it's more likely to catch a wrong assumption early.
Keep a high-level path for repeatable work
Decomposition shouldn't force every caller to assemble the whole workflow by hand. That just moves complexity from the tool into the agent - and makes routine jobs less reliable. A project-level operation still matters when its behavior is well-defined and the caller wants a standard end-to-end process.
So the interface ends up layered: narrow operations for inspection and composition, plus a higher-level operation for routine orchestration. The CLI can stay convenient, and MCP can expose both the complete workflow and the smaller steps. You get an interface that matches the task, not one abstraction that every caller must use.
A practical review question is: Can a caller use each operation independently, and is there still a clear path for common end-to-end jobs? If both are true, the API is more likely to serve humans and agents without making either one carry unnecessary complexity.
Why do MCP tools need safer defaults?
An MCP server isn't just a wrapper around existing functions. Its tools get called under a host application and an AI model - often while the agent is operating inside a real project directory. That makes side effects part of the interface design.
A repository translation can create or replace lots of files. If a default tool call immediately writes changes, an agent can modify the workspace before the user has seen what it plans to do. Even a well-intentioned request can turn into an overly broad change when the agent lacks the full context of what's safe to modify.
Co-op Translator starts repository translation through MCP in dry-run mode. A request can specify the target language, project root, and file types while keeping the operation non-destructive:
{
"language_codes": "ko",
"root_dir": ".",
"markdown": true,
"dry_run": true
}
If you want to write, you have to make an explicit step beyond the preview. The principle here isn't "every tool must always be a dry run." It's that the default should match the cost and reversibility of the action.
Match confirmation to the impact of an action
A good tool design separates "collect information" actions from "change state" actions. Listing files, inspecting configuration, or preparing translation chunks usually has less impact than overwriting documents or removing generated assets. The more consequential the side effect, the more important it is to clarify scope and intent before proceeding.
For an agent-facing tool, helpful guardrails include:
- A preview or dry-run mode for broad changes.
- Explicit inputs for the project root and target language.
- A clear indication of which files would be affected.
- A deliberate confirmation step before writing or deleting data.
- Results that distinguish completed work from skipped or failed work.
These controls also make debugging easier. If something unexpected happens, explicit inputs and a preview help explain how the request turned into the result. Safety and operational clarity reinforce each other.
Avoid turning confirmation into friction
There's a trade-off. If a workflow asks for confirmation before every harmless action, users and agents will burn time approving noise. Guardrails should be proportional: inspect freely when it's safe, and pause for actions with meaningful - or hard-to-reverse - consequences.
Dry runs also aren't a substitute for accurate permissions or careful scoping. A preview that hides files the write step will later change creates false confidence. The preview has to represent the planned operation accurately enough for a person or agent to make a real decision.
A solid default supports progress without surrendering control. In practice, that often means: let the agent gather context and propose a change, then require explicit intent before the tool mutates a broad workspace. The tool still does its job - but it doesn't treat "the agent can write" as the same thing as "the user approved writing."
What should an agent translate, and what should the tool own?
The agent-assisted translation flow is a concrete example of separating model capability from the surrounding workflow. Co-op Translator can call a provider like Azure OpenAI or OpenAI directly. That provider-backed mode fits production pipelines and repeatable automation, where the application controls which model performs the translation.
In an MCP setup, though, the host agent already has access to a language model. Calling a second provider just to translate Markdown adds cost, configuration, latency, and another credential boundary. For text documents, the tool can prepare the translation work and let the host agent handle the language step.
The workflow looks like this:
start_markdown_agent_translationprepares document chunks.- The host agent translates the returned chunks using its available model.
finish_markdown_agent_translationreconstructs and normalizes the document.
This isn't just about saving one provider call. It assigns responsibilities to the component that's best positioned to handle them.
Let the model handle language; let the tool protect the document
A host agent is great at producing translated text. Co-op Translator handles the document-specific stuff around that text: chunking content, preserving code placeholders, reconstructing frontmatter, replacing Markdown cells in notebooks, and normalizing the result after translation.
This split helps avoid a common failure mode in AI document workflows. The model can write fluent language and still accidentally damage the structure around it. Code blocks, links, metadata, and notebook cell types aren't translation targets, even though they're surrounded by text that is. A workflow tool can make those constraints explicit instead of trusting the model to remember every boundary in a long document.
If a user asks for a Markdown file translated into Korean while keeping formatting, code blocks, and links intact, the agent can prepare the job through MCP, translate the prepared chunks, and pass the translated text back for reconstruction. The model brings language skills; the tool provides a controlled document workflow.
Keep provider-backed processing where the content requires it
This doesn't mean every translation feature should become agent-driven or keyless. Images are different from Markdown. Translating text inside an image needs more than language generation. The system needs text extraction, bounding boxes, and layout-aware rendering to put the translated text back into the visual design.
That's why image translation stays provider-backed and depends on Azure AI Vision for text and layout information. An agent can coordinate the task, but it doesn't remove the need for vision capabilities and rendering logic.
So there's a real product distinction here: MCP support doesn't require one execution model for every feature. Pick the model that fits the content and the operations required. Text documents can often use the host agent for translation while a dedicated tool protects structure. Image translation still needs vision and rendering. The boundary follows the work, not the preference for a uniform architecture.
What does this mean for building AI tools?
The main lesson from Co-op Translator MCP is that agent-facing APIs need clearer boundaries than human-facing CLIs. People often want a CLI to "just finish the job." Agents use tools as steps in a reasoning loop, where each result changes the next decision. The API has to make that loop inspectable and predictable.
This shows up in product design. A tool isn't useful just because a model can call it. The tool's inputs have to constrain what it does, its outputs have to support the next decision, and its side effects have to be understandable. Those qualities affect reliability as much as the model's ability to reason.
A design checklist for agent tools
Before exposing an existing capability through MCP (or any agent interface), work through these questions:
- What is the operation's single responsibility? If it translates, writes files, rewrites paths, and deletes assets, decide whether those actions should be separately inspectable.
- What context must the caller provide? Make key choices - like project root, target language, and path policy - explicit instead of hidden behind assumptions.
- What changes outside the tool? Identify file writes, deletions, network calls, and other side effects. Make high-impact changes deliberate.
- Can the caller inspect intermediate output? An agent should be able to evaluate a proposed result before committing it when that review is useful.
- How does partial failure work? Return enough information to tell the difference between completed, skipped, and failed work, and make recovery realistic.
- Which component owns each capability? Don't pay for or configure a second model when the host agent can handle the language step - but keep specialist services where the task genuinely needs them.
This checklist isn't an argument for splitting everything into tiny tools. Too many narrow tools create a different problem: the agent has to choose among a pile of functions and stitch together routine sequences correctly. The goal is a manageable set of operations grouped around meaningful decisions and clear side effects.
Think beyond whether the demo works
A demo can show that an agent can call a tool. It doesn't prove the tool behaves well across a big repository, an interrupted run, a surprising input, or a user's existing uncommitted changes. Real readiness depends on what happens when the expected sequence breaks.
That's why dry runs, explicit boundaries, and recovery paths should be treated as product decisions, not just implementation details. They decide whether the feature is actually trustworthy in everyday workflows. The best design isn't necessarily the one with the most autonomous agent. It's the one that makes useful progress while keeping consequences visible and manageable.
Conclusion
Building Co-op Translator MCP drove home a practical principle: agent-facing APIs should expose clear decisions, not just whatever functions you already had. The CLI can stay broad and convenient, while the MCP interface supports composable steps, visible side effects, and safer defaults for work inside a real project.
The split also matters. Let the host agent handle language reasoning when it already has the model it needs, and let the workflow tool protect document structure, paths, and reconstruction. Keep specialist services where they're truly required, like detecting and laying out text in images.
If you're designing your own agent tools, start with responsibilities and consequences. Make it easy to see what will happen, require intent for high-impact changes, and keep recovery straightforward when something goes wrong. That's what turns a callable tool into something you can actually trust.