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;
}