Agent Workflows

MCP turned agent tools into an interface

6 min read

MCP made agent tool access feel like an interface instead of a pile of bespoke integrations.

That is the interesting part. Tools already existed. Function calling existed. Agents could call APIs, read files, search databases, and run commands before MCP. But every integration had its own shape. The agent had to learn a new tool contract each time, and the host application had to decide how to expose tools, data, prompts, authentication, errors, and permissions.

The Model Context Protocol gave that work a shared vocabulary: clients, servers, tools, resources, prompts, schemas, and capabilities.

That does not make tool use safe by itself. It makes the design questions easier to see.

tool access is an interface

Once a server exposes a tool to an agent, it has designed an interface.

The interface includes the tool name, description, input schema, output shape, permissions, error behavior, and side effects. If any of those are vague, the agent has to guess. Agents are very willing to guess.

A tool named run is a problem. A tool named create_invoice_draft is better. A schema that accepts data: any is a problem. A schema with required fields, enums, limits, and clear descriptions is better.

MCP did not invent this discipline. It forced it into view.

{
  "name": "create_invoice_draft",
  "description": "Create a draft invoice. Does not send it to the customer.",
  "inputSchema": {
    "type": "object",
    "required": ["customerId", "lineItems"],
    "properties": {
      "customerId": { "type": "string" },
      "lineItems": {
        "type": "array",
        "items": {
          "type": "object",
          "required": ["description", "amountCents"]
        }
      }
    }
  }
}

The important sentence is in the description: “Does not send it to the customer.” That is product behavior and safety behavior in one line.

resources and tools should not be blurred

MCP separates resources and tools for a reason.

Resources provide context. Tools perform actions. That difference should matter in the product. Reading a document, listing projects, and fetching a schema are different from sending an email, editing a file, or changing a customer record.

If the interface blurs read and write operations, approvals become messy. A user may approve “access project data” and accidentally authorize mutation. A model may treat a read-like tool as harmless even though it triggers a side effect.

I want read paths to be boring and write paths to be explicit:

resource:
  workspace://docs/refund-policy

tool:
  update_customer_billing_contact
  requires approval
  logs audit event
  can be rolled back manually

That separation helps the host, the user, and the agent reason about risk.

descriptions are part of the control plane

Tool descriptions are not documentation garnish.

The model uses them to decide which tool to call and how to call it. A weak description can misroute work. A vague description can encourage overuse. A missing warning can hide a side effect. A bloated description can waste context and still fail to say the one thing that matters.

Good descriptions are compact and operational:

Search current support articles by keyword and product area.
Use this before answering policy questions.
Does not search archived articles.

That gives the model a purpose, a recommended use, and a boundary.

Bad descriptions sound like marketing:

Powerfully search our rich support knowledge base to unlock helpful answers.

That tells the model almost nothing.

permissions need to be visible before execution

MCP gives a common shape for connecting tools, but permission is still the host’s job.

The host has to decide which servers are allowed, which tools are available, which resources can be read, which calls need approval, and what the user sees before a tool runs.

For risky tools, approval text should be specific:

Approve editing `src/routes/billing.ts` in this workspace.
This tool can modify files but cannot access paths outside the repository.

That is much better than:

Approve tool call?

The approval is part of the interface. If the user cannot understand the effect, the permission model is not finished.

errors should be model-readable

Tool errors are a major part of agent behavior.

If a tool returns failed, the agent may retry blindly, apologize, or invent a workaround. If the tool returns a structured error, the agent has a chance to recover.

{
  "ok": false,
  "code": "permission_denied",
  "message": "The user can read invoices but cannot create invoice drafts.",
  "recoverable": true,
  "next": "Ask a workspace owner to approve invoice drafting."
}

That error tells the model what happened and what not to do next. It also gives the UI something useful to show.

Agent tools need error contracts for the same reason APIs do. The caller is trying to decide the next step.

receipts matter more as tools get real

Tool calls should leave receipts.

For read operations, the receipt might be which resource was read and at what version. For write operations, it should include what changed, who authorized it, and how to inspect or reverse it. For external calls, it should include the target system and result.

{
  "tool": "update_issue_status",
  "issue": "PLAT-184",
  "from": "in_review",
  "to": "done",
  "authorizedBy": "jeremy",
  "receipt": "audit://agent-runs/2024-12-02/184"
}

Without receipts, agent work becomes hard to audit. The final answer says something changed, but the system has no durable record.

MCP makes tool calling easier to standardize. The product still has to decide what evidence survives.

the interface will attract governance

Once tools have a shared shape, governance naturally moves there.

Which tools can a given agent see? Which ones require approval? Which servers can run locally? Which tools are allowed in CI? Which descriptions are trustworthy? Which outputs can be passed to another tool? Which resources are sensitive?

Those questions should not be scattered across prompts. They belong in the host, server configuration, permissions, and audit layer.

That is why MCP feels bigger than a connector format. It creates a place where agent capability can be inspected.

the useful shift

MCP did not solve agent safety. It did not make every tool well designed. It did not remove the need for approvals, scoping, logging, or evaluation.

It did something more basic: it turned agent tools into an interface people could argue about.

That is progress. Once the interface is visible, teams can improve names, schemas, permissions, descriptions, errors, receipts, and review paths. Before that, tool access is mostly integration glue and vibes.

Agents get better when their tools have real contracts.

Jeremy London

About Jeremy London

Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.