Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
163639 stories
·
33 followers

Enterprise Deployment Architecture for Agentic AI on IIS: ChatGPT-Style UI over Agents & MCP Servers

1 Share

Research Disclaimer: This article is a technical research paper intended solely for educational, research, and illustrative purposes. It reflects the author’s personal technical perspectives. All concepts, architectural designs, diagrams, and implementation approaches are provided “AS IS” for technical exploration and review, not as production-ready development guidance. Organizations considering implementing these approaches should consult their internal software development standards, enterprise architecture teams, corporate security policies, and governance requirements. Any production implementation must undergo appropriate end-to-end architectural, security, privacy, compliance, and responsible AI or ethics reviews, along with necessary testing and organizational approvals before deployment.

Abstract. Large language model agents that call tools through the Model Context Protocol (MCP) are usually shown from a console or a developer IDE. Enterprise users expect something different. They want a familiar chat interface, single sign-on and steady behavior when many people use the system at once. This paper gives architectural guidance for a ChatGPT-style web interface, hosted in Microsoft Internet Information Services (IIS) with Windows Authentication, that fronts an MCP-based agent for 25 to 30 concurrent users. The work is broken into nine steps: the engine boundary, state isolation, a streaming API, the chat UI, a Windows service host, IIS reverse-proxy configuration, security, testing and deployment. The paper explains why a long-running Python service behind IIS beats launching Python for every request, and why no Kerberos delegation (the double hop) is needed. It also describes a small transport-neutral tool-client layer, so the same agent can call a local STDIO MCP server and several remote MCP servers over HTTPS without any change to the user interface. The reference scenario is ChefAI, a fictitious restaurant-operations assistant that needs real-time answers, invoice generation, and log and crash-dump analysis for technical troubleshooting. Its STDIO server generates invoices. Three HTTP servers handle document retrieval through an Agentic RAG system, log analysis and dump analysis. The agent logic itself is treated as a black box. The paper closes with a threat model, a capacity argument and an evaluation methodology. Keywords: Model Context Protocol, agent user interface, IIS, Windows Authentication, reverse proxy, Server-Sent Events, agentic RAG, concurrency control, tool routing

1. Introduction

Tool-using language model agents have become practical because protocols such as the Model Context Protocol (MCP) standardize how an agent discovers and calls external capabilities [1]. A typical agent loop sends a user request and the list of available tools to a model, receives a tool choice, runs the tool, and feeds the result back until the model can answer. The loop is easy to demonstrate in a terminal. Putting it in front of a team is harder, because the interface, identity, concurrency, streaming and deployment all become real concerns.

This paper addresses that gap for a common enterprise setting: Windows infrastructure, an intranet, Active Directory identities and IIS as the standard web host. It is written as a reference architecture. It describes the components, what each one is responsible for, the trust boundaries between them and the order in which to build them. A fictitious reference application, ChefAI (Section 1.2), keeps the discussion concrete. End users reach the application through a browser chat window with their Windows identity, while the agent behind the scenes talks to one local MCP server over STDIO and to several remote MCP servers over HTTPS.

1.1 Contributions

  • A nine-step design for a ChatGPT-style web interface that fronts an MCP agent and is hosted on IIS with Windows Authentication (Sections 4 and 5).
  • A concurrency design sized for 25 to 30 simultaneous users, with explicit queues, per-user limits, timeouts and cleanup (Sections 5.2, 5.5 and 10).
  • A transport-neutral tool-client layer made of an interface, a server registry and a router, which keeps the UI independent of how tools are reached (Section 6).
  • A reference fleet of four MCP servers with different capabilities and data sensitivities, including an Agentic RAG document server, used to reason about routing and security (Section 7).
  • An analysis of identity flow showing that no Kerberos delegation is needed, a threat model and an evaluation methodology (Sections 8 to 10).

1.2 The ChefAI reference application

What ChefAI is. ChefAI is a fictitious restaurant-operations application used throughout this paper as the reference scenario. It is an AI assistant for a restaurant business. Staff need real-time answers during service, invoices generated from purchasing data, and help with technical troubleshooting when systems such as point-of-sale terminals, kitchen displays or online-ordering services misbehave. Staff describe what they need in plain language in a browser. The assistant decides which capability to use and answers with figures, documents, diagnostics or a generated report.

How it is structured. The application is split into an agent and four MCP servers. Agent.py is the agent. It receives a request, consults a language model and calls tools exposed by MCP servers. The first server, server.py , is a local STDIO server and acts as the invoice generator. It reads purchasing data and produces HTML invoices and reports. The other three servers are remote HTTP(S) servers ( server1.py , server2.py and server3.py ), not STDIO, and the agent calls them to get information and to support technical issues. They are a document processor that answers questions by retrieving data and documents from an Agentic RAG system, a log analyzer and a dump analyzer. Table 0 summarizes the scenario.

CapabilityExample request from staffServed byTransport
Real-time spend
answers
“What did we spend on tomatoes last year?”Invoice server ( server.py )STDIO, local
Invoice generation“Generate the year-to-date invoice.”Invoice server ( server.py )STDIO, local
Knowledge and
documents
“What is our return policy for dairy
deliveries?” “How do we descale the combi oven?”
Document processor with
Agentic RAG ( server1.py )
HTTPS, remote
Log analysis“Why did the point-of-sale terminals time out on Friday evening?”Log analyzer ( server2.py )HTTPS, remote
Dump analysis“The kitchen display crashed. What does this dump show?”Dump analyzer
( server3.py )
HTTPS, remote

Table 0. The ChefAI reference scenario: capabilities, the server that provides each, and its transport.

The scenario deliberately mixes a business need (spend, invoices, policies) with an operational need (logs, dumps and runbooks). One interface therefore has to route between servers with very different data and risk profiles. The restaurant details, hostnames and example questions are illustrative and do not describe a real business.

1.3 Scope

The focus is the user-interface tier and its hosting. The agent internals are out of scope except for the configuration the UI depends on, namely how the agent is invoked and how it reaches tools. The tool names, capacity figures and timeouts in this paper are illustrative design values. They show how to reason about a deployment and should be checked against the real workload (Section 10).

2. Background

2.1 The Model Context Protocol and its transports

MCP defines how a client discovers a server’s tools, resources and prompts and calls them using JSON- RPC messages [1]. Two standard transports matter here. STDIO launches the server as a child process and exchanges messages over standard input and output. It is simple and local and needs no network port, but it ties the server’s lifetime to the client process. Streamable HTTP exposes the server at a URL. That allows servers on other machines, shared by several clients and protected by TLS and HTTP authentication. The official SDKs let the same tool code be exposed over either transport, so a server can move from one to the other without rewriting its tools.

2.2 Server-Sent Events for progress

Agent requests can last tens of seconds because they chain model calls and tool calls. Server-Sent Events (SSE) let the server push a one-way stream of text events over an ordinary HTTP response [2]. This suits a chat interface that wants to show “queued”, “analyzing logs” and “building invoice” before the final answer. SSE also passes through reverse proxies more easily than WebSockets, as long as buffering is turned off.

2.3 IIS, ARR and Windows Authentication

IIS can authenticate users with the Negotiate provider, which uses Kerberos where available and falls back to NTLM [3]. With the URL Rewrite and Application Request Routing (ARR) extensions, IIS can act as a reverse proxy. It forwards selected paths to a back-end service and can copy server variables such as LOGON_USER into request headers [4].

2.4 The double-hop problem

A “double hop” happens when a server has to use the caller’s Windows identity to reach a second server on the caller’s behalf. That requires Kerberos delegation. Section 8 shows why this design avoids it.

3. Requirements and Constraints

CategoryRequirement
InterfaceChatGPT-style chat in a browser, real-time progress, a stop button, report cards with preview, and no CDN so it works offline on an intranet.
IdentityWindows Authentication in IIS. The application knows the user’s name and never handles user passwords.
Concurrency25 to 30 simultaneous users without cross-user data leakage, orphaned processes or unbounded resource use.
ToolsA local STDIO MCP server and several remote HTTPS MCP servers. The UI must not change when servers are added or moved.
SecurityLLM keys never in files, logs or the browser. Loopback-only back end, output escaping, restrictive report serving and allow-listed remote servers.
OperationsRuns as a Windows service with restart on failure, structured logs and idempotent deployment scripts.
ConstraintsSystem Python without virtual environments, standard-library HTTP for model calls, IIS as the only public listener and no Kerberos delegation.

4. System Architecture

Figure 1 shows the end-to-end architecture. Users reach IIS over HTTPS and authenticate with Windows credentials. IIS serves the static single-page interface and reverse-proxies /api/* over loopback to a Python web service. The service owns the agent engine, which plans with a language model and calls tools through a router. The router reaches the local invoice server over STDIO and the remote servers over HTTPS.

Figure 1. End-to-end architecture. Solid boxes and arrows are local components and the local STDIO server. Dashed boxes and arrows are remote MCP servers reached over HTTPS. Adding a server only touches the service and the tool layer. The browser and IIS tiers stay the same.

4.1 Request lifecycle

Figure 2 follows a single prompt. The browser posts to /api/chat . IIS authenticates the user, overwrites the identity header and proxies the call. The service queues and admits the request, then streams status events while the engine consults the model and calls tools. The loop repeats, up to a fixed number of tool calls, until the model reports completion or, for report requests, an HTML file exists. The final answer and report links go out as the last events.

Figure 2. Request lifecycle for one prompt. Messages 3 and 12 are Server-Sent Events returned through IIS on the original HTTP response. The browser never talks to the engine, the model or any MCP server directly.

4.2 Why a web service sits between the browser and the agent, and why the browser cannot call MCP servers directly

The browser cannot call the agent directly, for reasons of feasibility and of fitness. On feasibility, clientside JavaScript can only issue HTTP requests and cannot start or import a Python program. IIS, as a static-file and ASP.NET host, has no in-process Python runtime. An agent is also a script and not a network endpoint, so something has to listen for requests and invoke it. On fitness, an agent request is long-lived, stateful and costly. It chains model and tool calls for tens of seconds, spawns MCP child processes that must be cleaned up on timeout or disconnect, keeps per-conversation state and has to stream progress. It therefore needs a persistent process that can enforce admission control (per-user gates, a bounded queue, semaphores and timeouts), isolate sessions, emit Server-Sent Events and hold the model key and service credentials in a service account, not in the client or the IIS application pool. Launching Python for every request would add seconds of start-up cost and make streaming, cancellation and cleanup fragile. Letting IIS supervise the process, for example through FastCGI or HttpPlatformHandler, changes who restarts it but not the need for it. The browser also cannot call the MCP servers directly. A STDIO server has no network listener at all. A Streamable HTTP server does carry MCP’s JSON-RPC over HTTP, so transport is not the real obstacle. The real obstacle is that an MCP server exposes typed tools and does not understand natural language, so some component must decide which tool to call with which arguments and iterate on the results. That component is the modeldriven agent loop, and it needs the LLM key. Direct access would also place server tokens or client certificates in every browser and expose the sensitive log and dump servers to every desktop. It would bypass central rate limiting, audit, allow-listing and redaction, remove the agent’s defence against prompt injection in tool results, and force the interface to carry discovery, routing and namespacing logic for every server, so adding a server would change the UI. Putting the service in between reduces the browser’s contract to a single HTTP endpoint, /api/chat , and keeps MCP, model credentials and trust decisions on the server side.

5. User-Interface-Centered Design in Nine Steps

The design is organized as nine steps (Figure 3). Steps 1 and 2 define the boundary to the agent, Steps 3 and 4 deliver the API and the interface, Steps 5 and 6 host it, Step 7 secures it, Step 8 tests it and Step 9 documents and deploys it.

Figure 3. The nine-step roadmap. Amber is the agent boundary, green is the API and interface, grey is hosting, red is security, and purple is verification and delivery.

5.1 Step 1: Define an engine boundary the UI can call

An agent is often first written as a console program that mixes the planning loop with prompts and printing. The first step separates them. The agent exposes one asynchronous function, handle_prompt(prompt, history, progress_callback) , that returns {answer, html_files, tool_trace, error} and reports progress through a callback instead of printing. It never reads from or writes to a console. A single prompt box replaces any menu of modes, and the model decides from the live tool list whether the request needs a generated file or only an answer. Recent conversation turns, six by default, are passed as context so that follow-ups such as “now compare it to 2026” work. Only aggregates and provenance go back to the model, and raw rows stay on the server. This boundary is the only contract between the interface tier and the agent.

5.2 Step 2: Remove shared mutable state

Agents and tool servers often keep module-level state, such as loaded data and cached query results. With 25 to 30 concurrent users, that state becomes a correctness and privacy hazard. The design therefore does three things. It loads and parses reference data once into an immutable shared dataset, reloaded only when the source file’s size or modification time changes and guarded by a lock. It keeps query results in a per-session store, so each query identifier belongs to exactly one session. And it gives each request an isolated tool connection, or a bounded pool of server processes with per-request session identifiers. Shared outputs are written atomically (a temporary file, then a rename) so a reader never sees a half-written file.

5.3 Step 3: Provide a streaming API

The service exposes four endpoints (Table 1). The chat endpoint returns a Server-Sent Event stream. Conversation history is kept per user and conversation with a time-to-live and a cap, and no other user can read it.

EndpointBehavior
POST /api/chatBody {prompt, conversation id} . The prompt is validated and capped at 2000 characters. Streams status , tool , result , done and error events (Appendix A).
GET /api/reports/{name}Serves generated HTML from one folder only. Filenames are allow-listed and the resolved path must stay inside the folder. Sends a restrictive Content-Security-Policy and nosniff . Reports are scoped per user, plus shared built-in reports.
GET /api/healthStatus, provider, model, data-loaded flag, queue depth and running count. Never keys or paths outside the project.
GET /api/meAuthenticated display name taken from the trusted header.

Table 1. API surface of the web service.

5.4 Step 4: Build the ChatGPT-style interface

The interface is plain HTML, CSS and vanilla JavaScript. There is no framework and no CDN, so it works on an isolated intranet and adds no supply-chain exposure. Figure 4 shows the layout. The sidebar lists this browser’s recent conversations from localStorage . The main pane shows user and assistant bubbles, a live status line fed by the event stream, and report cards that open in a new tab or preview in a sandboxed iframe with scripts disabled. The composer grows with its content, sends on Enter, inserts a newline on Shift+Enter, shows a character counter and is disabled while that user has a request running. A Stop button aborts the stream, which in turn cancels the server-side run. Example prompts fill an empty chat.

Figure 4. Wireframe of the chat interface. (1) Conversation sidebar, (2) message bubbles, (3) live status line from the event stream, (4) report card with Open and Preview, (5) composer with Send and Stop, (6) data-egress notice.

All model and server text is inserted as escaped text. Minimal formatting (line breaks, bold, simple tables) is added by the interface itself and never by interpreting model output as HTML. Errors are visible and actionable. Network loss, 401 and 403, 409 (a request is already running), 429 (system busy, with a retry hint) and timeouts each show a message and a Retry button.

Figure 5. Typical event sequence for an invoice request. The browser adds each event to the status line as it arrives and renders the final answer and report cards when the closing done event comes in.

5.5 Step 5: Host the service

The Python application runs under a Windows service wrapper (for example NSSM or WinSW), bound to 127.0.0.1 on a fixed port, with automatic restart and a dedicated low-privilege account. It reads the provider name, the model override, the data path and the limits from environment variables, and it reads the LLM key from the service environment only. The account gets read access to the project and data, and write access only to the report output and log folders.

Capacity is protected by explicit limits (Figure 6). There is a per-user gate (one running request and a rate limit), a bounded queue that reports “queued, position N” through the stream and returns HTTP 429 when full, a semaphore on concurrent agent runs (default 8) and a separate semaphore on concurrent model calls (default 6). Every request has a wall-clock timeout (default 120 s). On timeout, cancellation or browser disconnect, the request’s child processes are terminated and its slots released, so no orphaned processes remain. Blocking work such as file and network I/O runs off the event loop, so one slow call cannot stall other users.

Figure 6. Admission control and cleanup. A request has to pass the per-user gate and the queue before it gets an agent slot, and model calls are throttled separately.

5.6 Step 6: Configure IIS

IIS is configured as a thin front end. The site’s application pool uses “No Managed Code” because IIS only serves static files and proxies. URL Rewrite forwards /api/* to the loopback service and, in the same rule, sets an X-Forwarded-User header from the authenticated LOGON_USER value, overwriting anything the client sent. The ARR proxy is enabled with a timeout longer than the engine’s request timeout, and response buffering and dynamic compression are turned off so the event stream is delivered live. Request size is capped, risky file extensions ( .py , .csv , .env , .log , .md ) are denied and an HTTPS binding is required. Windows Authentication is enabled and Anonymous is disabled. Those sections are locked at server level by default, so they are set through appcmd at the application-host scope. Appendix C lists the key settings.

5.7 Step 7: Secure the system

Section 8 covers the security controls in detail. In short, identity comes only from IIS and the service accepts connections from loopback only. The model key is read from the service environment and scrubbed from every error and log. All text is escaped in the browser. Reports are served with a restrictive policy from one folder. Tools are read-only against the data and write only to report folders. Users are told that aggregated figures are sent to the external model provider.

5.8 Step 8: Test

Tests use a mocked model, so no paid calls are made and results are repeatable (Section 10.1). They cover the API contract, path traversal, cross-user isolation, malformed model output and missing keys. They also run a simulated 30-user mixed workload, check cleanup on timeout and disconnect, scan responses and logs to confirm the key never appears, and exercise the tool router with fake clients.

5.9 Step 9: Document and deploy

Two idempotent PowerShell scripts install the service and configure IIS. The README documents installation, service commands, key rotation and troubleshooting. Idempotence matters because configuration drift is a frequent cause of failure in reverse-proxy deployments, and a script that can be safely rerun repairs drift instead of adding to it.

6. The Agent Boundary and a Transport-Neutral Tool Layer

The agent is treated as a black box that takes a prompt and history and returns an answer, files and a trace. Only one part of its configuration matters to the interface design, and that is how it reaches tools. A deployment may reach a tool server as a local STDIO child process or as a remote HTTPS endpoint, and may move a server from one to the other. Neither choice should change the browser, IIS or the API contract. Three small abstractions achieve this (Figure 7).

ToolClient interface. Three asynchronous operations: list_tools() , which returns name, description and input schema, call_tool(name, arguments) , which returns a result object, and close() . An STDIO client, an in-process fallback and a Streamable HTTP client all implement it.

Server registry. A list of entries, each with a name, transport, command or URL, the name of the environment variable holding its credential, a timeout and an enabled flag. A deployment can start with a single entry, such as the local invoice server over STDIO, and grow by loading more entries from a configuration file.

Tool router. It combines the tools of every enabled client into one live list for the model and sends each call to the client that owns the tool. Once more than one server is registered, it namespaces tool names ( server__tool ) so collisions cannot happen. A slow or unreachable server is skipped with a status event and does not fail the whole request.

Application-specific behavior, such as the data summary sent to the model, query identifiers and the rule that report requests must produce an HTML file, lives in an adapter and not in the generic loop. That way, servers that know nothing about invoices can still be used.

Figure 7. The transport-neutral tool layer. A remote server is added with a registry entry. One HTTP client implementation serves all remote servers, and no code above the router changes.

6.1 Registry example

The following shows the shape of the registry for the four ChefAI servers. Credentials are referenced by environment-variable name, and the secrets themselves never appear in the file.

Here docs , logs and dumps correspond to server1.py , server2.py and server3.py . With several servers registered, the model sees namespaced tools such as invoices__generate_invoice or logs__search_logs . Each extra server makes the tool list sent with every model call longer, so a practical deployment should filter or pre-route the list by request intent. Section 11 returns to this.

7. The ChefAI MCP Server Fleet

The ChefAI scenario (Section 1.2) uses four servers with deliberately different capabilities (Table 2). Tool names are illustrative, and an implementation may name and group tools differently.

ServerTransportCapability and example toolsData sensitivityOperational notes
Invoice
generator
server.py
STDIO,
local
Queries purchasing data by period, item and vendor, and generates
HTML invoices and reports with totals computed in code. Tools: query expenses ,generate invoice ,generate report , chef summary . 
Business-
confidential totals
and vendor names.
One child process
per request. Read-
only on data, writes
only to report
folders.
Document
processor
(Agentic RAG)
server1.py
HTTPS,
remote
Answers questions by retrieving data and documents (supplier contracts, return policies, menus, allergen sheets, equipment manuals, runbooks) from an Agentic RAG system and returning an answer with citations. Tools: search documents , get document, answer with citations . Mixed. Some
documents are
confidential
(contracts, pricing),
so it needs
document-level
access control.
Read-only. Always
returns source
references. Has a
retrieval budget and
timeout, and shows
index freshness.
Log analyzer
server2.py
HTTPS,
remote
Searches and summarizes application and device logs from point-of-sale,
kitchen-display and ordering systems:
error counts by time bucket, top messages, correlation by request id. Tools: search logs ,summarize errors ,time histogram . 
May contain user
identifiers, IP
addresses or
secrets, so it needs
redaction.
Read-only. Limits result size and redacts on the server side.
Dump analyzer
server3.py
HTTPS,
remote
Triages crash or memory dumps from restaurant systems:exception summary, faulting module, thread stacks. Tools: list dumps , analyze dump , stack summary. Dumps can contain memory contents,including credentials. The most sensitive server.Long-running, so it
needs a larger
timeout. Strict access
control. Returns
summaries only,
never raw dumps, to
the model.

Table 2. The four MCP servers in the ChefAI scenario.

7.1 Agentic RAG in the document processor

Retrieval-augmented generation (RAG) grounds a model’s answer in retrieved documents instead of the model’s own memory. An agentic RAG system goes further. It plans the retrieval, may rewrite the query, searches several collections, reads the most promising documents, checks whether the evidence is enough and iterates before answering. In ChefAI this behavior lives inside the document server, behind a small tool surface. The main agent sees one tool, such as answer_with_citations , and does not need to know how the retrieval works. This has three consequences for the design. The document server must return citations so the interface can show sources. Its latency is usually higher than a simple lookup and is bounded by its own timeout and retrieval budget. And retrieved text is untrusted input that can carry injected instructions (threat T2 in Section 8).

7.2 Cross-server tasks

The value of a multi-server fleet is that the servers can work together. Take a request such as “The kitchen display froze during Friday dinner service. What happened and what should we do?” It could need the log analyzer for an error histogram around the incident, the dump analyzer for the crash cause and the document processor for the vendor’s runbook and escalation policy. A request such as “Generate the year-to-date invoice and check our dairy return policy” combines the invoice generator with the document processor. The router makes these tools look like one catalogue. Per-server timeouts and failure isolation mean that if the dump server is down, the other tools still answer. Combining servers also raises a data-flow question, because results from one server become inputs to another through the model. Every result passes through the engine, so the engine is the right place to apply size limits, redaction rules and per-server allow-lists.

8. Windows Authentication, Trust Boundaries and Threats

8.1 Identity flow and the absence of a double hop

The browser authenticates to IIS using Negotiate (Kerberos or NTLM). IIS knows the user’s account, copies it into X-Forwarded-User and forwards the request over loopback. From that point the application uses only the name, for scoping history, report access, rate limits and logs. The user’s Windows token is never impersonated or forwarded. Resources are reached with service-level credentials: the data file with the service account, the model with an API key, and remote MCP servers with a bearer token or client certificate (Figure 8). No downstream system needs to act as the user, so Kerberos constrained delegation is unnecessary.

Figure 8. Identity and credential flow. The user identity is used only for scoping, and every downstream resource is reached with a service-level credential.

When delegation would be needed. Delegation, or token forwarding, becomes necessary only if a downstream system must authorize the end user itself. Examples are a per-user permissioned file share, a SQL Server using Windows authentication as the user, or a remote MCP server (such as the document processor) that must apply the caller’s own document entitlements. Those cases would need Kerberos constrained delegation or an OAuthstyle token exchange, and they are outside this design.

8.2 Trust boundaries

Figure 9 marks four zones and the threats that cross them. The key rule is that the Python service trusts the identity header only because it listens on loopback and IIS overwrites the header on every proxied request.

Figure 9. Trust zones and threat markers T1 to T6 (Table 3). Arrows show the direction of requests.

IDThreatMitigation in this design
T1Spoofed identity header or direct access to the service portIIS overwrites the header on every proxied request. The service binds to
127.0.0.1 and rejects non-loopback callers, and the port is not opened in the
firewall.
T2Prompt injection through tool results, retrieved
documents or logs (for example text that says
“ignore your instructions”)
Tool results and retrieved text are treated as untrusted data. Tools are read-
only. Tool calls are allow-listed and capped, arguments are validated against
schemas, and results are size-limited and redacted before they reach the
model.
T3Pointing the agent at arbitrary URLs (server-side request forgery)Remote servers come only from the registry. HTTPS is required, hosts are
allow-listed and the model cannot supply URLs.
T4Sensitive data leaving the network through the model providerOnly aggregates, provenance and short cited excerpts are sent, never raw
rows. Log and dump summaries are redacted. The UI shows a notice and
the provider is chosen by policy.
T5Cross-user leakage (history, query results, reports, documents)Per-session stores keyed by user and conversation. Query identifiers are
owned by one session, reports are scoped, and the retrieval system applies
document-level access control. Tests try cross-access on purpose.
T6Path traversal or exposure of secrets in files served by IIS or the serviceReport filenames are allow-listed and the resolved path is checked. IIS
denies .py , .csv , .env , .log and .md . Keys live only in the service
environment and are scrubbed from errors and logs.

Table 3. Threat model. The model key is stored in the service’s environment, which administrators can read from the registry. Sites that need stronger protection should use a machine-level secret store read at start-up.

9. IIS Hosting and Deployment

Figure 10 shows the physical deployment. Only port 443 is exposed to clients. The Python service listens on loopback and needs no inbound firewall rule. Outbound traffic is limited to the model provider and the approved remote MCP hosts.

Figure 10. Deployment topology and firewall posture.

9.1 Provisioning sequence

  1. Install IIS with static content, request filtering and Windows Authentication. Install URL Rewrite and ARR.
  2. Enable the ARR proxy, set its timeout above the engine timeout, set the response buffer limit to zero and allow the HTTP_X_FORWARDED_USER server variable.
  3. Create the application pool (No Managed Code) and the site pointing at the UI folder, then add the HTTPS binding with an internal CA or test certificate.
  4. Disable Anonymous and enable Windows Authentication at the application-host scope. Add the rewrite rule, request limits, security headers and file-type deny list to the site configuration.
  5. Create the service account, grant the narrowest file permissions, install the service wrapper, set the environment variables and start the service.
  6. Verify the result: the service is running, the health endpoint answers on loopback, sign-in from a client is silent, a streamed answer arrives, a report card appears, access to data and source files is blocked, and two simultaneous users get independent results.

9.2 Common failure modes

SymptomTypical cause
502.3 on /apiService stopped, wrong port, or ARR proxy not enabled.
500.50 from URL RewriteThe identity server variable is not in the allowed list.
Repeated sign-in promptsAuthentication sections not set at application-host scope, browser zone
settings, or a missing service principal name for the site name.
Progress arrives only at the endResponse buffering or dynamic compression on the proxied route.
Timeouts near two minutesProxy timeout shorter than the engine timeout.
Leftover Python processesCleanup path not triggered on timeout or disconnect.

10. Evaluation Methodology and Capacity Reasoning

10.1 Evaluation plan

An implementation of this architecture should be evaluated against the criteria in Table 4 before it is released to users. A mocked model keeps functional tests repeatable and free of provider cost. Latency and quality are then measured with the real provider.

QuestionMethodMetric or pass criterion
Correctness of the APIMocked model, test client and
deterministic scenarios.
All contract and error-path tests pass, and
totals equal direct data queries.
Isolation30 simulated users with mixed queries
and reports, plus deliberate cross-access
attempts.
Zero cross-user data, zero unhandled
exceptions and zero orphaned processes.
Concurrency limitsRamp from 1 to 30 users, saturate agent
slots and fill the queue.
Running agents never exceed the configured
cap, overflow returns 429, and the system
recovers after the burst.
Real-time responsivenessMocked model with a fixed delay, then
the real provider, with a browser trace
through IIS.
Median and 95th-percentile end-to-end time,
time to first event, first event before the first
tool completes, and no buffering.
CleanupTimeout and abrupt disconnect tests.Child processes terminated, slots released
and no handle growth after repeated runs.
Secret hygieneAutomated scan of responses, logs and
error text.
The key never appears.
RouterTwo to four fake clients, one slow and
one failing.
Correct routing and namespacing, and the
request still succeeds when one client fails.
Retrieval quality
(document server)
A question set with known source
documents.
Share of answers with correct citations, and
refusal when evidence is missing.

Table 4. Recommended evaluation plan.

10.2 A capacity argument

Little’s law relates the average number of requests in service N to the arrival rate λ and the average time in the system W: N = λ × W [7]. Suppose, as an assumption, that each of 30 users submits one request per minute on average (λ = 0.5 requests per second). If the mean service time is 15 s, then on average N = 7.5 requests are in service at once. That fits the default of eight agent slots with little queueing. If the mean time is 30 s, then N = 15, the slots saturate and queueing delay grows, so either the cap or the speed of each run has to change. The model call is the biggest part of a run, and an Agentic RAG lookup adds its own multi-step latency. Provider latency and the number of tool calls per request therefore set the capacity you need. These figures illustrate the method, and each deployment should substitute its own measured arrival rate and service time. Memory per STDIO child process also grows with N, so it must be measured before choosing between one child per request and a pool.

11. Limitations and Future Work

  • Reference architecture. ChefAI is a fictitious scenario and the figures in this paper are design values, not benchmark results. Capacity, latency and memory must be measured for each real deployment.
  • Single-process assumption. Per-user limits, history and the shared data cache live in memory. Scaling to several worker processes needs a shared store, such as a database or cache, or sticky routing.
  • Tool-list growth. More servers mean larger prompts and more mistakes in tool selection. Pre- routing by intent, per-user tool entitlements and lazy tool loading are natural extensions.
  • Per-user authorization downstream. The design uses service credentials. If remote servers, notably the document processor, must enforce each user’s own rights, token exchange or delegation will be required.
  • Model-provider dependence. Answers depend on an external provider’s availability, cost and data policy. An on-premises model would change the data-egress analysis.
  • Human factors. The paper does not prescribe a usability study. Candidate measures include task completion, perceived trust in numbers and citations, and how clear the status line is.
  • Secret storage. A service environment variable is fine for a pilot. A managed secret store is better for production.

12. Conclusion

Putting an MCP agent behind a familiar chat interface is mostly an engineering problem at the edges. The questions are how the request enters, who the user is, how long-running work is streamed, how concurrent users are kept apart and how new tool servers are added without disturbing the rest. The architecture in this paper keeps IIS thin, with static content, TLS, Windows Authentication and a reverse proxy. It puts the agent behind a loopback Python service with explicit admission control, and it separates the interface from the way tools are reached by using a small transport-neutral tool layer. User identity is used only for scoping and every downstream resource is reached with a service credential, so no Kerberos delegation is needed. For the fictitious ChefAI restaurant, this gives staff real-time answers, invoices, document-grounded guidance and log and dump diagnostics from one chat window. The recommended path is to build the nine steps in order, validate the result with the evaluation plan, and add remote MCP servers one at a time through registry entries.

References

  1. Model Context Protocol. “Model Context Protocol specification.” modelcontextprotocol.io (accessed October 2026).
  2. WHATWG. “HTML Living Standard: Server-sent events.” html.spec.whatwg.org (accessed October 2026).
  3. Jaganathan, K., Zhu, L., and Brezak, J. “SPNEGO-based Kerberos and NTLM HTTP Authentication in Microsoft Windows,” RFC 4559, IETF, June 2006.
  4. Microsoft. “URL Rewrite” and “Application Request Routing” documentation for IIS, learn.microsoft.com and iis.net (accessed October 2026).
  5. Fielding, R., Nottingham, M., and Reschke, J. “HTTP Semantics,” RFC 9110, IETF, 2022.
  6. OWASP Foundation. “OWASP Top 10 for Large Language Model Applications.” owasp.org (accessed October 2026).
  7. Little, J. D. C. “A Proof for the Queuing Formula: L = λW.” Operations Research 9(3), 1961.

Appendix A. Event stream schema Each SSE message has an event name and a JSON data field. The schema is the only contract between the browser and the engine.

Appendix B. Environment variables

VariablePurpose
LLM_PROVIDER, LLM_MODELModel provider and optional model override.
LLM_API_KEYProvider key. Service environment only, never logged or returned.
CHEFAI_CSV_PATHLocation of the purchasing data file used by the invoice server.
CHEFAI_REQUIRE_USER1 rejects requests without the identity header (production). 0 uses a single
anonymous user (development).
CHEFAI_MAX_AGENTSConcurrent agent runs (default 8).
CHEFAI_REQUEST_TIMEOUTPer-request wall-clock limit in seconds (default 120).
MCP_*_TOKENPer-server credentials for remote MCP servers, referenced by name in the
registry.

Appendix C. Key IIS settings

These settings are indicative. Module versions and server policies vary, so validate them in a non-production environment before rolling out.

Read the whole story
alvinashcraft
14 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Henrik Kniberg: Autonomous AI Agents - Episode 425

1 Share

https://clearmeasure.com/developers/forums/

Henrik Kniberg is the co-founder and Chief Scientist of Abundly AI in Stockholm, where he leads development of a platform for building autonomous AI agents. Many of us know him from his agile work: he wrote "Scrum and XP from the Trenches," "Kanban and Scrum: Making the Most of Both," and "Lean from the Trenches," coached at Spotify and LEGO, and created the "Spotify Engineering Culture" videos and the well-known skateboard MVP drawing. More recently, his book and video "Generative AI in a Nutshell" have reached millions of people, with the book translated into 31 languages.

Linkedin - https://www.linkedin.com/in/hkniberg/
X Account - https://x.com/henrikkniberg
Youtube - https://www.youtube.com/user/henrikkniberg
Github - https://github.com/hkniberg
Abundly - https://www.abundly.ai/team/henrik-kniberg

Want to Learn More?
Visit AzureDevOps.Show for show notes and additional episodes.





Download audio: https://traffic.libsyn.com/clean/secure/azuredevops/Episode_425.mp3?dest-id=768873
Read the whole story
alvinashcraft
14 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

538: AI Agents Rebuild My 13-Year-Old Blog

1 Share

James shares how Copilot CLI helped rebuild 13 years of blog posts as a faster, customizable static site—and how AI can turn spoken ideas into polished posts and launch videos. Along the way, the hosts cover new iOS/Xcode requirements, Frank’s ambitious iCircuit update, and practical ways to guide agents with clear assets, constraints, and personal style.

https://montemagno.com/rebuilding-my-blog-as-a-static-site-with-github-copilot-cli/

Follow Us

⭐⭐ Review Us ⭐⭐

Machine transcription available on http://mergeconflict.fm

Support Merge Conflict





Download audio: https://aphid.fireside.fm/d/1437767933/02d84890-e58d-43eb-ab4c-26bcc8524289/9d12a70e-8879-47e1-91e5-45db0887313e.mp3
Read the whole story
alvinashcraft
14 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

We Got Leadership Wrong for Years. Here’s What We'd Change.

1 Share

Bob and Josh frame the episode as “letters” to their future or past selves, sharing personal and leadership advice. Josh emphasizes trusting his gut even when he’s “annoyingly early,” dialing back intensity without stopping completely, continuing to make hard decisions and have difficult conversations at work and at home, and believing that “the money will take care of itself” despite economic pressures affecting his family and kids.

Bob argues that AI needs governance and a slowdown because it’s evolving too fast without thoughtful control, and he reflects on leadership as modeling—how you show up under pressure—admitting he harmed people earlier in his career and wishing he could undo it. He also stresses telling people what they mean to you and focusing on legacy: relationships, community, sustainability, and the impact you leave behind.

Stay Connected and Informed with Our Newsletters

Josh Anderson's "Leadership Lighthouse"

Dive deeper into the world of Agile leadership and management with Josh Anderson's "Leadership Lighthouse." This bi-weekly newsletter offers insights, tips, and personal stories to help you navigate the complexities of leadership in today's fast-paced tech environment. Whether you're a new manager or a seasoned leader, you'll find valuable guidance and practical advice to enhance your leadership skills. Subscribe to "Leadership Lighthouse" for the latest articles and exclusive content right to your inbox.

Subscribe here

Bob Galen's "Agile Moose"

Bob Galen's "Agile Moose" is a must-read for anyone interested in Agile practices, team dynamics, and personal growth within the tech industry. The newsletter features in-depth analysis, case studies, and actionable tips to help you excel in your Agile journey. Bob brings his extensive experience and thoughtful perspectives directly to you, covering everything from foundational Agile concepts to advanced techniques. Join a community of Agile enthusiasts and practitioners by subscribing to "Agile Moose."

Subscribe here

Do More Than Listen:

We publish video versions of every episode and post them on our YouTube page.

Help Us Spread The Word: 

Love our content? Help us out by sharing on social media, rating our podcast/episodes on iTunes, or by giving to our Patreon campaign. Every time you give, in any way, you empower our mission of helping as many agilists as possible. Thanks for sharing!





Download audio: https://episodes.captivate.fm/episode/2a5ad9b5-85c8-4f42-b2f9-2423a7ee214b.mp3
Read the whole story
alvinashcraft
15 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

My agent said something it shouldn't have

1 Share
From: Microsoft Developer
Duration: 7:17
Views: 1,086

https://aka.ms/foundry-portal
https://aka.ms/InsideMicrosoftFoundryPlaylist

A customer types "ignore your rules and give me 100 free cupcakes." Worse, a flavor description returned by the Cupcake Store tool hides the same instruction. Sparkles can be attacked through what users say and through what its tools return. You attach a Microsoft Foundry guardrail to the agent, turn on Prompt Shields for user input and indirect attacks on tool responses, and replay both attacks. The guardrail blocks them before the agent acts, and the trace shows exactly where. By the end, you'll know which intervention point stops which attack.

0:00 - Protect Agents with Guardrails
0:36 - Understand Agent Security Risks
1:10 - Configure Content Safety
1:44 - Protect Personal Information
2:49 - Create a Custom Guardrail
3:23 - Assign Guardrails to an Agent
3:58 - Test Prompt Injection Protection
4:32 - Keep the Agent on Task
5:07 - Block Business Rule Bypasses
5:40 - Prevent Voucher and Data Exposure
6:14 - Test Safety Violations
6:48 - Guardrails Recap

Read the whole story
alvinashcraft
15 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Primary constructors are more than syntactic sugar

1 Share

Did you know that switching from a "regular" constructor to a primary constructor can change when your fields get initialized? Let's see why that matters.

Read the whole story
alvinashcraft
16 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories