<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Syed Zadi</title>
    <description>The latest articles on DEV Community by Syed Zadi (@syedzadi).</description>
    <link>https://dev.to/syedzadi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4194118%2Fe454bbbb-547b-4d11-9be5-0a9cfce835e3.png</url>
      <title>DEV Community: Syed Zadi</title>
      <link>https://dev.to/syedzadi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/syedzadi"/>
    <language>en</language>
    <item>
      <title>What Is GraphRAG? A Plain English Explainer</title>
      <dc:creator>Syed Zadi</dc:creator>
      <pubDate>Wed, 21 Oct 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/syedzadi/what-is-graphrag-a-plain-english-explainer-4e74</link>
      <guid>https://dev.to/syedzadi/what-is-graphrag-a-plain-english-explainer-4e74</guid>
      <description>&lt;p&gt;GraphRAG is retrieval-augmented generation where the retrieval layer queries a &lt;strong&gt;knowledge graph&lt;/strong&gt; not, or not only, a vector database.&lt;/p&gt;

&lt;p&gt;Instead of returning similar text chunks, it returns typed entities and the relationships between them. The LLM then answers from structured, citable facts rather than statistical guesses about which paragraph looked relevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG in one paragraph, then what GraphRAG adds
&lt;/h2&gt;

&lt;p&gt;Retrieval-augmented generation grounds an LLM answer in retrieved evidence. The standard recipe: chunk your documents, embed them with a model, store the embeddings in a vector database. At query time, embed the user's question, find the most similar chunks, pass them to the LLM as context.&lt;/p&gt;

&lt;p&gt;This works beautifully for "summarize this document" and "find me a policy that says X."&lt;/p&gt;

&lt;p&gt;It falls apart the moment the answer requires composing facts from multiple entities or systems.&lt;/p&gt;

&lt;p&gt;A knowledge graph stores your business as typed entities customers, contracts, products, incidents connected by typed relationships. When a user asks a question, the retriever can &lt;strong&gt;walk the graph&lt;/strong&gt; (customer → contract → clause → obligation) to compose the actual answer, then hand the LLM the resulting facts with pointers to the source systems they came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three concrete failures GraphRAG fixes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hallucination on multi-hop questions.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which of our Platinum plan customers raised P1 tickets about the feature we deprecated last quarter?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No single document contains that answer. Vector search returns chunks that &lt;em&gt;look&lt;/em&gt; related and the LLM fabricates the join. GraphRAG returns the exact list, with citations to the source system for each row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabricated citations in high-stakes domains.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Legal and clinical assistants built on pure vector RAG keep inventing cases and papers. When retrieval returns a typed entity with a real identifier, there is nothing to invent the citation is the node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answers that go stale silently.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vector chunks do not know that a policy was superseded. A graph can model supersession as an edge and exclude the retired version by traversal, rather than hoping the stale chunk ranks lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five layers of a GraphRAG system
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ontology&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defines the entity types and relationship types your domain actually has&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ingestion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extracts entities and relationships from source systems and documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graph store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Holds the typed nodes and edges; Neo4j is the common choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hybrid retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Combines graph traversal with vector search over node text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Evaluation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Measures whether retrieved context actually supports the answer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The ontology is the part teams underestimate. It is a modeling exercise about your business, not a database schema task, and getting it wrong is the most expensive mistake in the stack.&lt;/p&gt;

&lt;p&gt;The evaluation layer is the part teams skip. Without it you cannot tell a retrieval regression from a model regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use GraphRAG and when not to
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use it when:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Answers require composing facts across multiple entities or systems&lt;br&gt;
You need counting, aggregation, or absence ("which accounts have no owner?")&lt;br&gt;
Citations must point to systems of record, not paragraphs&lt;br&gt;
Permissions are relationship-shaped and cannot be expressed as one filter&lt;br&gt;
Content gets superseded and stale answers are harmful&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not use it when:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your corpus is a document pile and the questions are "summarize" or "find the policy that says X"&lt;br&gt;
Access control is effectively open, or expressible as a single filter&lt;br&gt;
Nothing in your source data gets reversed or superseded later&lt;/p&gt;

&lt;p&gt;If all three of those hold, plain vector search is sufficient and considerably cheaper to run. Internal enterprise search over operational data almost never satisfies all three at once which is why the question keeps coming up.&lt;/p&gt;

&lt;p&gt;For the full decision framework, see &lt;a href="https://www.agenticgiants.com/blog/graphrag-vs-vector-rag-enterprise" rel="noopener noreferrer"&gt;GraphRAG vs vector RAG&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;We build enterprise GraphRAG systems on Neo4j. If you are deciding whether your stack needs one, &lt;a href="https://www.agenticgiants.com/contact" rel="noopener noreferrer"&gt;talk to our team&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>graphrag</category>
      <category>neo4j</category>
    </item>
    <item>
      <title>How to Build an MCP Server in Next.js</title>
      <dc:creator>Syed Zadi</dc:creator>
      <pubDate>Tue, 20 Oct 2026 10:35:00 +0000</pubDate>
      <link>https://dev.to/syedzadi/how-to-build-an-mcp-server-in-nextjs-2ni4</link>
      <guid>https://dev.to/syedzadi/how-to-build-an-mcp-server-in-nextjs-2ni4</guid>
      <description>&lt;p&gt;To build an MCP server in Next.js, you expose a single API route that speaks the Model Context Protocol over Streamable HTTP. It accepts the client's JSON-RPC requests, dispatches each one to a registered tool, and streams results back.&lt;/p&gt;

&lt;p&gt;That is the whole shape. The interesting part is everything around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are actually building
&lt;/h2&gt;

&lt;p&gt;An MCP server is a governed adapter. It gives an AI client scoped, audited access to your tools and data instead of pasting raw API keys into a prompt and hoping.&lt;/p&gt;

&lt;p&gt;The route handler is the surface the AI client connects to. Behind it sit the tool implementations that actually touch your systems.&lt;/p&gt;

&lt;p&gt;If that framing is new, start with &lt;a href="https://www.agenticgiants.com/blog/what-is-an-mcp-server" rel="noopener noreferrer"&gt;what an MCP server is&lt;/a&gt; and come back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick the transport: HTTP, not stdio
&lt;/h2&gt;

&lt;p&gt;MCP defines two transports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;stdio&lt;/strong&gt; is for a local subprocess the client spawns the server as a child process and talks over standard input and output. Useful for desktop tooling, wrong for a web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streamable HTTP&lt;/strong&gt; is for a remote server reached over the network. That is what a Next.js route is.&lt;/p&gt;

&lt;p&gt;Choose HTTP. It lets many clients connect, and it sits behind the same authentication, rate limiting, and observability you already run in front of your app. You do not have to invent a second operational stack for your AI surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal route handler
&lt;/h2&gt;

&lt;p&gt;The shape is a POST handler that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authenticates the caller&lt;/li&gt;
&lt;li&gt;Parses the JSON-RPC request&lt;/li&gt;
&lt;li&gt;Dispatches to the right tool&lt;/li&gt;
&lt;li&gt;Returns the result
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/mcp/route.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;caller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;             &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TOOLS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;     &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonRpcError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;32601&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Method not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;                    &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="na"&gt;jsonrpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note what happens before any tool runs: the caller is authenticated, and the arguments are parsed against a schema. Neither step is optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exposing tools without handing out the keys
&lt;/h2&gt;

&lt;p&gt;A tool is a named, typed function the model may call.&lt;/p&gt;

&lt;p&gt;The temptation is to expose a thin passthrough to an internal API. The discipline is to expose the &lt;strong&gt;capability&lt;/strong&gt;, not the API.&lt;/p&gt;

&lt;p&gt;A passthrough tool called &lt;code&gt;callInternalApi(path, method, body)&lt;/code&gt; is not a tool. It is a remote shell with extra steps. The model can reach anything the service account can reach, and your audit log records "called the API" rather than "read customer 4821's billing status."&lt;/p&gt;

&lt;p&gt;Three rules that hold up in production:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The server holds its own scoped credentials.&lt;/strong&gt; The model never sees a key. Each tool runs with the narrowest permission that does its job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No tool is "run arbitrary query."&lt;/strong&gt; If a tool accepts SQL, Cypher, or a shell string, you have built an injection surface that no amount of prompting will close.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every input is validated at the boundary.&lt;/strong&gt; A model or a prompt injection riding inside retrieved data will eventually send something malformed or hostile. Parse with a schema, reject on failure, and log the rejection.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes in production
&lt;/h2&gt;

&lt;p&gt;The demo works on your laptop. These are what break first when it does not.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;What to add&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Per-caller identity, not a shared secret&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Permission check inside each tool, not just at the route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limiting&lt;/td&gt;
&lt;td&gt;Per caller and per tool agents retry aggressively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeouts&lt;/td&gt;
&lt;td&gt;Every downstream call needs one; agents will hang otherwise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit logging&lt;/td&gt;
&lt;td&gt;Caller, tool, arguments, result, timestamp immutable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error shape&lt;/td&gt;
&lt;td&gt;Return structured JSON-RPC errors, never raw stack traces&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last one matters more than it looks. A stack trace returned to a model becomes context the model reasons over, and leaks your internals into whatever the agent does next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go next
&lt;/h2&gt;

&lt;p&gt;Once the route is live, the real work is tool design deciding what each tool exposes and, more importantly, what it refuses to.&lt;/p&gt;

&lt;p&gt;That is a security question more than an engineering one. &lt;a href="https://www.agenticgiants.com/blog/mcp-server-security" rel="noopener noreferrer"&gt;MCP server security&lt;/a&gt; covers the threat model and a hardening checklist to run before anything touches a system of record.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;We build production MCP servers for regulated industries. If you are shipping one, &lt;a href="https://www.agenticgiants.com/contact" rel="noopener noreferrer"&gt;talk to our team&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>nextjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>What Is an MCP Server? An Enterprise Guide</title>
      <dc:creator>Syed Zadi</dc:creator>
      <pubDate>Mon, 19 Oct 2026 12:30:46 +0000</pubDate>
      <link>https://dev.to/syedzadi/what-is-an-mcp-server-an-enterprise-guide-5a7n</link>
      <guid>https://dev.to/syedzadi/what-is-an-mcp-server-an-enterprise-guide-5a7n</guid>
      <description>&lt;p&gt;Every AI agent needs data. The question is whether it gets that data through a governed, auditable channel or through a raw database connection your security team has never reviewed.&lt;/p&gt;

&lt;p&gt;That is the problem the Model Context Protocol (MCP) solves. And the MCP server is the component that sits between your enterprise systems and the AI model.&lt;/p&gt;

&lt;p&gt;What is an MCP server?&lt;br&gt;
An MCP server is a lightweight process that exposes a specific slice of your data or tooling to an AI agent through a standardized protocol. Anthropic introduced MCP in 2024 as an open standard, and it has since been adopted across the AI industry.&lt;/p&gt;

&lt;p&gt;Think of it this way: if MCP is USB, the MCP server is the device you plug in a camera, a keyboard, a drive. Each server does one thing and declares exactly what it offers.&lt;/p&gt;

&lt;p&gt;Three pieces make up an MCP integration:&lt;/p&gt;

&lt;p&gt;Host: The AI application (Claude Desktop, your custom agent, an IDE)&lt;br&gt;
Client: Maintains a 1:1 connection with a single server&lt;br&gt;
Server: Exposes tools, resources, and prompts from one data domain&lt;br&gt;
Why the protocol exists&lt;br&gt;
Before MCP, every AI integration was a custom REST wrapper. A LangChain tool calling your CRM looked nothing like a LangChain tool calling your ERP. Every new data source meant a new integration pattern, a new auth flow, a new set of failure modes.&lt;/p&gt;

&lt;p&gt;MCP replaces that with a single contract: the server declares its capabilities, the client discovers them at runtime, and the model calls them through a typed interface. One pattern, regardless of what sits behind the server.&lt;/p&gt;

&lt;p&gt;For enterprises, this matters because:&lt;/p&gt;

&lt;p&gt;Security teams can audit a finite surface not an unbounded set of custom integrations&lt;br&gt;
New data sources plug in without rebuilding the agent add a server, the agent discovers it&lt;br&gt;
Vendor lock-in drops swap the model, keep the servers&lt;br&gt;
Host, client, and server&lt;br&gt;
The host is the application the user interacts with. The client is the connection manager one client per server, maintaining session state and handling the handshake. The server is where your logic lives.&lt;/p&gt;

&lt;p&gt;This separation matters operationally. A server can be restarted, versioned, or replaced without touching the host application. A new model can be swapped into the host without rewriting a single server.&lt;/p&gt;

&lt;p&gt;Why enterprises build custom servers&lt;br&gt;
Public MCP servers exist for common tools GitHub, Slack, Postgres. They are useful for prototyping and nearly always wrong for production.&lt;/p&gt;

&lt;p&gt;The reason: a generic Postgres MCP server exposes arbitrary SQL. That is exactly what you do not want an AI model holding. A production server exposes operations, not access.&lt;/p&gt;

&lt;p&gt;At Agentic Giants we build one server per data domain. A real deployment might look like:&lt;/p&gt;

&lt;p&gt;Server  What it exposes What it does NOT expose&lt;br&gt;
Task Server Task creation, status, assignments  Raw database queries&lt;br&gt;
File Server File metadata, upload/download  File system paths&lt;br&gt;
User Server User profiles, roles    Password hashes, tokens&lt;br&gt;
Activity Server Audit logs, events  PII without masking&lt;br&gt;
Each server enforces its own access controls. The model never sees raw infrastructure it sees a curated, permission-scoped interface.&lt;/p&gt;

&lt;p&gt;What makes an MCP server safe&lt;br&gt;
Four principles separate a production MCP server from a demo:&lt;/p&gt;

&lt;p&gt;Least privilege per tool. Each tool declaration specifies exactly which parameters it accepts and which data it returns. The model cannot improvise a query or reach a field the server does not expose.&lt;/p&gt;

&lt;p&gt;No raw query composition. The server translates structured requests into backend queries. The model asks for "tasks assigned to user X in the last 7 days" the server builds and executes the query. SQL injection becomes structurally impossible, because the model never composes SQL.&lt;/p&gt;

&lt;p&gt;Immutable audit logs. Every tool call, every parameter, every response logged and traceable. When compliance asks "what did the AI access?" you have a complete answer, not a reconstruction.&lt;/p&gt;

&lt;p&gt;Human in the loop. MCP supports approval flows. High-risk operations deleting data, sending external communications, moving money can require explicit human confirmation before the server executes.&lt;/p&gt;

&lt;p&gt;How many servers do you need?&lt;br&gt;
One per data domain is the pattern that works. Not one per table, and not one monolithic server for everything.&lt;/p&gt;

&lt;p&gt;Too few servers and you have a god-object problem: one server with broad access is one server with a broad blast radius. Too many and you pay orchestration overhead on every request.&lt;/p&gt;

&lt;p&gt;For most enterprises, 5–15 servers cover the full data landscape. Our largest production deployment runs ten servers, one per data domain, and has been stable for ninety days.&lt;/p&gt;

&lt;p&gt;Getting started&lt;br&gt;
If you are evaluating MCP for your enterprise:&lt;/p&gt;

&lt;p&gt;Map your data domains CRM, ERP, document store, task management&lt;br&gt;
Pick the first high-value agent use case usually internal knowledge retrieval or task automation&lt;br&gt;
Build one server for that domain get it into production, learn the operational patterns&lt;br&gt;
Expand one domain at a time each new server is additive, never a rewrite&lt;br&gt;
The protocol is open and the specification is at modelcontextprotocol.io. The enterprise question is not whether to adopt MCP — it is how to build servers your security and compliance teams will actually approve.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>security</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
