Enterprise Integration

Agents and Legacy Systems

MCP standardises how an agent reaches a tool server. It says nothing about what that server integrates with. Compare the tempting shortcut against the pattern that actually works.

Anti-pattern: expose legacy directly
Pattern: capability layer

Agent

must choose from

Generated MCP tools

340
ZFI_GET_DOC_HDR_02
ZFI_GET_DOC_HDR_03

SOAP / ERP

WSDL, no docs
Why it fails reliably

Context consumed before any work

340 tool descriptions occupy the window before the agent reads a single instruction.

Selection accuracy collapses

Choosing well among near-identical operations is a task models perform badly.

Coded values get guessed

A field with values 0147 is documented somewhere unmachine-readable, so the model fills the gap plausibly.

Security boundary is the union

Everything those operations can do — for an ERP interface, close to unlimited.

Every quirk becomes the model's problem

Solved probabilistically, and differently each time.

Optimises for the wrong milestone

Fast to build, expensive to operate.

Agent

chooses from

Capability layer

11
get_customer_credit_position()
task-shaped, semantics resolved

SOAP / ERP / batch

340 operations, hidden
Four properties that make it work

Task-shaped granularity

Designed from the agent's task decomposition, not the legacy system's structure. Eleven tasks means roughly eleven capabilities — not 340 operations, and not one god-tool with a mode parameter.

Semantics resolved, not forwarded

Tribal knowledge encoded once, in code, reviewably — instead of re-guessed by a model on every call. The highest-value single thing the layer does.

Knowledge / action separation

Read capabilities split cleanly from write capabilities, so governance can differentiate: reads broadly available, writes gated.

Idempotency added

Where the legacy interface cannot offer it, the layer implements a request key and deduplication window. This is what stops an agent retry double-posting a journal entry.

Semantics resolved at the layer
Legacy response
{
  "STATUS": "17",
  "DOCTYP": "RE",
  "WAERS": "EUR"
}
Capability response
{
  "status": "awaiting_credit_approval",
  "document_type": "invoice",
  "currency": "EUR"
}
Modelling the genuinely asynchronous
Submit

Capability returns a handle, not a result

Do not hide the asynchrony behind a synchronous facade that blocks for four hours — or worse, polls internally and times out at ninety seconds.

Poll

A second capability checks status

The agent's workflow gains an explicit waiting state rather than a blocked tool call.

Design test

Does the process tolerate four-hour latency?

Often yes — then build a workflow with agentic steps, not a conversation. Sometimes no — and the honest finding is that this use case needs a change to the underlying system, surfaced in week two rather than month five.

Reads broadly, writes narrowly. Build the read surface across as many systems as you can reach — an agent that answers "what is the status of this order across our four systems" is genuinely useful and cannot damage anything. For state changes, route through whatever validated path the business already uses, and start with propose-and-approve rather than propose-and-execute.