The problem
toolCallRequest covers a built-in function, a connector, an MCP server tool, a file operation, and a shell execution under one hook, and carries nothing that says which integration path a call arrived through.
The narrow version of this, stated up front so the issue is not read as something it is not: this is not about what a tool does. capability already answers that, with exactly the right vocabulary. Its description gives filesystem.delete, network.egress, process.execute. A policy that wants to deny shell execution has a field for it, and the remaining problem there is that capability is optional, which is a floor question for #132 rather than a new field.
What has no field is where the tool came from. A first-party built-in implemented inside the harness process and a third-party MCP server reachable over a socket can present identical name, capability, and arguments. They are not equivalent risks, and nothing distinguishes them.
tool.provider is the nearest thing and answers a different question. Provider is the identity of whoever published the tool. Integration path is how the call reaches execution, and that is what determines what an attacker who controls the tool can actually do. A compromised in-process built-in and a compromised external MCP server have different blast radii and different detection surfaces, whatever the provider string says. A trustworthy provider reached over an untrusted path is still an untrusted path.
Why the wire has to carry it
A policy that says "treat tools from third-party MCP servers as untrusted" has to match on something. Today the only available discriminator is a naming convention, since harnesses tend to prefix MCP tools with a server identifier. A naming convention is not a contract. A harness can change its prefix format in a point release and break every policy written against it, without altering a single schema.
That makes this the write-once promise in miniature. The control should be written once and hold on every harness. Today it is rewritten per harness against each one's naming habits, which is the cost ACS exists to remove.
It cannot be derived Guardian-side. The Guardian sees the tool name, the arguments, and whatever optional fields the client populated. Which dispatch path the harness used to reach the tool is known only to the harness, and is gone by the time the envelope is built.
Shape: a tool_kind discriminator over integration path, with a small closed vocabulary that stays stable as harnesses proliferate. Something on the order of builtin, connector, mcp, shell, file. The value is a fact about dispatch, not a trust judgment, which keeps it deterministic and keeps trust classification where §7.1 already puts it, in Guardian policy against local rules.
Which constituencies this affects
Alternatives considered
Infer origin from a name prefix. The informal status quo. Breaks on any harness that changes its convention, and cannot be validated.
Overload tool.provider. Answers who published the tool rather than what class of call this is. A policy keyed on provider cannot express "anything arriving over MCP", because provider values are open strings and every new server adds one.
Require capability instead. Solves a real and adjacent problem, and it is the better first move for "deny shell execution" specifically. It does not solve this one, because capability describes the effect and two different integration paths can produce the same effect. The elevation question belongs to #132, which is reshaping the ACS-Core floor, and should not be reopened here.
Ride the AgBOM. agbom/snapshot inventories tools and would be a natural place to record integration path. It answers what the agent is capable of using rather than what this call is, and it is an ACS-Inspect profile feature, so a policy depending on it would not work for an ACS-Core deployment. Related: #8 proposes trust-boundary metadata on ToolDefinition, which is adjacent and is a richer, slower change than this one.
Discussion link
#151
Current Priority Scope
Feeds the AGT interoperability benchmark
The problem
toolCallRequestcovers a built-in function, a connector, an MCP server tool, a file operation, and a shell execution under one hook, and carries nothing that says which integration path a call arrived through.The narrow version of this, stated up front so the issue is not read as something it is not: this is not about what a tool does.
capabilityalready answers that, with exactly the right vocabulary. Its description givesfilesystem.delete,network.egress,process.execute. A policy that wants to deny shell execution has a field for it, and the remaining problem there is thatcapabilityis optional, which is a floor question for #132 rather than a new field.What has no field is where the tool came from. A first-party built-in implemented inside the harness process and a third-party MCP server reachable over a socket can present identical
name,capability, andarguments. They are not equivalent risks, and nothing distinguishes them.tool.provideris the nearest thing and answers a different question. Provider is the identity of whoever published the tool. Integration path is how the call reaches execution, and that is what determines what an attacker who controls the tool can actually do. A compromised in-process built-in and a compromised external MCP server have different blast radii and different detection surfaces, whatever the provider string says. A trustworthy provider reached over an untrusted path is still an untrusted path.Why the wire has to carry it
A policy that says "treat tools from third-party MCP servers as untrusted" has to match on something. Today the only available discriminator is a naming convention, since harnesses tend to prefix MCP tools with a server identifier. A naming convention is not a contract. A harness can change its prefix format in a point release and break every policy written against it, without altering a single schema.
That makes this the write-once promise in miniature. The control should be written once and hold on every harness. Today it is rewritten per harness against each one's naming habits, which is the cost ACS exists to remove.
It cannot be derived Guardian-side. The Guardian sees the tool name, the arguments, and whatever optional fields the client populated. Which dispatch path the harness used to reach the tool is known only to the harness, and is gone by the time the envelope is built.
Shape: a
tool_kinddiscriminator over integration path, with a small closed vocabulary that stays stable as harnesses proliferate. Something on the order ofbuiltin,connector,mcp,shell,file. The value is a fact about dispatch, not a trust judgment, which keeps it deterministic and keeps trust classification where §7.1 already puts it, in Guardian policy against local rules.Which constituencies this affects
Alternatives considered
Infer origin from a name prefix. The informal status quo. Breaks on any harness that changes its convention, and cannot be validated.
Overload
tool.provider. Answers who published the tool rather than what class of call this is. A policy keyed on provider cannot express "anything arriving over MCP", because provider values are open strings and every new server adds one.Require
capabilityinstead. Solves a real and adjacent problem, and it is the better first move for "deny shell execution" specifically. It does not solve this one, because capability describes the effect and two different integration paths can produce the same effect. The elevation question belongs to #132, which is reshaping the ACS-Core floor, and should not be reopened here.Ride the AgBOM.
agbom/snapshotinventories tools and would be a natural place to record integration path. It answers what the agent is capable of using rather than what this call is, and it is an ACS-Inspect profile feature, so a policy depending on it would not work for an ACS-Core deployment. Related: #8 proposes trust-boundary metadata onToolDefinition, which is adjacent and is a richer, slower change than this one.Discussion link
#151
Current Priority Scope
Feeds the AGT interoperability benchmark