← Building agentic patient workflows

Part 10 of 18 · 5 min read

MCP, A2A and the tool boundary

Scoped tool discovery, authenticated adapters and delegated task contracts.

Arunank Sharan · Kuzushi Labs ·

In this article

Our PRM backend already has an internal tool registry and domain-agent catalogue. A protocol can make that capability available to another agent runtime, but it cannot repair a mismatched adapter or decide who may book an appointment.

I would introduce protocols only at a real integration boundary. Inside one service, a typed function call is often simpler. Across independently operated clients or agents, a standard capability and message format becomes useful. This chapter is a proposed extension of the inspected project; it does not claim that the PRM already exposes MCP or A2A servers.

Distinguish tools from delegated work

MCP provides a tool interface suitable for an operation such as preparing a booking proposal. A2A describes communication between agents, including tasks and their lifecycle. An application framework implements execution around those interfaces; it is not interchangeable with either protocol.

The examples here pin the MCP tool specification dated 2025-11-25 and A2A 1.0.0. I would negotiate and test versions for a particular deployment rather than assume all SDKs support the same features.

External agent clients reach scoped protocol adapters; domain services retain validation and write authority.

Publish the smallest useful capability

For an MCP client, I would begin with patient lookup, availability search and proposal preparation. A tool description should explain what it can return and what it cannot commit:

{
  "name": "prm_prepare_booking",
  "description": "Prepare a reviewable booking proposal for a verified patient and server-issued slot. Does not book.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "patient_id": {"type": "string", "maxLength": 64},
      "slot_id": {"type": "string", "maxLength": 64}
    },
    "required": ["patient_id", "slot_id"],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": false,
    "idempotentHint": false,
    "openWorldHint": false
  }
}

Although this tool does not book, it creates a proposal record, so I would not label it read-only. Repeated calls may create distinct proposals, so the example does not promise idempotency. These annotations are hints for clients, not permission enforcement.

The response should include a proposal ID, revision, expiry, review fields and the next required action. It should not put a bearer token or hidden confirmation capability into model-readable text. If confirmation is exposed through a tool, that tool must require an independently recorded authorized approval; the model cannot approve its own proposal by calling a second function.

Bind identity at the adapter

The protocol server derives tenant and user context from its validated connection. It validates the tool arguments, checks the operation permission and calls the same domain service used by the dashboard. That makes the protocol another entry point into one policy boundary.

async def prepare_booking_tool(arguments, authenticated_context, booking_port):
    actor = authenticated_context.actor
    request = validate_prepare_booking(arguments)
    require(actor, "appointments.write")
    return await booking_port.prepare(actor, request)

This is interface pseudocode: validate_prepare_booking and the port belong to the implementation. The important constraint is that actor never comes from the tool arguments. I would also restrict upstream connection selection so a caller cannot use this tool as an arbitrary HTTP proxy.

For HTTP-based MCP authorization, the pinned authorization specification describes its OAuth-based mechanisms. Application resource permissions remain separate. I would keep token audiences, scopes, secret storage and connection revocation under the deployment's identity system rather than embed them in prompts.

Delegate a task only when ownership can move

A2A becomes interesting when a referral coordination agent operated by another service owns a longer task. For example, the PRM may request an appointment proposal from a scheduling agent and wait for an artifact containing candidate slots.

I would define an application contract around the protocol task:

{
  "local_workflow_id": "wf-001",
  "remote_task_id": "remote-task-001",
  "purpose": "prepare_referral_appointment",
  "allowed_outputs": ["slot_candidates", "needs_information", "unavailable"],
  "deadline": "2026-10-01T09:10:00Z",
  "write_authority": "none"
}

This is a local tracking record, not a complete A2A wire message. I would implement wire serialization with a version-compatible SDK and test it against the partner. A remote task reporting completion does not mean a local appointment exists; the artifact must be validated and translated into the local workflow.

Cancellation also needs precise semantics. Requesting cancellation of a remote task is not proof that an external operation was undone. Keep the last observed state and reconcile any side effects already accepted by the remote service.

Keep protocol errors separate from business outcomes

An invalid JSON-RPC request, an expired access token, a slot conflict and an unavailable practitioner are different failures. The first two belong to transport or authorization handling. The latter two are valid business results the agent may explain or use to prepare alternatives.

I would test discovery under restricted scopes, unknown tools, extra fields, revoked credentials, tenant-crossing references, oversized results, request cancellation and a partner timeout. Contract tests should also confirm that an older client cannot accidentally bypass a newly required approval field.

For this project, the order is straightforward: repair the internal adapter contracts, prove one end-to-end workflow, then expose a small external tool surface. A protocol makes a working capability easier to connect. The capability still needs a dependable result, a clear owner and a recovery path.

The implementation kit includes these reference contracts. It contains no running MCP or A2A server; those integrations require the chosen SDK, identity provider and partner contract tests.