<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>The Agentic Company</title><description>Technical blueprints, architecture frameworks, and benchmarks for building enterprise context engines, MCP tooling, and permission-aware AI agent systems.</description><link>https://agntc.work/</link><language>en-us</language><ttl>60</ttl><item><title>Permission-Aware RAG for Enterprise Knowledge Systems</title><link>https://agntc.work/blog/permission-aware-rag/</link><guid isPermaLink="true">https://agntc.work/blog/permission-aware-rag/</guid><description>Enforce role-based access control at query time across vector databases and GraphRAG pipelines.</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate><content:encoded>
          &lt;p&gt;&lt;strong&gt;Executive Summary:&lt;/strong&gt; Permission-aware RAG applies role-based access control filters during retrieval, so sensitive chunks never reach an unprivileged context window. The control belongs at the vector store, not in the prompt.&lt;/p&gt;
          &lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Filter at retrieval time using security metadata so unauthorized chunks never enter the prompt.&lt;/li&gt;&lt;li&gt;GraphRAG needs permissions on both nodes and edges, not just documents.&lt;/li&gt;&lt;li&gt;Payload indexes keep metadata filters in the low-millisecond range.&lt;/li&gt;&lt;/ul&gt;
          &lt;hr /&gt;
          &lt;p&gt;Retrieval augmented generation collapses the distance between a question and every document behind it. In an enterprise that includes compensation tables, incident reports, and board decks. The failure mode is not a bad answer; it is a correct answer built from a document the caller was never allowed to read.&lt;/p&gt;
&lt;h2&gt;The control belongs at retrieval&lt;/h2&gt;
&lt;p&gt;The only durable place to enforce access is the retrieval step. If an unauthorized chunk reaches the prompt, every downstream control is a mitigation rather than a boundary. Attach a security predicate to the query and let the vector store do the filtering.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const results = await qdrant.search(&apos;knowledge&apos;, {
  vector: embedding,
  limit: 8,
  filter: {
    must: [
      { key: &apos;tenant_id&apos;, match: { value: tenantId } },
      { key: &apos;acl&apos;, match: { any: callerRoles } },
    ],
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Where teams get it wrong&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Post-filter in application code&lt;/td&gt;
&lt;td&gt;Over-fetch then discard, leaks in logs&lt;/td&gt;
&lt;td&gt;Filter inside the query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt-level instructions&lt;/td&gt;
&lt;td&gt;Model may ignore or summarize protected text&lt;/td&gt;
&lt;td&gt;Enforce in retrieval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-document ACL only&lt;/td&gt;
&lt;td&gt;Graph edges bypass document rules&lt;/td&gt;
&lt;td&gt;Permission nodes and edges&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;GraphRAG needs dual-level permissions&lt;/h2&gt;
&lt;p&gt;Graph retrieval traverses relationships. A node may be visible while the edge that connects it encodes a sensitive relationship. Apply the same security predicate to node lookups and to edge traversals, and audit both.&lt;/p&gt;

        </content:encoded><author>The Agentic Company Editorial Team</author><category>security-governance</category><rawMarkdownUrl>https://agntc.work/blog/permission-aware-rag.md</rawMarkdownUrl></item><item><title>MCP Server Architecture for Enterprise Tool Integration</title><link>https://agntc.work/blog/mcp-server-architecture/</link><guid isPermaLink="true">https://agntc.work/blog/mcp-server-architecture/</guid><description>Design Model Context Protocol servers that expose enterprise tools and share context safely across agents.</description><pubDate>Thu, 10 Sep 2026 00:00:00 GMT</pubDate><content:encoded>
          &lt;p&gt;&lt;strong&gt;Executive Summary:&lt;/strong&gt; An enterprise MCP server is a typed, permissioned boundary between agents and internal systems. Design it around explicit tools, scoped credentials, and deterministic error contracts.&lt;/p&gt;
          &lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Model each internal capability as a narrow, well-described tool rather than a generic executor.&lt;/li&gt;&lt;li&gt;Scope credentials per tool so a compromised agent cannot exceed its grant.&lt;/li&gt;&lt;li&gt;Return deterministic, typed errors so agents can recover instead of guessing.&lt;/li&gt;&lt;/ul&gt;
          &lt;hr /&gt;
          &lt;p&gt;Agents become useful when they can act, and acting means calling internal systems. The Model Context Protocol standardizes that boundary: a server advertises tools, an agent calls them, and the transport is uniform across providers. What the protocol does not decide is your security and error model. That is the architecture.&lt;/p&gt;
&lt;h2&gt;Tools, not a generic executor&lt;/h2&gt;
&lt;p&gt;The fastest way to create an unsafe agent is a single &lt;code&gt;run_query&lt;/code&gt; tool. Model each capability as a narrow tool with a typed schema, so the agent&apos;s surface area is legible and reviewable.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;server.tool(
  &apos;get_invoice_status&apos;,
  { invoiceId: z.string().uuid() },
  async ({ invoiceId }, ctx) =&amp;gt; {
    const invoice = await billing.getInvoice(invoiceId, ctx.auth.scopes);
    if (!invoice) return { error: &apos;not_found&apos; as const };
    return { status: invoice.status, dueAt: invoice.dueAt };
  }
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Credentials are per-tool&lt;/h2&gt;
&lt;p&gt;A shared service account turns every agent into a superuser. Issue scoped credentials per tool call, derived from the caller identity, and deny by default.&lt;/p&gt;
&lt;h2&gt;Errors are part of the interface&lt;/h2&gt;
&lt;p&gt;Agents plan around outcomes. Return typed, non-throwing errors such as &lt;code&gt;not_found&lt;/code&gt; or &lt;code&gt;rate_limited&lt;/code&gt; and document them, so the agent retries or escalates instead of fabricating a result.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Weak default&lt;/th&gt;
&lt;th&gt;Enterprise contract&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Tooling&lt;/td&gt;
&lt;td&gt;One generic executor&lt;/td&gt;
&lt;td&gt;Narrow typed tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Shared service account&lt;/td&gt;
&lt;td&gt;Per-call scoped credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Errors&lt;/td&gt;
&lt;td&gt;Thrown exceptions&lt;/td&gt;
&lt;td&gt;Typed, documented outcomes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

        </content:encoded><author>The Agentic Company Editorial Team</author><category>mcp-tooling</category><rawMarkdownUrl>https://agntc.work/blog/mcp-server-architecture.md</rawMarkdownUrl></item></channel></rss>