ai technology
MCP and Harness Engineering: Building an Environment Where LLMs Can Work
Junyoung Park · 2026-08-17 · 16 min
Suppose we ask an LLM to fix some code. The model can read code and suggest a patch. Yet it cannot inspect the current implementation if it has no access to the repository. It cannot know whether the patch works if it cannot run the build. It cannot tell whether the problem is gone if it cannot read the logs or see the screen. Its claim of success remains inside the answer.
Is a larger model always the first solution to this problem? While studying MCP and Harness Engineering I began to think that the environment outside the model is often more important. They are different concepts. Still they begin with the same question.
What must we prepare for an LLM to finish real work rather than produce a plausible answer?
MCP concerns the contract for reaching external information and capabilities. Harness Engineering concerns the entire working environment that includes those connections. This article does not treat MCP as another name for Tool Calling. I will first examine why a shared protocol became useful. Then I will connect it to the way a Harness manages goals and state and verification.
This article follows the MCP 2026-07-28 specification. Earlier material describes a stateful session and an initialization handshake. The latest revision changed the protocol core to a stateless request-response design. The broad separation of responsibilities between a Host and Client and Server is still useful for understanding the system.
Why a Prompt Is Not Enough
Early LLM applications were largely about writing a good prompt. We assigned a role and specified an output format. Then we received one response. An Agent works differently. It makes several decisions and takes several actions. It finds files and calls APIs. It uses the result of one action to decide what to do next. The initial prompt is only one part of what the model sees.
- System instructions
- Conversation and work history
- Retrieved documents and files
- Descriptions of available Tools
- Results returned by those Tools
- The current plan and remaining work
- Errors and test results
Together these items become the Context that shapes the next output. Anthropic's article on Context Engineering frames this as the continuing task of selecting what should enter a limited Context Window. The goal is not to include the largest possible amount of information. It is to provide the smallest useful set of high-signal information for the current decision.
Prompt Engineering is close to writing one instruction well. Context Engineering is closer to updating the reference set as work progresses. Tool Calling becomes a core part of this process as soon as the model needs information from the outside world.
What Happens When We Connect Every Tool by Hand
A direct function registration is enough for a small Agent. We can write a function that calls a weather API and describe its arguments with JSON Schema. The situation changes as the number of Agent Frameworks and external systems grows.
Imagine an internal search Agent and a coding Agent. Both need a file system and GitHub and an internal database. Each Framework has its own Tool registration interface. Authentication may be configured in a different place. Streaming and timeouts may follow different conventions. Several adapters must be updated when a database schema or API response changes.
If we have Frameworks and Tools then direct integration conceptually creates connection points. Real implementation effort does not increase according to this exact equation. Shared code can reduce it. The repeated need for an Adapter that understands both sides still remains.
MCP gathers those connection points behind a common Protocol.
MCP does not remove the differences between external systems. It standardizes the boundary that an Agent meets.
An Agent Framework that implements an MCP Client can discover and call capabilities from different MCP Servers through the same interface. A Tool provider can expose a capability through an MCP Server and make it reusable across Hosts. The connection structure becomes conceptually closer to .
One distinction matters here. MCP does not remove every SDK or integration layer. A Server that calls the GitHub API still needs to understand GitHub authentication and pagination and error responses. A database Server still needs to handle queries and connection pools and permissions. MCP standardizes how a capability is discovered and called and how its result is returned. It does not standardize the internal behavior of every connected system.
What MCP Standardizes
MCP defines a request format between a Client and Server using JSON-RPC messages. A Server exposes its capabilities through common primitives.
| Primitive | Responsibility | Example |
|---|---|---|
Tools | Provide executable actions | API calls and file edits and database queries |
Resources | Provide data that can become Context | File contents and schemas and Git history |
Prompts | Provide reusable prompt templates | Code review or document summary templates |
Early MCP documentation described Prompts as mostly user-selected and Resources as application-managed. Tools could be selected by the model. This does not mean that the model owns the final authority. The Host still decides whether a call is allowed and whether user confirmation is required.
The responsibilities can be divided as follows.
Host
The Host is the application where the LLM and user meet. It chooses which Servers to connect to and manages permissions and consent. It also decides how Context from several Servers will be given to the model.
MCP Client
The Client handles the Protocol inside the Host. It discovers Server capabilities and sends Tool calls. It passes responses and errors back in a form that the Host can use.
MCP Server
A Server exposes capabilities for a focused domain through MCP. It may read local files or call an external API. It may be a thin Adapter in front of an internal database. It can focus on its own domain without seeing the full conversation or the internal state of every other Server.
This separation matters for more than code reuse. It helps define which component manages user consent and which Server is allowed to reach which data.
How Local Files and APIs and Databases Fit
There are few restrictions on what can sit behind an MCP Server. A Server can call a REST API or read a local SQLite file. It can reach an internal Vector Database or a remote PostgreSQL instance. This should not be confused with the model connecting directly to the database.
A common flow looks like this.
- A Server publishes the name and input schema of a Tool such as
search_documents. - The Host places the relevant Tool description in the model Context.
- The model proposes a Tool call when it decides that the current task needs one.
- The Host checks permissions and policy before sending the request through the Client.
- The Server calls the real API or database and returns a structured result.
- The Host includes only the useful part of that result in the next Context.
Local connections commonly use stdio. The Client starts a Server process and exchanges messages through standard input and output. Remote Servers can use Streamable HTTP. In the 2026-07-28 revision each request carries the Protocol and Client information it needs. State is no longer hidden in a transport session. This makes routing and scaling on ordinary HTTP infrastructure easier.
The application itself can still be stateful. A long workflow may need a workflow ID. A Server can return an explicit handle and accept it again in a later call. A stateless Protocol is not the same as a stateless task.
A Shared Protocol Does Not Solve Security
MCP makes connections easier. It also makes it easier to attach powerful Tools to an Agent. A system with a read-only file Tool has a different risk profile from one that can mutate a production database. Using a Protocol does not make a Server or Tool result trustworthy.
The official MCP Security Best Practices covers authentication as well as local Server execution and token handling and SSRF. A practical first checklist looks like this.
| Risk | Response |
|---|---|
| Excessive permission | Separate reads from writes and grant the smallest scope |
| Destructive Tool calls | Require explicit approval before deletion or deployment or payment |
| Malicious Server | Verify the source and startup command and use a Sandbox |
| Prompt injection | Treat Resources and Tool results as untrusted input |
| Token misuse | Separate the MCP Server token from downstream API tokens |
| SSRF and internal network access | Validate URLs and enforce egress policy and block private ranges |
| Untraceable actions | Record the caller and arguments and result and approval history |
Token passthrough deserves particular care. If an MCP Server accepts a Client token and forwards it to a downstream API without proper validation then the audience and trust boundary become unclear. A Server should validate a token that was issued for itself. It should use separate credentials intended for the downstream API.
A database Server should also prefer narrow read-only Tools over one unrestricted run_sql Tool. Names and descriptions cannot replace authorization. A focused interface does make policy enforcement and auditing easier.
Is MCP Enough for an Agent to Finish the Job?
MCP extends the distance an Agent can reach. It does not define what the Agent should accomplish or when the work is complete. A search Tool is not useful if the Agent cannot identify the right document. A coding Tool does not prove a patch if the Agent does not know how to run the tests. Logs are only numbers if the expected healthy state is unknown.
This is where Harness Engineering becomes useful.
Harness Engineering is not a Protocol Specification like MCP. I use the term here to mean designing the environment around a model so that it can understand an objective and find Context and act and verify the result.
One simple representation is:
MCP is a useful component for connecting Tools and Context sources. MCP itself does not design the objective or completion criteria or tests. It can belong inside a Harness. The two concepts are not interchangeable.
A Good Harness Turns Work into a Loop
Verification is not decoration at the end. It compares the observed result with the original goal.
The flow required for a long Agent task is surprisingly simple.
- Define the goal: what should change and what done means.
- Assemble the context: the files, documents, and constraints needed now.
- Act: use a Tool to make one small change.
- Observe the execution result, errors, screen, and metrics.
- Verify the observed state against the completion criteria.
- Update the plan and work record before assembling the next Context.
The important part is not to connect one Action directly to another. Without observation and verification an Agent can promote its own assumption into a fact for the next step. One misunderstanding can then spread across the entire task.
Why Goals and State Should Be Written Down
A long task may not fit inside one Context Window. Intermediate results may be compacted. A session may change. A decision that exists only in a person's memory or a chat thread is close to nonexistent from the Agent's point of view.
OpenAI's Harness Engineering article describes a system where repository knowledge became the System of Record. A short AGENTS.md served as a map instead of one enormous manual. Detailed design documents and execution plans lived elsewhere and were retrieved when needed. The team used Progressive Disclosure rather than loading everything into Context at the start.
A work record does not need to become a long diary. The following structure preserves much of what the next decision needs.
Goal:
Completion criteria:
Confirmed facts:
Attempts and observed results:
Remaining risks:
Next action:
We keep attempted methods to avoid repeating the same command or returning to a rejected hypothesis. We should not place every line of raw logs back into Context either. A failure should be compressed into a form that helps the next decision rather than erased.
The System Must Verify Results Rather Than Answers
We can ask an LLM to review its own answer. That is useful. Self-review with the same Context and the same misunderstanding is still a weak substitute for external verification.
Verification becomes stronger as it becomes more executable.
| Task | Verification signal |
|---|---|
| Code change | Tests and type checks and lint and build |
| UI change | Real browser interaction and DOM inspection and screenshots |
| API change | Contract tests and status codes and response schemas |
| Retrieval improvement | A fixed query set and recall and failure-case review |
| Translation improvement | Reference data and error categories and domain-expert review |
| Production incident | Logs and metrics and traces and a reproduction procedure |
A good Harness makes these signals directly available to the Agent. A test suite that the Agent cannot locate or run is almost equivalent to no test suite. A dashboard that the Agent cannot access cannot support a decision. In the OpenAI example the Agent became able to reproduce and validate changes only after the UI and logs and metrics and traces were made legible to it.
This connects to my earlier article Generation Is Cheap and Judgment Is Expensive. The faster an Agent can produce output the more valuable a verifiable environment becomes. Faster generation does not lower the completion standard.
The Parts of a Harness That Need Maintenance
It is too narrow to identify a Harness with one Framework or configuration file. Several parts must remain aligned.
| Part | Question to ask |
|---|---|
| Objective | Are the goal and completion criteria observable |
| Context Map | Can the Agent find where relevant knowledge lives |
| Tool Interface | Are inputs and outputs and side effects clear |
| State | Do progress and decisions and failures survive |
| Verification | Can the result be checked mechanically |
| Guardrails | Are permissions and approvals and Sandbox boundaries appropriate |
| Observability | Can the Agent read logs and metrics and traces |
| Maintenance | Can stale documents and Tools be found and removed |
More documentation does not automatically make a better Harness. More Tools do not automatically make a more capable Agent. Every Tool description consumes Context. Similar Tools also increase selection errors. Common paths should be short and explicit. Rare information can remain discoverable through search.
Documentation can be more dangerous than no documentation when it disagrees with the real code. Documentation should therefore become a verification target. CI can check whether links work and schemas are current and commands still run. Those checks improve the reliability of future Context.
Common Misunderstandings
Is MCP an Agent Framework?
No. MCP is a Protocol for exchanging Context and capabilities. Planning and Tool selection and loop control remain the responsibility of the Host or Agent Framework.
Does MCP Remove Every Custom SDK?
No. MCP unifies the Integration Boundary that was repeated for each Agent and Tool. Code that talks to the real API or database is still required inside the Server. Client and Server implementations may also use MCP SDKs.
Does Connecting More Tools Always Improve the Answer?
No. Irrelevant Tool descriptions occupy Context. Overlapping functions make selection harder. It is more stable to expose only the Tools that match the current task and permission level.
Is a Long System Prompt a Good Harness?
A long Prompt is only one part of a Harness. A giant instruction file obscures priority and becomes stale quickly. A short map with a navigable document structure is often more useful.
Is Verification Complete When the Agent Explains the Result?
An explanation is not evidence. The system needs signals from outside the answer such as test output and the actual screen and query results. It should also record what was executed and what could not be executed.
We Do Not Need a Giant Agent Platform on Day One
The term Harness Engineering can make it sound as though a complex Platform must come first. It is usually better to prepare what one repeatable task needs from beginning to end.
- Choose one task that happens repeatedly.
- Turn done into an executable condition.
- Provide short links to the required files and documents.
- Begin with read-only Tools.
- Connect one MCP Server and record its calls.
- Add narrow permissions and approval steps to write Tools.
- Record failures and improve the Tool or document that caused them.
Repeated manual integrations will reveal where MCP helps. Repeated navigation failures will reveal where the Context Map is weak. Repeated human checks will reveal where a new Verifier is useful. Harness Engineering is less about designing a finished Platform in one attempt. It is more about turning repeated failures into improvements to the environment.
Conclusion
MCP reduces repeated integration work by giving external Context and Actions a shared contract. APIs, files, and databases keep their own complexity behind MCP Servers. A Client can discover and call them through a common interface.
Harness Engineering addresses a wider problem. It builds an environment where a model can find the objective and read the necessary Context and use Tools and verify the result. MCP is an important connection mechanism inside that environment. It is not the entire environment. Plans and state and documents and tests and logs and permissions must work together.
Choosing a capable model still matters. Placing that model in a poor environment is much like asking a talented new engineer to finish a task without showing where the documentation lives or how the tests run. The work may look convincing for a while. Reliable completion is a different question.