Skip to main content
  1. writings/
  2. AI-Assisted Data Engineering/

Wiring Tools with MCP

·7 mins·
Table of Contents

Introduction
#

MCP is how the agent reaches the tools where the work really lives, including issue trackers, repositories, and databases. Wired well, it turns a messy brain dump into a structured issue that becomes the contract the agent reads while it implements.

For a long time I believed the path to better output was better prompts. It was not. The thing that actually moved the needle was connecting the agent to the systems my team already treats as the source of truth. The protocol that does the connecting will keep evolving, so I will focus on what the connection unlocks, which has not changed and will not.

What MCP Solves
#

The problem is isolation. An agent with no live access to your tools is guessing at everything you did not paste into the chat. It does not know the ticket number, the labels, whether a pull request already exists, or what the current state of a table is. It can write plausible text about all of these, and plausible text about facts it cannot see is exactly the kind of confident wrong answer that wastes an afternoon.

The Model Context Protocol, and whatever succeeds it, solves this by giving the agent a consistent interface to reach external systems and read their real state. Instead of guessing the ticket, it fetches the ticket. Instead of inventing a link, it looks up the live one. That single capability kills an entire category of mistakes, including wrong links, stale titles, and descriptions that have drifted away from what the code actually does. The agent stops hallucinating facts it could simply retrieve.

There is a quieter benefit underneath the obvious one. Once the agent can read the live object, every future session can re-fetch the current state instead of relying on whatever happened to be in an old chat history. The source of truth stays in the system where it belongs, and the agent reads from it freshly each time, rather than carrying a stale copy forward and slowly diverging from reality.

Connecting Issues and Repositories
#

The two connections that paid off first were the issue tracker and the code host, because together they cover the full arc of a task. With the issue tracker connected, the agent can turn my rough notes into a properly structured ticket and keep it updated as the work proceeds, without me retyping metadata into a web form. With the code host connected, it can read the repository, draft the pull request, summarize the diff, and flag the risky parts before a human reviewer has to find them.

The loop these two enable is the real product. I describe what I want in rough bullets, including the goals, the risks, the open questions, and the relevant links. The agent maps that onto my issue template so the fields read like something a reviewer would actually thank me for. I then point the agent at that issue as the source of truth while it implements, and when the branch is ready, it opens or updates the pull request from a second template that captures the summary, the test plan, the risk, and a link back to the issue.

The whole idea is one narrative in the places my team already looks, instead of three slightly different versions of the story scattered across a chat thread, a comment, and a scratch file on my desktop. For a data project the same pattern extends naturally to the warehouse and the transformation tooling, where the agent can check lineage, propose tests, and ground its work in the real schema rather than an imagined one. The connections turn the agent from a clever text generator into a participant in the systems where the work actually happens.

The Tracking Issue as Contract
#

The habit that improved my results more than any other is creating a structured tracking issue before writing code. Forcing the issue into existence early turns a messy brain dump into something precise, with scope, acceptance criteria, and explicit out-of-scope notes. That artifact then becomes the contract the agent reads while it implements, and the anchor the agent summarizes in the pull request when the work is done.

In practice, the issue does not need to be elaborate. The useful version has a goal, a short list of files or systems likely in scope, the acceptance criteria, the checks that must pass, and a few explicit non-goals. That is enough structure for a later agent run to know where to work, where not to wander, and what evidence will prove it is finished.

Templates are what make this reliable, and I know templates can look like bureaucracy. A template is really just a schema, and an agent fills in structured sections far more dependably than it invents structure from a blank page. My templates bake in what done means, what reviewers should check, and where the links belong. When the agent drafts the issue first, the result is something I can read and edit in seconds, instead of staring at an empty text box trying to remember what I meant.

The most valuable move in this whole workflow is letting the agent brief the next agent. Before I switch context, whether to a new chat, a subagent, or a long implementation pass, I have the current model document everything it did in the issue, the way a careful shift worker writes a handover before leaving. The next session reads that block to see what was done, where it was left, and what comes next, because the task was well defined with done criteria from the start. The agent is remarkably good at compressing a messy conversation into clean instructions the next session can simply pick up and run. No rediscovering the plan, no asking where it left off.

Guarding the Connections
#

A connection that can read is power, and a connection that can write or change things is real power, not a toy. Every connection you wire in deserves the limits that match what it can do, and the strict version of this gets its own part of the book. The short form belongs here, because the moment you connect a tool is the moment to set its boundaries, not later.

The defaults I insist on are least privilege and no standing destructive capability. Each connection gets the narrowest access that lets it do its job, a separate narrow role per use beats one powerful role shared across everything, and credentials live in environment variables or a secret manager rather than pasted into a chat where they end up in logs and history. Anything that can write, delete, or change real state should require an explicit confirmation before it fires, so a convenient connection never becomes a dangerous one.

This is where connecting agents to data systems gets serious, and it is why the guardrails part of this book follows so closely. A connection to a database is a connection to the thing you most cannot afford to damage. The convenience of letting the agent reach the warehouse is exactly proportional to the harm of letting it reach the warehouse with more permission than the task requires. Wire the connection for what the task needs, and nothing more.

Putting It Into Practice
#

  1. Connect the agent to the systems your team treats as the source of truth, starting with the issue tracker and code host.
  2. Write a structured tracking issue before you write code, and treat it as the contract for the work.
  3. Use templates as schemas, and let the agent fill structured sections rather than invent structure from blank pages.
  4. Keep one narrative across the issue and the pull request instead of scattering the story across tools.
  5. Before any context switch, have the agent document what was done and what comes next in the issue.
  6. Give every connection the narrowest access that fits its job, and keep credentials out of the chat entirely.
  7. Require explicit confirmation for any connection that can write or change real state, especially the database.

Related