Tool integration path is not on the wire, so a policy cannot distinguish a built-in from a third-party MCP server #151
rocklambros
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
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.Stating the narrow version up front so this is not read as something it is not. This is not about what a tool does.
capabilityalready answers that, with the right vocabulary: its description givesfilesystem.delete,network.egress,process.execute. A policy that wants to deny shell execution has a field for it. The remaining problem there is thatcapabilityis optional, which is a floor question for #132 rather than a new field, and it should not be reopened here.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,capabilityandarguments. 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 it has to be on the wire. A policy that says "treat tools from third-party MCP servers as untrusted" has to match on something. Today the only discriminator is a naming convention, since harnesses tend to prefix MCP tools with a server identifier. A convention is not a contract, and a harness can change its prefix format in a point release and break every policy written against it without touching a 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 also 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 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, on the order ofbuiltin,connector,mcp,shell,file. The value is a fact about dispatch rather than a trust judgment, which keeps it deterministic and keeps trust classification where §7.1 already puts it, in Guardian policy against local rules.Alternatives considered. Inferring origin from a name prefix, which is the informal status quo and cannot be validated. Overloading
tool.provider, which cannot express "anything arriving over MCP" because provider values are open strings and every new server adds one. Requiringcapabilityinstead, which is the better first move for shell execution specifically and does not solve this, because capability describes the effect and two different integration paths produce the same effect. Riding the AgBOM, which answers what the agent is capable of using rather than what this call is, and is an ACS-Inspect 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 a richer, slower change than this one.All reactions