<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>MCP | Hailin Liu</title><link>https://hailin.ai/tags/mcp/</link><atom:link href="https://hailin.ai/tags/mcp/index.xml" rel="self" type="application/rss+xml"/><description>MCP</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Tue, 28 Apr 2026 00:00:00 +0000</lastBuildDate><image><url>https://hailin.ai/media/icon_hu_76af94951e63d377.png</url><title>MCP</title><link>https://hailin.ai/tags/mcp/</link></image><item><title>SafeAgent Coder: Runtime-Controlled Coding Agent</title><link>https://hailin.ai/projects/safeagent-coder/</link><pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate><guid>https://hailin.ai/projects/safeagent-coder/</guid><description>&lt;h2 id="what-is-safeagent-coder"&gt;What is SafeAgent Coder?&lt;/h2&gt;
&lt;p&gt;SafeAgent Coder is a coding agent that works directly inside software
repositories. It inspects a project&amp;rsquo;s structure, finds the files and symbols
that matter, reads and searches source code, makes targeted changes, prepares a
development environment, and runs the commands needed to build or test a
project — all within one workflow.&lt;/p&gt;
&lt;p&gt;Everything comes together in a local development workspace. The agent starts
by understanding an unfamiliar repository, then moves on to making and
validating a change without switching tools or copying code between windows.
File operations, repository inspection, environment setup, and command
execution are exposed to the agent as tools, and the surrounding application
provides the workspace and interface where those actions actually take place.&lt;/p&gt;
&lt;p&gt;Tool use stays visible while the agent works. Selected operations are
intercepted before they take effect, so they can be checked or sent for human
approval when needed. Controlled execution is one part of SafeAgent Coder; at
its core it is a coding agent built for practical, repository-level development
tasks.&lt;/p&gt;
&lt;h2 id="how-does-it-work-with-a-repository"&gt;How Does It Work with a Repository?&lt;/h2&gt;
&lt;p&gt;When SafeAgent Coder receives a repository-level task, it begins by building
enough context about the project before making any changes. For an unfamiliar
codebase, that usually means inspecting the directory structure, identifying
entry points and dependency files, locating tests, and searching for the
symbols or configuration related to the task.&lt;/p&gt;
&lt;p&gt;From there, the agent narrows its attention to the files that actually matter.
It reads source code, follows references across the project, and uses what it
has gathered to decide what needs to change. It favors small, targeted edits
and works incrementally whenever possible.&lt;/p&gt;
&lt;p&gt;Once a change is in place, the same workflow can continue into execution. The
agent prepares a Python environment, installs project dependencies, runs build
or test commands, inspects the output, and uses those results to decide whether
another iteration is needed.&lt;/p&gt;
&lt;p&gt;For example, a request such as:&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;Find why the tests are failing and fix the problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;might lead the agent through a sequence like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;inspect project → locate tests → search relevant code → read source → edit → run tests → verify&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Every task takes its own path. A simple question may need only a few inspection
tools, while a setup, debugging, or adaptation task can involve several rounds
of reading, execution, and modification. The goal is to let the agent treat the
repository as a living development environment.&lt;/p&gt;
&lt;h2 id="inside-the-agent"&gt;Inside the Agent&lt;/h2&gt;
&lt;p&gt;SafeAgent Coder builds its coding agent with LangChain and LangGraph. The
agent is assembled from a chat model, a repository-oriented system prompt,
a set of MCP tools, persistent graph state, and an execution layer that sits
around tool calls.&lt;/p&gt;
&lt;p&gt;The current implementation pulls its tools from LangChain&amp;rsquo;s
&lt;code&gt;MultiServerMCPClient&lt;/code&gt;. When a new agent session is created, it connects to
the local MCP server and loads the available development tools before passing
them to &lt;code&gt;create_agent&lt;/code&gt;. The model, tools, system prompt, checkpoint memory,
and middleware are then combined into a single LangGraph-backed agent named
&lt;code&gt;vibe_shell&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiServerMCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checkpointer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;interrupt_after&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;vibe_shell&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The system prompt gives the agent a fairly specific working style. It is
encouraged to understand a repository before acting, narrow its search before
reading large parts of the codebase, prefer targeted edits over broad
rewrites, and run commands from an explicit project directory. This keeps the
agent loop focused on deliberate progress through a repository, with each tool
call serving that progress.&lt;/p&gt;
&lt;p&gt;Each user session also carries its own agent state. A &lt;code&gt;MemorySaver&lt;/code&gt;
checkpointer keeps the LangGraph thread state across multiple steps, while the
application caches the corresponding agent instance by session ID. That
continuity matters for repository tasks that need several rounds of reasoning
and tool use: the agent inspects a project, receives tool results, continues
reasoning, makes a change, and runs another command, all without treating every
action as an independent request.&lt;/p&gt;
&lt;p&gt;Execution is streamed live. The runner listens for model-output, tool-start,
and tool-end events as the graph runs. Model tokens arrive in the chat
interface as they are generated, while each tool invocation and its result
land in a separate execution trace. In practice, you can watch both sides of
the agent at once — what it is saying and what it is actually doing inside the
workspace.&lt;/p&gt;
&lt;p&gt;The agent also supports interruptions after tool execution. SafeAgent Coder
uses this hook for controlled execution and human-in-the-loop interactions,
layered on top of the same coding-agent loop. We will come back to that
shortly.&lt;/p&gt;
&lt;h2 id="the-tool-workspace"&gt;The Tool Workspace&lt;/h2&gt;
&lt;p&gt;The agent works inside a dedicated development workspace, backed by a Docker
container and exposed through an MCP server. Keeping the agent&amp;rsquo;s environment
separate means it can touch files and run commands in a safe, isolated place.&lt;/p&gt;
&lt;p&gt;The playground container runs a &lt;code&gt;FastMCP&lt;/code&gt; server and mounts a working directory
at &lt;code&gt;/home/ubuntu/workspace&lt;/code&gt;. Docker Compose exposes the MCP service on the host,
and the LangChain agent connects to it through &lt;code&gt;MultiServerMCPClient&lt;/code&gt;. The
reasoning side of the agent stays cleanly separated from the environment where
file operations, project setup, and command execution happen.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://hailin.ai/projects/safeagent-coder/images/safeagent-coder-execution-architecture.png"
alt="The execution stack: a LangChain/LangGraph agent talks MCP to a FastMCP server inside a Docker playground, whose mounted workspace holds the software repository."&gt;&lt;figcaption&gt;
&lt;p&gt;The execution stack: a LangChain/LangGraph agent talks MCP to a FastMCP server inside a Docker playground, whose mounted workspace holds the software repository.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The container behaves like a small development machine. It is based on Ubuntu
and ships with common command-line utilities, plus Git, Python, virtual
environments, and &lt;code&gt;uv&lt;/code&gt;, so the agent can handle repositories that need more
than simple file editing.&lt;/p&gt;
&lt;p&gt;The MCP server turns those environment capabilities into a set of
repository-oriented tools that cover a normal development workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project understanding&lt;/strong&gt; — &lt;code&gt;inspect_project&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;file_glob_search&lt;/code&gt;,
&lt;code&gt;search_in_files&lt;/code&gt;, and &lt;code&gt;get_file_info&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source inspection and editing&lt;/strong&gt; — &lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;create_new_file&lt;/code&gt;, and
&lt;code&gt;single_find_and_replace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution&lt;/strong&gt; — &lt;code&gt;run_terminal_command&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repository and network access&lt;/strong&gt; — &lt;code&gt;clone_repo&lt;/code&gt; and &lt;code&gt;fetch_url_content&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment setup&lt;/strong&gt; — &lt;code&gt;setup_python_env&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These tools are deliberately narrow, giving the model focused operations for
common development steps. For example, &lt;code&gt;inspect_project&lt;/code&gt; looks for common
project markers such as &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;Cargo.toml&lt;/code&gt;,
&lt;code&gt;go.mod&lt;/code&gt;, &lt;code&gt;pom.xml&lt;/code&gt;, &lt;code&gt;Makefile&lt;/code&gt;, and &lt;code&gt;CMakeLists.txt&lt;/code&gt;, and returns likely
project types, dependency files, entry points, and tests. That gives the agent
a quick first view of an unfamiliar repository before it starts reading files
one by one.&lt;/p&gt;
&lt;p&gt;For source navigation, the workspace separates searching paths from searching
contents. &lt;code&gt;file_glob_search&lt;/code&gt; narrows the repository by file pattern, while
&lt;code&gt;search_in_files&lt;/code&gt; looks for symbols or text inside matching files. Both cap
their results, so a large repository does not flood the agent context with
irrelevant information.&lt;/p&gt;
&lt;p&gt;File access follows the same workspace boundary. Before any path is used, the
MCP server resolves it against &lt;code&gt;WORKSPACE_ROOT&lt;/code&gt; and rejects paths that escape
the configured workspace. The same resolver guards reading, editing, directory
inspection, command working directories, and other file-oriented operations.&lt;/p&gt;
&lt;p&gt;When execution is needed, &lt;code&gt;run_terminal_command&lt;/code&gt; starts a Bash subprocess
inside a selected directory in the workspace and returns its exit code,
standard output, and standard error to the agent. That is how a task flows
naturally from reading code into running &lt;code&gt;pytest&lt;/code&gt;, a build command, or another
project-specific tool, then reasoning over the result.&lt;/p&gt;
&lt;p&gt;The workspace can also set a project up before running it. &lt;code&gt;setup_python_env&lt;/code&gt;
creates a virtual environment and installs dependencies from a requirements
file or project configuration, using &lt;code&gt;uv&lt;/code&gt; when available and supporting a
standard Python environment as well. Repository cloning is exposed separately
through &lt;code&gt;clone_repo&lt;/code&gt;, so a project can be brought into the workspace and
handled by the same inspection, editing, and execution workflow.&lt;/p&gt;
&lt;h2 id="controlled-execution"&gt;Controlled Execution&lt;/h2&gt;
&lt;p&gt;Giving an agent access to files and a terminal is useful, but it also means
some actions deserve more attention than others. SafeAgent Coder adds a
control layer around tool execution so proposed actions can be inspected
before they reach the workspace.&lt;/p&gt;
&lt;p&gt;In the current playground configuration, read-oriented operations such as
project inspection, file search, directory listing, and file reading proceed
directly. Actions with more visible side effects — creating or editing files,
cloning a repository, preparing an environment, or running a terminal command
— are paused for confirmation.&lt;/p&gt;
&lt;p&gt;When that happens, the proposed tool call appears in the WebUI together with
its arguments. You can approve the action and let the agent continue, or
reject it before it executes. Meanwhile, the Function Calls panel keeps a
trace of tool invocations and their results, so the agent&amp;rsquo;s execution stays
visible alongside the conversation.&lt;/p&gt;
&lt;p&gt;This control mechanism is deliberately one part of the project. The coding
workflow keeps working as before: the agent reasons about a repository,
selects tools, observes their results, and continues. The execution layer
simply adds a place to step in when a particular action deserves a human check
before it runs.&lt;/p&gt;
&lt;p&gt;A separate technical note will look more closely at how this kind of
controlled agent is built with LangChain middleware, LangGraph state,
MCP tools, and human-in-the-loop execution.&lt;/p&gt;
&lt;h2 id="safeagent-and-resources"&gt;SafeAgent and Resources&lt;/h2&gt;
&lt;p&gt;SafeAgent Coder was developed alongside &lt;strong&gt;SafeAgent&lt;/strong&gt;, our broader work on
runtime protection for agentic systems. SafeAgent Coder focuses on one concrete
application — a coding agent that works with repositories and development
tools — while SafeAgent studies the more general problem of governing agent
actions during execution.&lt;/p&gt;
&lt;p&gt;The two projects serve different purposes and complement each other.
SafeAgent Coder is the place to explore the coding-agent implementation and its
development workspace. The SafeAgent paper describes the broader runtime
protection architecture, and SafeAgent Core provides the corresponding
decision-side components.&lt;/p&gt;
&lt;p&gt;The interactive playground currently uses a lightweight configurable decision
backend, which makes it easy to experiment with different tool policies
without tying the coding agent to a particular safety backend. The agent-side
control interface stays separate, so other decision backends can be plugged
into the same execution workflow.&lt;/p&gt;
&lt;p&gt;The resources below connect this coding agent to the wider SafeAgent project:
the SafeAgent Coder implementation, the paper behind the runtime protection
architecture, and the SafeAgent Core decision-side components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
When the technical note is published, add:
- [How to Build a Controlled Tool-Using Agent with LangChain and MCP](/blog/...)
--&gt;</description></item></channel></rss>