Skip to content
DWKD
Journal 8 min read Intermediate AI

The contract behind a useful AI integration

An agent can find the right tool and still make the wrong change. Design the contract that connects intent, permission, execution, and a verifiable result.

An assistant says the ticket was created. The ticketing system says two tickets were created. The person who asked for help now has to explain why two teams are working on the same problem.

Every connection in that story can be technically healthy. Authentication worked. The request reached the server. The response was valid. The failure lives between those facts: the application did not know whether an interrupted operation had already changed the world.

That is the useful starting point for APIs, Model Context Protocol, and agent interoperability. A connection gives software a way to communicate. A dependable integration needs an agreement about what the communication means.

Three layers, three different jobs

An API exposes operations and data from a system. It might retrieve a customer, create a ticket, or return an invoice status. The caller needs to know the input shape, authentication requirements, and possible responses.

MCP provides a common way for AI applications to discover and use capabilities exposed by servers. Its architecture separates the host application, its clients, and the servers providing resources, tools, and prompts. The host coordinates access and user authorization. That division is described in the MCP architecture specification.

Agent-to-agent communication has another concern: handing work to a remote agent and following its progress. A2A describes Agent Cards for discovering capabilities, tasks with lifecycle state, and artifacts returned from the work. Those concepts are documented in the A2A core concepts.

These layers can coexist. An assistant could use MCP to access a ticket tool whose implementation calls an ordinary API. A separate agent might investigate the ticket through A2A. Adding every layer is unnecessary when a single direct call already meets the requirement.

Start with the business verb

“Connect our CRM” leaves almost every important decision open. “Let a support representative create one internal follow-up task for the customer they are viewing” gives the integration a boundary.

The verb should reveal the effect. Read, draft, create, approve, send, and delete are different permissions. A tool called manage_customer hides those distinctions. Separate operations make the allowed behavior easier to describe, review, and revoke.

Then identify the business object. Is a customer an account, a location, or an individual contact? Does “owner” mean the person assigned today or the person who sold the contract? An AI application cannot repair a disagreement between two systems merely by exchanging valid JSON.

Write those definitions beside the operation. DWKD’s lesson on scoping an integration before anyone writes code provides a broader set of questions about direction, identity, freshness, and failure ownership. Use it to expose unknowns before choosing a protocol.

A tool description is part of the interface

People operating an application see labels, confirmation screens, and help text. A model selecting tools also needs clear descriptions. The tool should explain when it applies, what it cannot do, and which information must already be known.

The MCP tools specification defines input schemas and optional output schemas. These help make the exchange explicit. A schema can establish that a customer identifier is required; it cannot establish that the identifier belongs to the customer the user intended.

For that reason, pair structural validation with business validation. Check permitted account access, allowed state transitions, required approvals, and any relevant version of the record. Return useful errors such as “customer is archived” or “record changed since preview,” with a supported recovery path.

Keep descriptions honest about side effects. If creating a task also sends an email, that effect belongs in the contract. Otherwise an apparently internal action can become an external communication the caller never intended.

Work through one interrupted request

Consider an illustrative support workflow. A representative asks an assistant to create a follow-up task for customer C-104. The assistant prepares a title and description. The application displays the customer and intended change for review.

After approval, the server creates task T-882. The network drops before the caller receives the result. A naive retry creates T-883. Both tasks look legitimate because the system has no stable identity for the original intent.

A better design assigns the operation a request key before the first attempt. The server records the key together with the accepted input and outcome, using a transaction or equivalent atomic protection. A retry with the same key and same intent returns T-882. A reused key with different input is rejected.

The details depend on the destination API. Some support idempotency directly; others require a controlled wrapper or a reconciliation mechanism. A key written into a log after the change is insufficient if the process can crash between those steps. The failure needs to be designed as a sequence, not solved with a hopeful retry.

Build a contract someone else can test

The following is an illustrative contract for that task operation. It is a starting artifact, not a universal API specification. Replace the example limits with requirements for your own workflow.

Example contract: create an internal follow-up task
Decision Written rule
Intent Create one task for one customer; never send a customer message.
Identity Use a stable customer ID and the authenticated representative’s identity.
Inputs Customer ID, title, description, due date with time zone, and request key.
Permission Check customer access and task-creation permission on the server.
Precondition Customer exists and remains eligible when the change is committed.
Retry Same key and accepted input return the original result; changed input requires a new intent.
Receipt Return task ID, actual state, creation time, and trace reference.
Recovery Look up an uncertain outcome before attempting another write.
Owner Name the team that investigates a missing receipt or conflicting state.

Notice how little of the table depends on the model. That is a useful property. You should be able to test the operation from a conventional interface and obtain the same permission checks and effects.

Carry permission across every boundary

An assistant acting for a user should not silently inherit an administrator’s entire reach. Decide which identity each downstream system sees and which authority is being delegated. The server must enforce that decision even when a tool call arrives with plausible arguments.

Keep credentials out of prompts and business payloads. A request can include a customer ID without carrying the key that grants access to every customer. Scope credentials to the operation and resource whenever the destination supports it.

The MCP project’s security guidance specifically addresses token audience validation and forbids token passthrough in its authorization model. These are implementation requirements to inspect, not assumptions to make because a connector advertises protocol support.

Also distinguish data from instructions. A customer note returned by a tool may contain text that asks the assistant to perform another action. That text is business content, not a new authorization. Define allowed follow-up actions in application policy rather than allowing returned documents to expand the workflow.

Make uncertainty a visible state

An operation can be requested, accepted, running, completed, failed, or awaiting clarification. “No response” is another condition: the caller does not know the result. Treating that uncertainty as failure can trigger duplicates; treating it as success can hide missing work.

For a long-running agent task, keep a task identifier and retrieve state through the supported protocol. A progress message is evidence that something happened, but it is not the final artifact. A cancellation request also needs a confirmed outcome; it may arrive after an irreversible step.

Record enough information to connect user intent, permission decision, execution attempt, and result. A trace reference should make investigation possible without copying every sensitive document into every log. Set retention and access rules around what the investigation actually needs.

Define timeouts by stage. Waiting for a tool to accept work differs from waiting for the work to finish. A single timeout wrapped around everything can obscure which component failed and whether a retry is safe.

Test the disagreements before the happy path

A useful test set includes the ordinary request, but it should spend considerable attention on conflicting facts. Test a deleted customer, an expired credential, a stale preview, malformed output, and a permission revoked between preview and execution.

For the illustrative ticket workflow, proposed acceptance criteria are concrete: every valid request creates exactly one intended task; repeating a committed request returns its original receipt; every unauthorized attempt creates zero tasks; and every injected timeout can be resolved to a known state.

These are design targets for the example, not results from a completed DWKD deployment. Record the actual pass count and inspect failures individually. Passing ten ordinary cases does not compensate for one duplicate write in the retry test.

Test the explanation as well. Can a support representative understand what changed and what remains uncertain? A generic “something went wrong” message transfers all recovery work to the user. The failure-mode register gives you a place to assign detection, recovery, and ownership to each failure.

Know when the protocol adds no value

A scheduled export between two systems may need a simple API job. Introducing a conversational agent can add latency and ambiguous intent to a task that was already precise. Use a model when interpreting varied requests has value, and keep deterministic operations deterministic.

MCP becomes useful when standardized tool access helps multiple compatible clients or reduces repeated integration work. Agent delegation becomes useful when the remote service genuinely manages a task with its own lifecycle. Neither is a requirement for calling a database.

Maintenance also matters. Protocol versions, authentication behavior, and tool schemas change. Keep a small compatibility test against the client and server versions you actually use. Re-run the failure cases when either side changes, particularly when permissions or side effects change.

A narrow operation with a named owner can be expanded after it proves useful. An enormous connector with unclear responsibilities creates a larger surface for mistakes before anyone has established that users need it.

Show the thing

The finished artifact is a contract, a working demonstration, and a record of the failure tests. Show one successful request, one denied request, and one interrupted request that recovers without repeating the change.

Use synthetic customer records when sharing the demonstration. Include the operation name, intended effect, receipt, and explanation of what the result proves. Keep credentials and customer details out of the shared material.

If you have only designed the contract, label it as a design. If you have exercised the implementation, record the environment and date. The distinction lets another builder adapt the work without mistaking a plausible architecture for a verified integration.

That is the practical payoff of interoperability: another person can understand what crosses the boundary, connect a compatible caller, and verify that the promised action happened exactly as intended.

Source note: Official MCP and A2A documentation was reviewed on September 23, 2026. Protocol details can change; confirm compatibility with the versions in your deployment. The workflow, contract, and acceptance criteria above are illustrative design guidance.

Continue the field guides: Build automations that can retry without creating a second mess or The permission boundary belongs outside the AI prompt.

Try this

Choose one action you would like an assistant to perform, such as creating an internal support ticket. Draw four boxes: request, permission check, system change, and receipt. Under each, write one fact the next box must receive. Now interrupt the flow immediately after the system change but before the receipt. Describe how a second attempt discovers the existing result instead of creating another one. Ask a colleague to act as the caller while you act as the system, using only your written contract. Record the first ambiguity they find and resolve it before selecting a connector.