Nothing Changed in the API. Everything Changed for the Agent.

While developing SWCraft, I needed to add support for client-server interfaces.
SWCraft is an experimental AUTOSAR software architecture environment. Its model is stored in version-controlled YAML, deterministic tools validate it and generate ARXML, diagrams and documentation, and an LLM agent works with the model through MCP.
This continues a boundary question from An Agent Can Pass Validation and Still Make an Unsafe Change. That article was about what a task authorizes an agent to change. This one is about the step before: what the model should even see when it chooses a tool.
The MCP server already had this tool:
add_interface
It creates a sender-receiver interface. For the new capability, I added:
add_cs_interface
From the perspective of a conventional API, this was a fully backward-compatible change. The existing tool did not change. Its name, arguments and implementation remained the same. The server simply gained another function.
But an LLM-driven system does not work like a conventional API client. The user does not name a function directly. The user describes a task, and the model chooses the tool.
Before the change, this request:
Create an interface called IDiagnostics.
could lead only to add_interface. After add_cs_interface was added, the model had two semantically close options.
Nothing broke syntactically. But the decision surface of the system changed.
A Tool Schema Explains How to Call a Tool
A typical MCP tool definition contains a name, a description and an input schema.
For example:
add_interface(
name: string,
element_name: string,
element_type: string
)
This information is enough to form a valid call. The description may also explain that the tool creates a sender-receiver interface.
But the schema does not answer other questions:
- Which user task does the tool solve?
- When should it be preferred over another tool?
- When is information missing?
- When should the system ask for clarification?
- Which tools may participate in the same solution?
- How does adding a new tool affect existing behavior?
This semantics is often placed in descriptions, with the final decision left to the model.
That may work for a small catalog. But SWCraft has grown from 18 to 39 MCP tools, and the catalog continues to expand. Today the entire catalog is passed to the model on every user turn.
As the catalog grows, descriptions become an informal routing policy that is difficult to test for backward compatibility.
Tasks, Not Tools, Define the System
A catalog of capabilities does not explain what the system exists to do.
The primary element should be a task: a user goal that the system is expected to solve under defined conditions. A task τ is defined by its admissible initial states, its expected result and its execution constraints.
Each task requires only part of the complete tool catalog:
Aτ ⊆ A
Here, A is the full set of server tools, while Aτ contains only the tools related to task τ.
The workflow then becomes:
The model chooses from the subset constructed for the current task, not from every capability in the system.
Composite Tasks Should Not Call Execution Tools Directly
Return to the SWCraft example.
CreateInterface is too broad a task. The system supports at least two different outcomes, and each of them is a different atomic task with its own tool scope:
If the user describes data elements, the system selects CreateSenderReceiverInterface.
If the user describes operations and arguments, it selects CreateClientServerInterface.
If the request is only:
Create an interface called IDiagnostics.
and the context does not determine the interface type, the system should ask:
Do you need a sender-receiver or a client-server interface?
At this point, the model should not choose between add_interface and add_cs_interface. The task must be determined first.
Task resolution should return:
Resolve(user intent, state)
→ ATOMIC_TASK
| CLARIFY(question)
| REJECT(reason)
Once the atomic task is selected, the tool ambiguity disappears because the two similar tools are no longer in the same decision scope.
What Makes a Task Atomic
An atomic task does not necessarily consist of one tool call. Creating an interface may include reading the existing interfaces, creating the new one and validating the model.
But inside an atomic task, there is no unresolved choice between several non-equivalent actions.
The task boundary already defines:
- the expected result;
- the required information;
- the applicable tools;
- their order or activation conditions;
- situations that require clarification;
- situations that require rejection.
If two valid but non-equivalent actions remain after the goal, state and constraints are known, the task is not yet atomic.
Similar tools therefore do not necessarily conflict. A conflict exists only when they are available at the same decision point.
Tool ambiguity is not a property of the global catalog. It is a property of a task-scoped decision point.
Task Scope Must Actually Limit Visibility
It is not enough to document that add_interface belongs to one task and add_cs_interface to another.
If both tools are still passed to the model, they remain part of the same decision surface.
The runtime must enforce that the model receives only the task scope:
The complete catalog remains on the MCP server. The orchestration layer presents the model with a task-specific projection.
Limiting the tool list passed to the model is not a new mechanic. Dynamic tool loading and tool search already exist, and they are usually motivated by context size and selection accuracy. The motivation here is different: behavioral backward compatibility. A task-scoped projection turns “adding a tool” into a change whose blast radius can be stated and tested.
This also limits the impact of future changes. A new tool added to one atomic task should not change tool selection in tasks where it never becomes visible.
Semantic Contracts at Two Levels
This architecture needs two related contracts.
A task contract defines:
- the goal;
- admissible initial states;
- success criteria;
- constraints;
- decomposition rules;
- clarification and rejection conditions;
- the task-scoped tool set.
A tool capability contract defines:
- which atomic tasks the tool supports;
- its preconditions;
- argument constraints;
- effects;
- close but unsupported cases.
The tool schema remains a syntactic contract: it explains how to form the call.
The semantic contract explains why the tool appears among the possible solutions at all.
What Should Happen When a Tool Is Added
A new MCP tool should not simply enter a global list.
Adding it requires answers to several questions:
- Which atomic task does it support?
- In which task scopes will it be visible?
- Which existing tools will be visible with it?
- Does it change the boundary of an existing task?
- Which new clarification cases appear?
- Which existing task contracts must be tested again?
The affected tasks are exactly those whose scope includes the new tool.
If the tool introduces a new atomic task, the task router must also be tested. The new task must not capture existing user intents.
But after successful task resolution, tasks with unchanged tool scopes should remain isolated from the new tool.
Semantic Contracts Become the Regression Corpus
Task contracts can contain executable examples:
(system state, user intent)
→ ATOMIC_TASK
| CLARIFY
| REJECT
After the task is selected, the execution contract defines:
(task state, plan stage)
→ CALL(tool, argument constraints)
| COMPLETE
| REJECT
When a new tool is added, the existing cases run again. The new tool should support new tasks without changing behavior inside established task scopes.
This does not prove correctness for every possible natural-language request. But it gives the system an expanding testable region and prevents known decision boundaries from degrading unnoticed.
Tool Catalogs Should Be Compiled, Not Dumped
An MCP server may own a large catalog of capabilities. That does not mean the entire catalog should become one decision surface for the model.
The system should determine the task first and then construct the minimal tool projection needed to solve it: supported tasks are decomposed into atomic tasks, an atomic task activates its scoped tools, and only then does execution begin.
Adding an MCP tool can be a breaking change not because its JSON schema changed, but because the decision space of the system changed.
A tool schema answers:
How do I call this function?
A semantic contract should answer:
In which task is this function allowed to become a possible solution?
What Still Needs to Be Tested
SWCraft provides a concrete environment in which this approach can be tested:
- its real MCP catalog grew from 18 to 39 tools;
- the complete catalog is currently passed to the model;
- individual tasks use much smaller subsets;
- the project history contains two closely related interface tools;
- the existing deterministic scenarios test execution, but not autonomous tool selection by the model.
The next step is to define task contracts for a bounded set of SWCraft workflows and compare:
old catalog
new global catalog
new task-scoped catalog
This is where I need to stop. Everything described above is still an architectural hypothesis. The reasoning is consistent, and SWCraft provides a suitable real-world example, but I do not yet know whether task scoping will preserve existing routing behavior, improve clarification, or actually limit regressions as the catalog grows.
Only an experiment can answer those questions.
But that is another story.