microsoft / microsoft/agent-host-protocol
`ToolDefinition` has no way for a client to scope a tool away from tool-spawned chats
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 344
- Forks
- 122
- Avg merge
- 14h 12m
- Merged PRs (30d)
- 22
Description
A client contributes tools to a session via SessionActiveClient.tools. Once contributed, a tool is available in every chat of that session — including chats the host creates with ChatOrigin.Tool for sub-agent / worker delegation.
The protocol already models the agent side of tool scoping. AgentCustomization.tools is documented as "Allowlist of tool names the agent is scoped to… A non-empty list restricts the agent to exactly those tools." There is no tool side: a client cannot say where its own tool may be invoked.
Why this matters for client-contributed tools specifically
A client-contributed tool is executed by the client, not by the server — ToolCallClientContributor.clientId makes the identified client "responsible for executing the tool and dispatching chat/toolCallComplete with the result."
Many such tools are only meaningful in a chat the user is actually driving:
- UI-bound tools — open a picker, render a surface, focus an editor. A tool-spawned worker chat has no foreground surface to drive.
- User-authority tools — post a message, file a ticket, send mail. Firing these from an autonomously-delegated worker is the wrong default.
The vocabulary for the distinction already exists: ChatOrigin separates user-driven chats (user, fork, sideChat) from tool-spawned ones (tool).
Proposal
An optional field on ToolDefinition:
/** Where in a session this tool may be invoked. Absent means `session`. */
availability?: ToolAvailability;
export const enum ToolAvailability {
/** Any chat in the session, including tool-spawned worker chats. */
Session = 'session',
/** Only chats the user drives directly — not chats with a `tool` origin. */
UserChats = 'userChats',
}
Semantics that make this a contract rather than a rendering hint:
- Hosts MUST NOT expose a
userChatstool to an agent running in a chat whoseoriginistool. - If such a call is produced anyway, the host MUST terminalise it itself (a
completedcall carrying a failed result) and MUST NOT set aToolCallClientContributoron it — the client was never asked to execute it, so it must not be told it is responsible for doing so. - Absence means
session, so existing producers and consumers are unaffected.
Why the origin-based workaround isn't sufficient
Without this field, the only portable option is for a client to inspect the invoking chat's origin and refuse when it isn't user. Two problems:
- It repurposes an advisory signal as an authorization boundary. The chat-channel spec says clients "MAY use the origin to render contextual UI (parent indicators, fork markers, 'spawned by tool' badges), but origin is not a hierarchy", and that ancestry "is advisory and may be incomplete."
originis also optional on bothChatStateandChatSummary, so a client must decide how to treat absence, and different hosts may reasonably differ. - It is reactive. The refusal happens after the model has already selected and called a tool it was never allowed to use — a wasted turn, an error the model may retry against, and no way to communicate that the tool is simply unavailable in that context.
A declarative field lets the constraint be enforced where the tool list is assembled, which is the only place it can be enforced without cost.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the TypeScript definitions for ToolDefinition, AgentCustomization, ChatOrigin, and ToolCallClientContributor, then trace where host tool lists are assembled for agent chats. Define the optional availability contract and verify that userChats tools are excluded or terminalised for tool-origin chats without assigning client responsibility.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100