using ModelContextProtocol.Utils; using System.Collections; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; namespace ModelContextProtocol.Server; /// Provides a thread-safe collection of instances, indexed by their names. public class McpServerToolCollection : ICollection, IReadOnlyCollection { /// Concurrent dictionary of tools, indexed by their names. private readonly ConcurrentDictionary _tools = []; /// /// Initializes a new instance of the class. /// public McpServerToolCollection() { } /// Occurs when the collection is changed. /// /// By default, this is raised when a tool is added or removed. However, a derived implementation /// may raise this event for other reasons, such as when a tool is modified. /// public event EventHandler? Changed; /// Gets the number of tools in the collection. public int Count => _tools.Count; /// Gets whether there are any tools in the collection. public bool IsEmpty => _tools.IsEmpty; /// Raises if there are registered handlers. protected void RaiseChanged() => Changed?.Invoke(this, EventArgs.Empty); /// Gets the with the specified from the collection. /// The name of the tool to retrieve. /// The with the specified name. /// is . /// A tool with the specified name does not exist in the collection. public McpServerTool this[string name] { get { Throw.IfNull(name); return _tools[name]; } } /// Clears all tools from the collection. public virtual void Clear() { _tools.Clear(); RaiseChanged(); } /// Adds the specified to the collection. /// The tool to be added. /// is . /// A tool with the same name as already exists in the collection. public void Add(McpServerTool tool) { if (!TryAdd(tool)) { throw new ArgumentException($"A tool with the same name '{tool.ProtocolTool.Name}' already exists in the collection.", nameof(tool)); } } /// Adds the specified to the collection. /// The tool to be added. /// if the tool was added; otherwise, . /// is . public virtual bool TryAdd(McpServerTool tool) { Throw.IfNull(tool); bool added = _tools.TryAdd(tool.ProtocolTool.Name, tool); if (added) { RaiseChanged(); } return added; } /// Removes the specified toolfrom the collection. /// The tool to be removed from the collection. /// /// if the tool was found in the collection and removed; otherwise, if it couldn't be found. /// /// is . public virtual bool Remove(McpServerTool tool) { Throw.IfNull(tool); bool removed = ((ICollection>)_tools).Remove(new(tool.ProtocolTool.Name, tool)); if (removed) { RaiseChanged(); } return removed; } /// Attempts to get the tool with the specified name from the collection. /// The name of the tool to retrieve. /// The tool, if found; otherwise, . /// /// if the tool was found in the collection and return; otherwise, if it couldn't be found. /// /// is . public virtual bool TryGetTool(string name, [NotNullWhen(true)] out McpServerTool? tool) { Throw.IfNull(name); return _tools.TryGetValue(name, out tool); } /// Checks if a specific tool is present in the collection of tools. /// The tool to search for in the collection. /// if the tool was found in the collection and return; otherwise, if it couldn't be found. /// is . public virtual bool Contains(McpServerTool tool) { Throw.IfNull(tool); return ((ICollection>)_tools).Contains(new(tool.ProtocolTool.Name, tool)); } /// Gets the names of all of the tools in the collection. public virtual ICollection ToolNames => _tools.Keys; /// Creates an array containing all of the tools in the collection. /// An array containing all of the tools in the collection. public virtual McpServerTool[] ToArray() => _tools.Values.ToArray(); /// public virtual void CopyTo(McpServerTool[] array, int arrayIndex) { Throw.IfNull(array); foreach (var entry in _tools) { array[arrayIndex++] = entry.Value; } } /// public virtual IEnumerator GetEnumerator() { foreach (var entry in _tools) { yield return entry.Value; } } /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// bool ICollection.IsReadOnly => false; }