Thanks to visit codestin.com
Credit goes to github.com

Skip to content

SEP-1300: Tool Filtering with Groups and Tags #1300

@cliffhall

Description

@cliffhall

Preamble

Title: Tool Filtering with Groups and Tags
Authors: Pat White ([email protected]), Cliff Hall ([email protected])

Abstract

One of the most frequent concerns raised by the MCP community is LLM context overload when a server has too many tools. When more than about 10 tools are presented to an LLM it can become confused, and quality of tool selection suffers. Our current protocol offers no mitigation for this problem, meanwhile some servers have grown to encompass thousands of tools.

Motivation

MCP server developers are using various methods to combat the problem such as limiting the number of tools at server startup, but that is less than optimal for remote servers that need to be up all the time and for which the available tools may change over the lifetime of connected sessions. Another approach is splitting the tool list over a number of endpoints, but that may not work for clients which are not prepared to manage many endpoints for a server.

For this reason, we feel there should be an in-protocol way to mitigate the issue which does not require a cumbersome or backward-incompatible spec change.

Specification

Overview

We propose to:

  • Introduce a new capability for filtering.
  • Add two new core primitives:
    • Group: a first-class object that defines a collection of tools. Includes a name, title, and description. Groups are for separating the tool list by functional area or use case.
    • Tag: a lightweight, user-defined label that may be attached to any number of tools. Includes a name and description. A particular tag may appear on tools across a number of groups. Tags are for cross-cutting concerns, such as whether a tool is destructive.
  • Extend the existing tools/list RPC method, with a new filter parameter, in a fully backwards compatible way, enabling clients to narrow the response by requesting only tools that match a specific set of groups and tags.

With filtering capabilities, the client / agent can select which subsets of the tool list to interact with based on current context. After fetching the group and tag lists in order to have full description of each for reference and presentation to LLM and/or user, dynamic filtering of tools can be done in two ways:

  • Client-side filtering of tools: Agent fetches all the tools with no filtering, organizes them by groups and tags within the host application, then provides the appropriate tools to the LLM when needed via whatever means, e.g., semantic search.
  • Server-side filtering of tools: Agent presents a list of groups to the LLM. When the LLM decides it needs a tool but doesn't have an appropriate one in its context, it may request the list of tools in a particular group or set of groups.

In either case, the groups and tags may also be presented to the user for selection. For instance, the user could choose not to allow the use of tools tagged "experimental" or "destructive" or in the group "user" or "admin".

Note: Broader filtering capabilities such as boolean logic operators and applicability of filtering to other lists such as resources and prompts, will be assessed in a future SEP. This proposal is meant to focus narrowly on reducing the tool list dynamically to avoid the pressing issue of overloading the LLM's context, while allowing all tools to be available all the time.

New Capability: filtering

Servers that support filtering MUST declare the filtering capability during initialization, including whether list change notifications are supported. Group and tag lists can change at runtime, and so support for listChanged notifications for each is included.

{
  "capabilities": {
    "filtering": {
      "groups": {
        "listChanged": true
      },
      "tags": {
        "listChanged": true
      }
    }
  }
}

New Primitive: group

A Group is a named collection of one or more tools. The primary intent of groups is to separate the server's toolspace by functionality or use case.

Note: When grouping tools by functionality, a tool of should only appear in one group. However, if tools are grouped by use case, a tool might appear in multiple groups. For example, a spell_check tool might appear in both compose_email and compose_document groups. Agents should be aware of this when managing the LLM's context so as not to present the same tool more than once.

Discovery method: groups/list

Request:
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "groups/list"
}
Response:
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "groups": [
      {
        "name": "user",
        "title": "User Management Tools",
        "description": "Tools used for managing user accounts within the system."
      },
      {
        "name": "mapping",
        "title": "Geospatial Mapping Tools",
        "description": "Tools used for map rendering, geocoding, and spatial analysis."
      }
    ]
  }
}

Use Cases for Groups

  • Discovery: Client UIs can display groups of tools and selectively load only desired tools into LLM context - "Geospatial Mapping Tools" as a category
  • Access control: Access could be granted at the group level, creating a consistent abstraction from security design to RPC layer
  • Use Case: A productivity server could expose use case based groups, such as Email or Calendar, and present related tools, e.g. Email: ["Draft Email", "Spell Check"], Calendar: ["Find Open Time", "Create Appointment"]
  • Bulk operations: enable, disable, hide, or version all tools in a group

New Primitive: tag

A Tag is a free-form label that can be attached to any tool—similar to Git labels or Kubernetes tags, and appear as part of a tool's definition. In contrast to groups which are intended for functional separation of the toolspace, tags are primarily used to denote cross-cutting concerns such as status (e.g., 'stable') or operational safety (.e.g, 'destructive').

Discovery method: tags/list

Request:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tags/list"
}

Response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tags": [
      {
        "name": "beta",
        "description": "Experimental or in-testing tools"
      },
      {
        "name": "stable",
        "description": "Production-ready tools."
      }
    ]
  }
}

Use Cases for Tags

  • Ad hoc filtering: server could allow end-users to "tag" favorites (e.g. "my-top-tools").
  • Lifecycle: mark tools as "deprecated", "stable", or "experimental."
  • Integration: CI pipelines can select all "release-candidate" tools for smoke testing.

New tools/list Parameter: filter

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "cursor": "...",
    "filter": {
      "groups": ["pull-requests", "issues"],
      "tags": ["stable", "non-destructive"]
    }
  }
}

Arguments:

  • groups (string array): Only return tools belonging to ANY of these named groups.
  • tags (string array): Of the tools in the specified groups (or of all tools, if no groups were specified), only return tools tagged with ALL of these tags.

Fully backwards compatible - If filter is omitted, behavior is unchanged: all tools are returned (subject to pagination as usual).

Changes to Response Format

Example tool definition from tools/list response with groups and tags:

{
  "name": "arithmetic_calculator",
  "title": "Arithmetic Calculator",
  "description": "Perform mathematical calculations",
  "inputSchema": {
    "type": "object",
    "properties": {
      "expression": {
        "type": "string",
        "description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4')"
      }
    },
    "required": ["expression"]
  },
  "groups": ["arithmetic"],
  "tags": ["stable", "non-destructive"]
}

Filter Combinations

By mixing the filter parameter with these primitives, clients can express powerful queries. Assuming the client has asked the server for the available groups and tags, let's explore some use cases.

Simple narrowing of tool list by tag

The client is a dev-ops app, and wishes to work with internal management tools, so it fetches all tools tagged "internal". Access to these tools could require special authentication and would not be contained in a list returned to unauthenticated users not in a particular access control group.

{ "filter": { "tags": ["internal"] } }

Simple narrowing of tool list by group

The client currently wants to work with pull requests and issues, so it requests a list of all tools in the "pull_requests", "issues" groups.

{ "filter": { "groups": ["pull_requests", "issues"] } }

Narrowing of tool list by group, further filtered by tag

The client currently wants to work with pull requests and issues, but there are beta/experimental tools available which it would like to avoid. So it requests a list of all tools in the "pull_requests", "issues" groups that are tagged "stable".

{ 
  "filter": { 
    "groups": ["pull_requests", "issues"], 
    "tags": ["stable"] 
  } 
}

Rationale

We have proposed top level groups and tags properties for tool definitions. An alternative would be to make them annotations. This would just require pushing them down one level into an annotations object on the tool definition.

There have been suggestions that groups and tags are the same thing and therefore only one primitive should be considered. When we began discussing this proposal, we too, felt that they could possibly collapse into a single primitive. Further thought led us to believe that tags are sufficiently different from groups to merit inclusion.

The benefit of grouping is obvious; segment a large number of tools into smaller sets by similar functionality or use case. But tags may apply across many groups. The example of the 'destructive' tag is most clear. If a client does not have 'brave' or 'yolo' mode on, it should not request destructive tools, which may appear in all groups.

Alternatively, for communicating the destructiveness of a tool (only one example of a tag), a model hint might be used, but it would not be a way to narrow the tool list, which is the ultimate focus of this proposal.

Backward Compatibility

The proposed changes are fully backward compatible.

Reference Implementation

  • Schema and docs are updated in this draft PR.
  • A full technical implementation has been added as added as a draft PR in the Typescript SDK. It includes the necessary SDK changes, unit tests, integration tests, and client/server examples.

Server Example

Image

Client Example

Image

Security Implications

No security issues have been identified.

Future Discussion

Our focus with this proposal is on adding a basic tool filtering capability with groups and tags as a way of mitigating the tool overload problem. There were some good ideas that we considered including, but are shelving for the sake of simplicity. Should this proposal be accepted, we would consider them in the future.

  • Partial Name Matching - e.g., name_contains or name_begins_with
  • Filtering by Annotations - audience, priority, last modified, etc.
  • Logical expressions - AND, OR, NOT, greater than, less than, include, exclude, etc.
  • Resources and Prompts - adding filter parameter to their list RPCs
  • Hierarchical Groups - Groups within groups has often come up in discussions

Metadata

Metadata

Assignees

Labels

Projects

Status

Draft

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions