cd /news/artificial-intelligence/turning-a-system-of-record-into-an-a… · home topics artificial-intelligence article
[ARTICLE · art-63250] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Turning a System of Record into an AI Agent: Building MCP Tools on Azure

A developer built an AI agent that provides read-only access to an enterprise system of record using the Model Context Protocol (MCP) on Azure. The architecture uses Azure Logic Apps, API Management, and Agent Foundry to expose discrete tools that an AI model can call in response to natural language queries. Key design choices include a single backend endpoint that routes to multiple logical tools and generating tool schemas programmatically to prevent drift.

read5 min views1 publishedJul 17, 2026

A practical, end-to-end walkthrough of taking a read-only slice of an enterprise source system and exposing it to an AI agent as a set of Model Context Protocol (MCP) tools — using Azure Logic Apps, API Management, and Agent Foundry. All identifiers below are placeholders; swap in your own.

We wanted a simple outcome: a user asks a business question in plain language and gets a straight answer — no dashboards, no field names, no training on the underlying system. That means an AI agent with safe, read-only access to a backend system of record, exposed as discrete tools the model can call.

The constraints shaped every decision:

Five layers, one direction of flow:

Agent (Agent Foundry)
      │  MCP (JSON-RPC over HTTP)
      ▼
MCP server (API Management)
      │  REST operation per tool
      ▼
API gateway (API Management)
      │  single POST, routed by body
      ▼
Tool executor (Logic App)
      │  OAuth token + REST calls
      ▼
Source system (REST API)

The key design choice: one backend endpoint, many logical tools. The Logic App exposes a single HTTP trigger that accepts { "tool": "records.list", "parameters": { ... } }

and routes internally. API Management then fans that single endpoint out into many named operations, and its MCP feature turns those operations into agent tools. This keeps the backend trivial to maintain while the agent still sees a rich, typed tool catalog.

Start from the questions, not the schema. A useful toolset usually falls into a few families:

Two implementation notes that matter a lot:

Prefer aggregates over "pull a list and count." If the source system can compute a sum or a group-by server-side, a "total by category" answer is one summary row, not hundreds of records the model has to tally. Push the work down to the system wherever you can.

Prototype against the real API first. A quick collection of calls against the source system's REST endpoint (with OAuth client-credentials) lets you nail the field names, filters, and relationships before you touch orchestration. Field-name mismatches are the most common silent failure — verify against real responses.

The Logic App is a dispatcher. One HTTP request trigger, then:

first(split(tool, '.'))

).Switch

on category, with a nested Switch

on the full tool id inside each — each leaf is one read-only REST call.A few hard-won details:

@

.@

alias, remember that Logic Apps reads a bare @

as an expression. Double it (@@

) so it renders as a literal @

at runtime.{ "error": "unknown tool" }

object; each matched case overwrites it. Unknown tools then return cleanly instead of hanging.The agent needs a tool schema per operation. Generate an OpenAPI document with one operation per tool, where each operation's request body is only that tool's parameters (a get

op takes a record id; an aggregate takes nothing). Keep the path equal to the tool id so a gateway policy can recover it later.

Generate this programmatically from the same source of truth as the Logic App so the two can't drift — derive each operation's parameters from the inputs the Logic App actually reads.

Gotcha:API Management's inline "OpenAPI specification" editor parses the document asSwagger 2.0. Paste an OpenAPI 3.0 doc and you get"The Swagger version specified is unknown."Either import via theAdd API → OpenAPIsurface (which accepts 3.0), or hand it a Swagger 2.0 document. Same operations either way.

Import the OpenAPI to create the operations, then add one API-scoped inbound policy that:

validate-jwt

with your audience),{ tool, parameters }

body the Logic App expects,

<set-variable name="toolId" value="@(context.Request.OriginalUrl.Path.Split('/').Last())" />
<set-body><![CDATA[@{
    var incoming = context.Request.Body?.As<JObject>(preserveContent: true) ?? new JObject();
    if (incoming["tool"] != null) { return incoming.ToString(); }   // already wrapped
    var wrapped = new JObject();
    wrapped["tool"] = (string)context.Variables["toolId"];
    wrapped["parameters"] = incoming;
    return wrapped.ToString();
}]]></set-body>

Authenticating to the backend — drop the shared secret. A Logic App request trigger defaults to a SAS signature (sig

) baked into its URL. That's a shared secret you then have to store and rotate. The better pattern: give API Management a managed identity, add an OAuth authorization policy on the Logic App trigger (issuer + audience, optionally locking to APIM's appid

), disable SAS on the trigger, and let APIM authenticate with its own identity:

<authentication-managed-identity resource="api://<APP_ID>" />

No sig

, nothing to rotate, and you can restrict the trigger to exactly one identity.

API Management can publish selected operations as an MCP server. Point its "expose an API as an MCP server" feature at your API, select the operations you want as tools, and it hands you a server URL (an /mcp

endpoint). The operation operationId

s become the tool names the agent sees, so keep them clean (records_list

, analytics_by_category

).

Tier caveat:MCP server export isn't available on the Consumption tier of API Management. If the MCP Servers blade is missing, that's why.

In the agent, add a Model Context Protocol tool:

aud

your gateway's validate-jwt

requires. The audience is the single most common misconfiguration — get it right and the token check passes.If the gateway 401s and the token looks right, paste it into a JWT decoder and check iss

/aud

against the policy. Managed-identity tokens use the v1 issuer (https://sts.windows.net/<tenant>/

); configuring the policy with the v2 issuer produces a mismatch.

Tools enforce read-only at the API layer, but the behavior — tone, safety, honesty — lives in the system prompt. Ours does three jobs:

That last point is worth underlining: the agent should never hand-craft queries or field names. It picks a tool and fills named inputs. If a question needs a field the tools don't expose, that's a capability gap to report, not something to invent.

The demo worked on the first real question. The next few turns taught us the operational lessons:

The result is an agent a non-technical user can talk to in plain language, backed by a boringly maintainable pipeline, with the secret-handling and injection surface handled deliberately rather than by accident.

— Engineering notes, generalized. Replace all <placeholders> with your own tenant and resource values.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @azure 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/turning-a-system-of-…] indexed:0 read:5min 2026-07-17 ·