[{"content":" At my day job, we are building something that sounds straightforward on paper: taking internal services and making them available to AI agents through MCP. Hundreds of them. Eventually thousands.\nIt sounds like plumbing work. Connect service A to agent B. Repeat.\nExcept the moment you start doing this at scale, a quiet question starts getting louder.\nWhich of these services is actually safe to hand an agent?\nSome services are read-only lookups. Some trigger real workflows. Some send external emails. Some modify customer data. Some reach into production systems. Most of them have documentation written for humans who already have the context — not for an AI agent operating autonomously at 3am.\nAnd here is the uncomfortable part: when an agent calls a tool, there is no moment of pause. No \u0026ldquo;are you sure?\u0026rdquo; No policy check. No audit trail. The action just happens.\nThat bothered me enough that I couldn\u0026rsquo;t stop thinking about it.\nThe Gap Nobody Is Filling We have spent decades building authorization systems for humans. OAuth, RBAC, IAM policies — all of it assumes a human is eventually in the loop, making a deliberate choice.\nAgents do not work that way.\nAn agent will call 40 tools in 3 seconds while you are still reading its first response. By the time you see the output, things have already happened. Files written. Emails sent. Records updated.\nWhat we need is not smarter agents. We need a control plane that sits between an agent\u0026rsquo;s intention and the execution of that intention. Something that asks — before anything runs — should this action happen, based on what we know right now?\nIf you have worked with AWS, GCP, or Azure, you already know what this looks like for humans. IAM. Roles, policies, least privilege, audit trails. It is one of the most important primitives in cloud infrastructure.\nNobody has built the equivalent for agents.\nThat is the idea behind AgentIAM.\nWhat It Actually Does AgentIAM is a small, framework-agnostic library that intercepts tool calls and evaluates them against a policy before anything executes.\nimport { definePolicy, createAgentIAM } from \u0026#34;@agentiam/core\u0026#34;; const iam = createAgentIAM({ policy: definePolicy({ rules: [ { id: \u0026#34;safe\u0026#34;, when: { action: \u0026#34;read_logs\u0026#34; }, decision: \u0026#34;allow\u0026#34; }, { id: \u0026#34;transfer\u0026#34;, when: { action: \u0026#34;transfer_money\u0026#34; }, decision: \u0026#34;approval_required\u0026#34; }, { id: \u0026#34;nuke\u0026#34;, when: { action: \u0026#34;delete_database\u0026#34;, context: { env: \u0026#34;prod\u0026#34; } }, decision: \u0026#34;deny\u0026#34; } ] }) }); const result = await iam.guard( { actor: { type: \u0026#34;agent\u0026#34;, id: \u0026#34;bot1\u0026#34; }, action: { name: \u0026#34;transfer_money\u0026#34;, input: { amount: 5000 } } }, async () =\u0026gt; myBankAPI.transfer(5000) ); console.log(result.executed); // false — paused for approval console.log(result.checkpoint.id); // \u0026#34;chk_abc123...\u0026#34; — resumable when approved The gate evaluates every tool call and returns one of four decisions:\nallow — execute immediately approval_required — pause, create a checkpoint, wait for a human clarification_required — the agent needs to provide more context first deny — hard block, never executes No execution happens until the policy says so. The agent proposes. The policy decides.\nWhy MCP Makes This Urgent MCP is quickly becoming the standard wiring layer between AI agents and external services. That is genuinely a good thing — interoperability matters, and a common protocol means agents can compose tools from many providers.\nBut it also means agents are about to have access to far more tools, from far more services, with far less oversight than before.\nEvery new MCP server is a new surface area. Every tool call is an action with real-world consequences. And right now, nothing governs which of those actions an agent is actually authorized to take.\nAgentIAM is my attempt to build that authorization layer in the open — generic enough to sit on top of any agentic framework, simple enough to adopt in an afternoon.\nLangGraph Integration If you use LangGraph, the integration is a single drop-in replacement for your ToolNode:\nimport { createGuardedToolNode } from \u0026#34;@agentiam/langgraph\u0026#34;; const guardedTools = createGuardedToolNode({ tools: myTools, iam, mapToolCall: (toolCall, state) =\u0026gt; ({ actor: { type: \u0026#34;agent\u0026#34;, id: state.agentId }, action: { name: toolCall.name, input: toolCall.args } }) }); When a tool call requires approval, AgentIAM automatically converts the checkpoint into a LangGraph interrupt(). The graph pauses. A human approves. The graph resumes. Exactly the human-in-the-loop pattern LangGraph was designed for — now policy-governed.\nThis Is Day One The core is working. The LangGraph adapter is live. Postgres persistence is available for production deployments. But there is a lot more to build — SQLite for lightweight local use, adapters for the OpenAI Agents SDK and Vercel AI SDK, better policy validation errors, and eventually a small approval UI.\nIf you are building with agents and this problem sounds familiar — I would genuinely love your input.\n⭐ Star the repo: github.com/golevishal/agentiam 🐛 Pick up a good first issue and contribute 💬 Open a discussion — tell me what your \u0026ldquo;thousand services\u0026rdquo; looks like The ecosystem is moving fast. Let\u0026rsquo;s make sure authorization keeps up.\nAgentIAM is MIT licensed and available now on npm as @agentiam/core.\n","permalink":"https://golevishal.github.io/posts/why-i-built-agentiam/","summary":"Why I built AgentIAM — and why this problem is only going to get bigger.","title":"MCP Gives AI Agents 1000 Tools. Who Decides Which Ones They Can Use?"},{"content":"AI agents are quickly moving beyond chat. They need to ask for approvals, show tables, collect structured inputs, expose tool traces, and update state while a task is still running. That creates a practical frontend problem: when an agent needs to present a real interface, how does it describe that UI without every application inventing its own one-off React components and JSON schema?\nThat is the space I wanted to explore with agui-cloudscape-renderer: a renderer that takes Agent-to-UI (A2UI) style events from an AG-UI stream and turns them into native AWS Cloudscape components. The goal is simple: let the agent describe what interface it needs, while the frontend owns how that interface is rendered, validated, and sent back to the agent.\nThe Problem: Backend Agents vs. Frontend Bloat Normally, if an agent needs a specific UI, developers build a custom React component, define a proprietary JSON schema, and hard-code the integration. This doesn\u0026rsquo;t scale. As agents become more autonomous, they need a way to \u0026ldquo;render\u0026rdquo; their own interfaces dynamically.\nThe A2UI approach solves this by defining a catalog of UI primitives that an agent can request: cards, text, buttons, inputs, tables, tabs, modals, and other building blocks. The frontend becomes a protocol renderer. It does not need to know every workflow in advance; it only needs to know how to map valid protocol components into real UI.\nThat distinction matters. The agent should not ship arbitrary HTML or unsafe frontend code. It should emit structured events. The renderer should interpret those events against a known component catalog, enforce validation, and emit structured user responses back to the agent.\nWhy Cloudscape? For this project, I wanted the output to feel enterprise-ready rather than like a prototype widget kit. Cloudscape is a good fit because it already provides production-grade patterns for forms, tables, status indicators, layout, accessibility, and dense operational interfaces. Those are exactly the surfaces agents tend to need when they move from chat demos into real workflows.\nThe renderer maps A2UI primitives to Cloudscape components so an agent can request a generic Table, Card, TextField, or Button, and the user still gets a consistent Cloudscape experience.\nArchitecture: The Bridge Pattern The library acts as the presentation layer between the agent event stream and the Cloudscape design system. At the center is a ProtocolBridge that routes incoming events by type.\nflowchart TD A[\"AG-UI Event Stream\\n(WebSocket / SSE / Mock)\"] --\u003e B[\"ProtocolBridge\\nRoutes events by type\"] B --\u003e C[\"A2UIRenderer\\nRecursive catalog tree\"] B --\u003e D[\"SurfaceRenderer\\nHITL forms + validation\"] B --\u003e E[\"A2UITableRenderer\\nAuto-columns + status icons\"] B --\u003e F[\"TraceSidebar\\nTool-call trace\"] C --\u003e G[\"Cloudscape Design System\"] D --\u003e G E --\u003e G style A fill:#232f3e,color:#ff9900,stroke:#ff9900 style B fill:#232f3e,color:#fff,stroke:#527fff style G fill:#232f3e,color:#ff9900,stroke:#ff9900 The bridge handles render events, human-in-the-loop action requests, state deltas, tool-call traces, and data model updates. Specialized renderers then take over:\nA2UIRenderer recursively renders catalog components. SurfaceRenderer manages HITL forms, validation, and response emission. A2UITableRenderer generates columns and maps status-like values to Cloudscape status indicators. TraceSidebar keeps tool activity visible while the main surface updates. From Agent Event to UI The core interaction starts with an A2UI_RENDER event. A backend can send a component tree like this:\n{ \u0026#34;type\u0026#34;: \u0026#34;A2UI_RENDER\u0026#34;, \u0026#34;payload\u0026#34;: { \u0026#34;surface\u0026#34;: \u0026#34;main\u0026#34;, \u0026#34;rootId\u0026#34;: \u0026#34;statusCard\u0026#34;, \u0026#34;components\u0026#34;: { \u0026#34;statusCard\u0026#34;: { \u0026#34;component\u0026#34;: \u0026#34;Card\u0026#34;, \u0026#34;child\u0026#34;: \u0026#34;col\u0026#34; }, \u0026#34;col\u0026#34;: { \u0026#34;component\u0026#34;: \u0026#34;Column\u0026#34;, \u0026#34;children\u0026#34;: [\u0026#34;heading\u0026#34;, \u0026#34;status\u0026#34;] }, \u0026#34;heading\u0026#34;: { \u0026#34;component\u0026#34;: \u0026#34;Text\u0026#34;, \u0026#34;variant\u0026#34;: \u0026#34;h2\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;Deployment Status\u0026#34; }, \u0026#34;status\u0026#34;: { \u0026#34;component\u0026#34;: \u0026#34;Text\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;$/deployment/message\u0026#34; } } } } The renderer resolves the rootId, walks the component dictionary, and renders a native Cloudscape card. The $/deployment/message value is a reactive binding path. When a later DATA_MODEL_UPDATE event arrives, the visible text can update from the data model without rebuilding the whole component tree.\nThat gives the agent a clean contract: describe the interface as structured data, send state changes as structured data, and let the renderer handle the UI mechanics.\nHuman-In-The-Loop Interaction Human approval is where this pattern becomes especially useful. Agents often need a person to confirm a deployment, approve a generated plan, fill a missing field, or choose between several options. The renderer handles those moments through ACTION_REQUIRED style events.\nThe SurfaceRenderer turns an action request into a form, applies field-level validation such as required fields, regex rules, and min/max lengths, then emits a USER_RESPONSE event when the user submits. The backend receives a structured response instead of scraping UI state or relying on custom callbacks per workflow.\nTables, Status, and Multi-Surface UI The renderer also supports patterns that show up constantly in operational tools:\ntables with generated columns, sorting, and pagination; status strings like Success or Failed rendered as Cloudscape status indicators; multiple target surfaces such as main, tools, and navigation; a protocol playground for editing JSON payloads and immediately seeing the rendered result. The current catalog includes layout components such as Row, Column, List, Card, Tabs, and Modal; primitives such as Text, Image, Icon, Button, and Divider; inputs such as TextField, CheckBox, ChoicePicker, and DateTimeInput; plus specialized components like Table and PropertyRedact.\nSecurity First: Shoulder-Surfing Protection Agent workflows often involve sensitive configuration values, tokens, account identifiers, or deployment parameters. I added a specialized A2UIPropertyRedact component for those cases. It renders sensitive values behind a click-to-reveal interaction so they are not visible on screen by default.\nThis is a small feature, but it reflects a larger principle: dynamic agent-generated UI still needs product-quality safety defaults. A protocol renderer should make the safe path easy.\nTry It Locally The project is built with Vite, React 19, TypeScript 5.9, and @cloudscape-design/components.\nnpm install npm run dev Once the dev server is running:\n/ opens the live agent demo with simulated real-time HITL interaction. /playground opens the JSON playground where you can edit A2UI payloads and see Cloudscape output immediately. The mock event hook documents how to swap in a real SSE backend. The ProtocolBridge itself is transport-agnostic: it accepts an event list and an emitEvent function, so the renderer does not care whether events came from a mock stream, WebSocket, or server-sent events.\nWhat Comes Next This is still an early renderer, but the shape is promising. The next areas I want to explore are broader catalog coverage, stronger layout constraints, richer streaming updates, and more real backend integrations. I also want the playground to become a useful debugging surface for anyone building against the protocol.\nConclusion Decoupling the agent\u0026rsquo;s logic from the frontend\u0026rsquo;s implementation gives both sides a cleaner job. The agent emits structured intent. The renderer turns that intent into accessible, responsive, enterprise-grade UI. Cloudscape makes the output feel native to serious operational tools, while A2UI-style events keep the integration flexible.\nCheck out the full source code and documentation on GitHub: 👉 golevishal/agui-cloudscape-renderer\nStay tuned for more updates as I continue to explore the intersection of AI protocols and design systems!\n","permalink":"https://golevishal.github.io/posts/agui-cloudscape-renderer/","summary":"A practical look at how agui-cloudscape-renderer turns Agent-to-UI events into dynamic, enterprise-grade Cloudscape interfaces.","title":"Rendering AI Agent Interfaces with A2UI, React, and AWS Cloudscape"},{"content":"Welcome! This is my first post on my new GitHub blog. Here is some code:\nconsole.log(\u0026#34;Hello, GitHub Pages!\u0026#34;); Stay tuned for more technical content!\n","permalink":"https://golevishal.github.io/posts/hello-world/","summary":"Welcome to my new blog powered by Hugo and PaperMod.","title":"Hello World: My New Tech Blog"}]