BLOG

TECHNICAL ARTICLES

Put AI to Work on Your Business Data

AI | MCP | RBAC

AI | MCP | RBAC

The problem

Questions that take one sentence to ask and half a day to answer

If you run a company, you have asked at least one of these in the last week:

  • “Has the truck for the XYZ order left yet, and when does it get there?”
  • “What quote did we give ABC last spring, and did they ever accept it?”
  • “Who is on shift at the ABC site today, and does everyone have a valid safety certificate?”
  • “How many hours do we actually spend on projects of this type, compared with what we quote?”
  • “Which clients have work we have done but have not invoiced yet?”
  • “Which customers have not heard from us in 90 days?”

None of these is a hard question. Every answer already exists in a system the company pays for. The hard part is that the truck is in the dispatch tool, the quote is in a PDF on a file share, the shift roster is in a spreadsheet, the hours are in the time-tracking app and the invoices are in the accounting package. The person asking is rarely the person who can log in to all five.

So the question becomes an e-mail, the e-mail becomes two exports, and someone stitches the exports together by hand. By the time the answer comes back it is Thursday, and the owner has stopped asking that kind of question, which is the real cost.

Large language models are good at exactly this kind of stitching. But in most companies the only people who can point an AI at live business data are developers. Everyone else gets a chat window that knows nothing about the company, or a copy-paste habit that quietly leaks data into a consumer chat app.

There is a second problem that is easy to forget until it bites. An AI assistant with access to company data is only as safe as its permissions. A sales person who asks “what is the payroll cost of the support team?” should get the same answer from the AI as from the HR system: you are not allowed to see that. Giving an AI a god-mode connection string and hoping the prompt keeps it honest is not a security model.

This post describes how we solved both problems for our own operations platform, NoetikAdmin, where the fourth and fifth questions above are asked daily. In short: expose the business through an MCP server, put that server behind the same role-based access control (RBAC) that already protects the web application, and let people reach it from whatever AI client they already use. The AI never gets more access than the person typing. NoetikAdmin is our worked example; the pattern applies to any company with scattered systems and an identity provider.

What MCP is

What an MCP server is

The Model Context Protocol (MCP) is an open standard, introduced by Anthropic in late 2024 and since adopted by OpenAI, Microsoft, Google and most AI tooling vendors, that defines how an AI application discovers and calls external capabilities. Think of it as a USB port for AI: one plug shape, so any client can connect to any server without a bespoke integration for every pair.

An MCP setup has three parts:

  • Host. The AI application the person is talking to: Claude Desktop, Claude Code, ChatGPT, Cursor, VS Code, or your own chat UI. The host runs the language model (or calls it over an API).
  • Client. A connector inside the host that speaks the protocol to one server. The host can hold many clients at once.
  • Server. A small program that exposes what a system can do. It can run locally on the laptop (over standard input/output) or remotely over HTTPS, which is what you want for a company-wide service.

A server offers three kinds of things:

PrimitiveWhat it isNoetikAdmin example
ToolsFunctions the model may call, each with a name, a description and a JSON schema for its argumentsfind_clients, get_charges_summary, get_time_entries
ResourcesRead-only data the host can attach as context, addressed by URIA project's specification document, a client's charge statement
PromptsReusable prompt templates the server suggests to the user“Prepare the monthly invoicing review for client X”

The key property is that the model never touches the database. It sees a menu of tools with human-readable descriptions, decides which one answers the question, fills in the arguments, and receives structured JSON back. Everything the model knows about your business comes through that door, which is exactly what makes the door a good place to enforce permissions.

Architecture

The architecture: an MCP layer in front of RBAC-aware middleware

The trick is to not build anything new for authorisation. Most companies that have been around for a while already have a middleware or service layer that sits between their users and their scattered systems: the thing that the web application, the mobile app and the nightly reports all call. That layer already knows who the user is, what roles they hold, and which records each role may see. The MCP server simply becomes one more client of it.

Architecture: AI clients, MCP server, RBAC-aware middleware, legacy systems and the identity provider

Permissions are enforced once, below the MCP server, for every AI client

Read top to bottom: the person signs in to their AI client with the company identity provider, the client carries the resulting token on every MCP call, the MCP server forwards the call to the middleware, and the middleware applies the same role filters it applies to the web app before touching the legacy systems.

In practice the layers are:

  1. Legacy systems. Invoicing, CRM, ticketing, timesheets, a file share. They stay exactly as they are. Nobody has to migrate anything.
  2. RBAC-aware middleware. One codebase that wraps those systems with a unified domain model (client, project, service request, charge, time entry) and a single permission check. In NoetikAdmin this is the ASP.NET Core service layer the web UI already uses. A manager sees every client; a project member sees only the projects they are assigned to; a contractor sees only their own time entries. Those rules live here, once.
  3. MCP server. A thin adapter. Each tool is a few lines: validate the bearer token, build a request on behalf of that user, call the middleware, return the result as JSON. The server has no connection string, no service account, and no way to answer a question the user could not answer themselves through the web app.
  4. AI clients. Whatever the person already uses. The model is told what tools exist and what they do, and it composes them to answer questions.

Identity and roles

Where the roles come from: OpenID Connect, OAuth 2.0 and your existing directory

The MCP server does not invent a user database. It trusts the identity provider the company already runs, through two standards that every AI client now supports:

  • OAuth 2.0 answers “is this client allowed to call this server on behalf of this person, and for what scope?”. The MCP specification requires remote servers to accept an OAuth 2.0 bearer token, and the major clients (Claude, ChatGPT, VS Code, Cursor) implement the authorisation-code flow with PKCE out of the box. When a person adds the NoetikAdmin connector to Claude, a browser window opens, they sign in with their work account, and the client receives a token it attaches to every tool call.
  • OpenID Connect (OIDC) sits on top and answers “who is this person?”. The ID token and the userinfo endpoint carry the user's identifier, e-mail, and, crucially, their group or role claims.

Which identity provider sits behind those standards is a deployment choice, not an architecture choice:

Identity providerTypical fitHow roles reach the middleware
Microsoft Entra ID (Microsoft 365)Companies already on Microsoft 365; roles follow the existing security groupsgroups or app-role claims in the access token, mapped to application roles
OpenIddict.NET shops that want to own the authorisation server inside the application itselfThe application issues the token and already knows its own roles
Keycloak, Auth0, Okta, Google WorkspaceMixed estates, or companies that want an identity product separate from the ERPRole or group claims, or a lookup by subject id against the application's user table

NoetikAdmin uses OpenIddict inside the application itself, because the application was already the system of record for who may do what. For a customer on Microsoft 365 we would instead federate: Entra ID authenticates, and the middleware maps Entra groups to its internal roles. The AI layer does not notice the difference.

The important part is what happens after the token arrives. The middleware does not trust a role claim blindly. It resolves the token to a user, loads that user's effective roles and assignments (which projects, which clients, which teams), and builds every query with those constraints baked in. If a manager removes someone from a project at 10:00, the AI stops seeing that project's data at 10:00, with no redeploy and no prompt change.

Three ways to use it

Three ways to consume it, one permission model

Once the server exists, the question becomes where people talk to it. We ended up supporting all three of the following, because different roles in the company want different things.

1. Off-the-shelf AI clients: Claude and ChatGPT

The fastest route. Claude (web, desktop and Claude Code) and ChatGPT both let an organisation register a remote MCP server as a connector. The person adds it once, signs in through the OAuth flow described above, and from then on can ask “which of my projects have unbilled time this month?” in the same chat they use for everything else.

For developers this is the natural home. A colleague in Claude Code can ask for a client's open service requests while fixing a bug for that client, without leaving the terminal. Because the token is theirs, they see what they would see in the web app and nothing more.

What you give up: control over the model, the system prompt, retention settings and where the conversation is processed. More on that in the data residency section.

2. A company chat built on the Anthropic or OpenAI API

For non-technical staff we built a chat page inside NoetikAdmin itself. It is a thin UI that calls the Anthropic Messages API (with the OpenAI Responses API as an alternative backend), passes the MCP server's tools as tool definitions, and runs the tool-call loop. The person is already signed in to the web app, so there is no second login: the chat uses their existing session to obtain a token for the MCP server.

This route costs more to build, but it gives you what the public clients cannot: a system prompt that speaks the company's vocabulary, control over which model answers which kind of question and what it costs, charts and tables instead of prose, and a full record of every question and every tool call kept in your own database.

3. Agents the company creates for itself

The third route has no chat window at all. An agent, in this architecture, is nothing more exotic than a saved instruction, a trigger, an identity and a list of allowed tools. A manager writes it in plain language from a form in the web app, the way they would brief a new assistant:

Every Monday at 08:00, look at the charge requests that have been open for more than 30 days. Group them by client and e-mail me the list. If a client is over 2,000 euro, prepare a draft invoice for me to approve.

The server stores that text, schedules it as a background job, and when the trigger fires it runs the same model loop the chat uses: the instruction goes in as the task, the MCP tools go in as the menu, and the model reads, reasons and reports. The trigger can be a schedule, or an event in the business: a ticket breaching its SLA, a tender matching a profile, a subscription coming up for renewal.

What keeps a self-created agent inside the fence is the same set of rules as everything else in this post, plus a few of its own:

  • An agent runs as somebody. Either as the person who created it, so it can never see more than they can, or as a dedicated service user with a narrower role. Disable the person, and their agents stop.
  • An agent proposes, it never commits. When the agent above wants to prepare a draft invoice, it calls the same propose_* tool a chat would, and the result is a pending action waiting for a human. The agent cannot approve its own proposals, and it is not told the approval code.
  • Every run has a budget and a log. A ceiling in euro and in tool calls per run, a timeout, and a readable record of what it read, what it concluded and what it proposed.

The reason this matters for an owner is that agents are where the time actually comes back. A question answered in chat saves a person ten minutes. An agent that checks the same thing every morning and only speaks when there is something to say removes the question from someone's head entirely. And because it is built on the MCP server, creating a new one is a form, not a project: no developer, no deployment, no new permissions.

This is the part of the NoetikAdmin layer we are building now, for a customer that asked exactly this question: “can we create agents ourselves on top of it?”. The first one is the overdue-charges report above.

RBAC on every path

The three routes differ in UI, cost and residency, but they all end at the same door. Whether the token was minted for Claude, for ChatGPT, for the in-house chat or for a nightly job, the middleware sees a user with roles and applies the same filters. There is no “AI mode” in the permission code. That is the property worth protecting as the system grows: add a fourth client tomorrow and you change nothing in authorisation.

Guardrails

Guardrails for the tools that can do damage

Reading is the easy case. The moment a tool can change something (approve a charge, e-mail a client, close a ticket, change a shift) or return genuinely sensitive data (salaries, contracts, health records), roles alone are not enough. The person is authorised, and the model can still call the right tool with the wrong arguments at the wrong moment.

The same middleware that enforces roles is the place to add a second layer, chosen per tool:

GuardrailWhat it doesUse it for
Read-only by defaultTools that write are a separate set the administrator enables per role, never part of the default connectorEvery deployment
Step-up authenticationThe tool call is accepted only if the person completed a second factor (authenticator app, passkey) within the last few minutes; otherwise the client is told to re-authenticatePayroll, contracts, anything regulated
Deferred execution on approvalThe model prepares the action and the middleware stores it as a draft; a person approves it in the web app, and only then does it runInvoices, e-mails to clients, purchase orders
Preview before commitThe tool returns exactly what would change (rows, amounts, recipients) and a second call with a one-time token performs itBulk updates, anything irreversible
Masking at the sourceSensitive fields are redacted inside the middleware before the result reaches the model, unless the tool and the role explicitly allow themTax numbers, bank accounts, personal data
Rate limits and spending capsCalls per minute, rows per answer and money per day, per user and per toolEvery deployment
Audit trailWho asked what, which tool ran with which arguments, what came back, which model saw itEvery deployment, and the first thing an auditor asks for

The pattern that makes all of these cheap is that the model never executes anything; it proposes. In NoetikAdmin every tool that writes is named propose_* and does exactly that: it validates the request, builds a preview and stores a pending action that expires in ten minutes. The person gets a link and a two-digit number. On the approval page they see the preview and three numbers, and must press the one the assistant showed them, so a prompt-injected or confused model cannot approve on their behalf. For high-risk actions such as creating a draft invoice they also type a fresh code from their authenticator app. Only then does the action run, server-side, as that user, and the assistant reads the outcome back with a separate tool. Issuing the invoice to the tax authority and e-mailing clients stay in the web app on purpose.

Working example

A working example: the NoetikAdmin AI layer

NoetikAdmin is the internal platform we run Noetik on: clients, projects, service requests, support tickets, time tracking, charge requests and invoicing, with about thirty MCP tools on top. The screen below is masked, but the behaviour is real.

NoetikAdmin AI chat: an account manager asks for a chart of open charge requests per client; the assistant calls one MCP tool and renders the answer

One question, one tool call, an answer limited to what this user may see

An account manager typed, in Greek, “show me a chart of the open charge requests per client”. What happened next:

  1. The in-house chat sent the question to the model together with the tool list the server advertises for this user.
  2. The model picked get_charges_summary and called it once. The green chip under the answer shows the tool name and its latency, so the person can see where the numbers came from.
  3. The middleware ran the summary query filtered to the clients this manager is allowed to see, and returned aggregated rows.
  4. The model rendered a bar chart from those rows, then wrote three sentences: the total, the three largest balances, and which of them are already invoiced versus awaiting invoicing.

The details around the answer are the parts an owner tends to care about:

  • Cost is visible per message and per conversation. The strip above the chat shows input and output tokens, cache hits, and the cost in euro. This answer cost about three cents.
  • A model picker with relative prices. The person chooses between a small, a medium and a large model, labelled ×1, ×2 and ×5. Quick lookups stay cheap; monthly analyses can use the large one.
  • A daily spending cap per user, shown next to the picker and enforced on the server.
  • No new permissions were created. The manager sees the same 60 clients they see in the clients list. A colleague with a narrower role would see a shorter chart from the same question.

Data residency

Data residency: what actually leaves the building

RBAC decides who sees data. Data residency decides where that data is processed once the model sees it, and the two are easy to confuse. Every tool result the MCP server returns is sent to a language model. If that model runs in a US data centre, your client list just crossed the Atlantic, with the permission of a perfectly authorised user.

The questions to ask any provider, for any of the three consumption routes:

QuestionWhy it matters
In which region is the prompt processed?GDPR transfer rules; some customers contractually require EU processing
How long are prompts and results retained?A tool result with client names sitting in logs for 30 days is a data store you did not plan for
Is the data used to train models?Consumer tiers of chat products often default to yes; business and API tiers to no
Is there a signed Data Processing Agreement and are sub-processors listed?Required to use the provider lawfully as a processor at all
Can retention be set to zero for the API?The strongest control for the in-house chat route

How the three routes compare, as of writing (check the provider's current terms before relying on this):

  • Public AI clients (Claude, ChatGPT). Business and enterprise plans of both do not train on your data and offer data-processing agreements; some offer EU data residency as a plan option. Consumer and individual plans are a different matter, and are the plan most employees already have on their phone. If you allow this route, make it an organisation-managed workspace, not personal accounts.
  • Direct API (Anthropic, OpenAI). Both offer business terms with no training on API traffic, retention controls, and zero-data-retention arrangements for qualifying customers. Default processing regions are US unless you select otherwise, so ask explicitly.
  • The same models through a cloud region you already trust. Claude is available through Amazon Bedrock, Google Cloud Vertex AI and Microsoft Foundry; OpenAI models through Azure OpenAI. Each lets you pin processing to an EU region such as Frankfurt, Paris or Stockholm under the cloud provider's existing DPA. For a company that already keeps its ERP in an EU region of one of these clouds, this is usually the path of least resistance.
  • Self-hosted open-weight models. For the most sensitive flows (payroll, legal) a model running on your own hardware or in your own VPC removes the question entirely, at the cost of model quality and operations effort. The MCP server does not care which model is on the other end.

Two mitigations apply regardless of the route and are cheap:

  1. Minimise what the tools return. get_charges_summary returns totals per client, not every charge line. Identifiers that are only useful to the database (internal IDs, tax numbers) are left out of tool results unless the question needs them.
  2. Log locally. The in-house chat stores the conversation, the tool calls and their arguments in NoetikAdmin's own database, in our region. The provider's logs can then be turned off without losing auditability.

For the document side of the same question, see our guide to private AI knowledge systems (RAG).

Takeaways

What we would tell another owner

The AI layer took weeks, not months, because we did not build an AI system. We built a thin protocol adapter over a permission model that already existed. If you are weighing something similar:

  • Start from your authorisation layer, not from the model. If your systems do not share a single place that knows who may see what, build that first. It pays off for the web app, the reports and the AI alike.
  • Use the standards. MCP for the tools, OAuth 2.0 and OpenID Connect for identity. Every serious AI client supports them, so you are not betting on one vendor.
  • Give the model fewer, better tools. Thirty well-described tools that return aggregated, pre-filtered data beat one “run SQL” tool every time, for both accuracy and safety.
  • Decide residency before the first demo. It is much harder to move a chat people already love than to pick the right region on day one.
  • Show the cost. People use AI responsibly when they can see the euro amount next to the answer.

The result is that a question which used to mean two exports and a spreadsheet now takes one sentence, from anyone in the company, and returns exactly what that person was allowed to know in the first place.

If you run a company on a handful of systems that do not talk to each other and want to see how this would look on your data, get in touch, or read more about our AI solutions and intelligent automation.

Let's talk!

We are at your disposal to discuss any aspect of your project, clarify your goals and needs, and work together on the project's implementation and growth!

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.