<?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: Bruno Vieira</title>
    <description>The latest articles on DEV Community by Bruno Vieira (@bruno_vieira_39eeac09381c).</description>
    <link>https://dev.to/bruno_vieira_39eeac09381c</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%2F4045723%2Ff7cac404-0400-4ed7-a329-5eb79686eba0.jpg</url>
      <title>DEV Community: Bruno Vieira</title>
      <link>https://dev.to/bruno_vieira_39eeac09381c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bruno_vieira_39eeac09381c"/>
    <language>en</language>
    <item>
      <title>What Still Required Human Judgment When Adding MCP to an AI-Assisted SaaS</title>
      <dc:creator>Bruno Vieira</dc:creator>
      <pubDate>Fri, 24 Jul 2026 14:45:41 +0000</pubDate>
      <link>https://dev.to/bruno_vieira_39eeac09381c/what-still-required-human-judgment-when-adding-mcp-to-an-ai-assisted-saas-3n57</link>
      <guid>https://dev.to/bruno_vieira_39eeac09381c/what-still-required-human-judgment-when-adding-mcp-to-an-ai-assisted-saas-3n57</guid>
      <description>&lt;p&gt;I am building a very small SaaS for Brazilian businesses that still manage employee work hours in notebooks or spreadsheets.&lt;/p&gt;

&lt;p&gt;The product is called PontoBarato. It was built quickly and with substantial AI assistance.&lt;/p&gt;

&lt;p&gt;This is not a story about a perfectly engineered, hyperscale system. It is also not a tutorial claiming that a prompt can replace security design. It is a product-level account of what still required human judgment when I added a Model Context Protocol (MCP) interface to the application.&lt;/p&gt;

&lt;p&gt;The surprising part was not getting an assistant to call a tool. The difficult part was deciding what the assistant should be allowed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The feature sounded simpler than it was
&lt;/h2&gt;

&lt;p&gt;The initial idea was straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let a business owner connect the product to ChatGPT or Claude and manage routine tasks with natural language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The public MCP interface now supports workflows such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating and updating employees;&lt;/li&gt;
&lt;li&gt;viewing and editing weekly schedules;&lt;/li&gt;
&lt;li&gt;listing, creating, and assigning shifts;&lt;/li&gt;
&lt;li&gt;checking recent time entries;&lt;/li&gt;
&lt;li&gt;viewing expected, worked, and balance hours;&lt;/li&gt;
&lt;li&gt;reading overtime and night-work totals;&lt;/li&gt;
&lt;li&gt;viewing or updating selected company settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On paper, this is just another interface to existing features.&lt;/p&gt;

&lt;p&gt;In practice, a conversational interface introduces ambiguity that normal forms avoid. A form has required fields, dropdowns, validation messages, and visible state. A user can see which company, employee, or shift is selected.&lt;/p&gt;

&lt;p&gt;A model receives a sentence.&lt;/p&gt;

&lt;p&gt;“Move Ana to the morning shift” sounds clear until the system has two employees named Ana, several companies in the same account, or no shift literally named “morning.”&lt;/p&gt;

&lt;p&gt;The integration therefore needed boundaries before it needed more tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  A model should not choose the tenant
&lt;/h2&gt;

&lt;p&gt;PontoBarato is multi-tenant: each company must only access its own employees, schedules, and time records.&lt;/p&gt;

&lt;p&gt;The most important product rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Company scope must come from the authenticated session, not from an identifier invented or supplied by the model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if a tool receives an employee identifier, the server still has to verify that the employee belongs to the authenticated company.&lt;/p&gt;

&lt;p&gt;This sounds obvious. It is also the kind of detail that can disappear when development becomes a rapid sequence of generated endpoints and happy-path tests.&lt;/p&gt;

&lt;p&gt;AI assistance made implementation faster, but it did not decide the trust boundary. That remained a human responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Narrow tools were easier to reason about
&lt;/h2&gt;

&lt;p&gt;A generic tool such as &lt;code&gt;update_record&lt;/code&gt; would have been quick to expose. It would also have been difficult to explain, authorize, validate, and audit.&lt;/p&gt;

&lt;p&gt;I preferred tools that map to actions a business owner recognizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create an employee;&lt;/li&gt;
&lt;li&gt;assign a shift;&lt;/li&gt;
&lt;li&gt;change a weekly schedule;&lt;/li&gt;
&lt;li&gt;inspect an hours balance;&lt;/li&gt;
&lt;li&gt;update the geofence requirement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Narrow tools create more work at the beginning, but they reduce ambiguity later.&lt;/p&gt;

&lt;p&gt;They also produce better conversations. If the assistant needs an employee name, a shift, and an optional role, the tool schema can say exactly that. If information is missing, the assistant has a reason to ask.&lt;/p&gt;

&lt;p&gt;The goal was not to give the model a flexible path into the database. The goal was to expose a small set of business capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read and write operations should feel different
&lt;/h2&gt;

&lt;p&gt;“Show this month's balance” and “deactivate this employee” should not have the same level of friction.&lt;/p&gt;

&lt;p&gt;I started thinking about the tool surface in three groups:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Main concern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;list shifts or recent time entries&lt;/td&gt;
&lt;td&gt;scope and data minimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reversible write&lt;/td&gt;
&lt;td&gt;assign a shift or update a role&lt;/td&gt;
&lt;td&gt;validation and a clear result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensitive write&lt;/td&gt;
&lt;td&gt;deactivate an employee or change location rules&lt;/td&gt;
&lt;td&gt;explicit intent and auditability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not a sophisticated framework. It is a practical reminder that not every successful tool call has the same consequence.&lt;/p&gt;

&lt;p&gt;For example, deactivation is usually safer than deletion in a time-tracking product because historical records still matter. The conversational interface should not make destructive actions easier than they are in the main application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The application should calculate; the model should explain
&lt;/h2&gt;

&lt;p&gt;Time tracking involves calculations such as expected time, worked time, balances, overtime categories, and night work.&lt;/p&gt;

&lt;p&gt;It is tempting to give raw entries to a model and ask it to calculate the result. I avoided making that the normal path.&lt;/p&gt;

&lt;p&gt;If the application already has domain logic for a calculation, the MCP tool should return that application's result. The assistant can then summarize or explain it.&lt;/p&gt;

&lt;p&gt;Otherwise, the dashboard, exported report, and AI response can disagree.&lt;/p&gt;

&lt;p&gt;This distinction also made debugging easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the product remains responsible for business rules;&lt;/li&gt;
&lt;li&gt;the MCP layer is responsible for authentication, validation, and translation;&lt;/li&gt;
&lt;li&gt;the model is responsible for choosing tools and communicating results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model should not become an unofficial payroll engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller responses were better responses
&lt;/h2&gt;

&lt;p&gt;My first instinct was to return complete objects. That is easy during development because the data is already available.&lt;/p&gt;

&lt;p&gt;It is rarely what the assistant needs.&lt;/p&gt;

&lt;p&gt;For an hours-balance question, a useful response contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;employee;&lt;/li&gt;
&lt;li&gt;period;&lt;/li&gt;
&lt;li&gt;expected minutes;&lt;/li&gt;
&lt;li&gt;worked minutes;&lt;/li&gt;
&lt;li&gt;balance minutes;&lt;/li&gt;
&lt;li&gt;relevant overtime totals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does not need internal flags, unrelated settings, framework metadata, or every stored field.&lt;/p&gt;

&lt;p&gt;Compact responses reduce accidental exposure and make the assistant's final answer easier to verify.&lt;/p&gt;

&lt;p&gt;Explicit units matter too. Returning &lt;code&gt;75&lt;/code&gt; is ambiguous. Returning &lt;code&gt;balanceMinutes: 75&lt;/code&gt; is much safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-assisted development increased the need for verification
&lt;/h2&gt;

&lt;p&gt;AI assistance was excellent for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;producing repetitive handlers;&lt;/li&gt;
&lt;li&gt;drafting schemas;&lt;/li&gt;
&lt;li&gt;suggesting validation cases;&lt;/li&gt;
&lt;li&gt;generating test scaffolding;&lt;/li&gt;
&lt;li&gt;refactoring similar tool definitions;&lt;/li&gt;
&lt;li&gt;writing initial documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was not a substitute for deciding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where tenant scope comes from;&lt;/li&gt;
&lt;li&gt;which actions are too destructive;&lt;/li&gt;
&lt;li&gt;whether a response exposes unnecessary data;&lt;/li&gt;
&lt;li&gt;which calculation is authoritative;&lt;/li&gt;
&lt;li&gt;what the user should confirm;&lt;/li&gt;
&lt;li&gt;how a changed record can be audited.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generated code often looks complete before the underlying decision is complete.&lt;/p&gt;

&lt;p&gt;That was the central lesson of this feature: faster implementation increases the importance of slowing down at trust boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do before adding more tools
&lt;/h2&gt;

&lt;p&gt;The current interface is intentionally limited, and the product itself is still evolving.&lt;/p&gt;

&lt;p&gt;Before expanding it, my checklist is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;verify tenant isolation for every tool;&lt;/li&gt;
&lt;li&gt;test ambiguous names and missing resources;&lt;/li&gt;
&lt;li&gt;keep write results concise and inspectable;&lt;/li&gt;
&lt;li&gt;prefer reversible changes;&lt;/li&gt;
&lt;li&gt;minimize returned employee data;&lt;/li&gt;
&lt;li&gt;reuse the application's calculation logic;&lt;/li&gt;
&lt;li&gt;make sensitive actions require clear intent;&lt;/li&gt;
&lt;li&gt;record enough information to understand what changed;&lt;/li&gt;
&lt;li&gt;test failures, not only successful demos;&lt;/li&gt;
&lt;li&gt;add capabilities gradually.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these points is unique to MCP. MCP simply makes them easier to overlook because the conversational demo feels magical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest takeaway
&lt;/h2&gt;

&lt;p&gt;You can build a useful SaaS with substantial AI assistance. You can also create serious problems very quickly if generated code is treated as proof that authorization and business rules are correct.&lt;/p&gt;

&lt;p&gt;For me, the valuable work was not typing every line manually. It was deciding which lines should exist, which operations should not be exposed, and which claims I was actually able to verify.&lt;/p&gt;

&lt;p&gt;PontoBarato's MCP server is available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://pontobarato.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main product is at &lt;a href="https://pontobarato.com/" rel="noopener noreferrer"&gt;pontobarato.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would be especially interested in feedback from people building MCP interfaces for other multi-tenant products:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which operations did you decide not to expose, even though they were technically easy to implement?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
