File: Mcp\Tools\ListDocsTool.cs
Web Access
Project: src\src\Aspire.Cli\Aspire.Cli.Tool.csproj (aspire)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using System.Text;
using System.Text.Json;
using Aspire.Cli.Mcp.Docs;
using ModelContextProtocol.Protocol;
 
namespace Aspire.Cli.Mcp.Tools;
 
/// <summary>
/// MCP tool for listing available Aspire documentation pages.
/// </summary>
internal sealed class ListDocsTool(IDocsIndexService docsIndexService) : CliMcpTool
{
    private readonly IDocsIndexService _docsIndexService = docsIndexService;
 
    public override string Name => KnownMcpTools.ListDocs;
 
    public override string Description => """
        Lists all available Aspire documentation pages from aspire.dev.
        Returns page titles, URL slugs, and brief summaries.
        Use this to browse the documentation catalog and discover available topics.
        Pass a slug to the get_doc tool to retrieve full page content.
        """;
 
    public override JsonElement GetInputSchema()
    {
        return JsonDocument.Parse("""
            {
              "type": "object",
              "properties": {},
              "required": [],
              "additionalProperties": false,
              "description": "Lists all available Aspire documentation pages. No parameters required."
            }
            """).RootElement;
    }
 
    public override async ValueTask<CallToolResult> CallToolAsync(
        ModelContextProtocol.Client.McpClient mcpClient,
        IReadOnlyDictionary<string, JsonElement>? arguments,
        CancellationToken cancellationToken)
    {
        _ = mcpClient;
        _ = arguments;
 
        var docs = await _docsIndexService.ListDocumentsAsync(cancellationToken).ConfigureAwait(false);
 
        if (docs.Count is 0)
        {
            return new CallToolResult
            {
                Content = [new TextContentBlock { Text = "No documentation available. The aspire.dev docs may not have loaded correctly." }]
            };
        }
 
        var sb = new StringBuilder();
        sb.AppendLine("# Aspire Documentation Pages");
        sb.AppendLine();
        sb.AppendLine(CultureInfo.InvariantCulture, $"Found {docs.Count} documentation pages:");
        sb.AppendLine();
 
        foreach (var doc in docs)
        {
            sb.AppendLine(CultureInfo.InvariantCulture, $"## {doc.Title}");
            sb.AppendLine(CultureInfo.InvariantCulture, $"**Slug:** `{doc.Slug}`");
            if (!string.IsNullOrEmpty(doc.Summary))
            {
                sb.AppendLine(CultureInfo.InvariantCulture, $"> {doc.Summary}");
            }
            sb.AppendLine();
        }
 
        sb.AppendLine("---");
        sb.AppendLine("Use `get_doc` with a slug to retrieve the full content of a specific page.");
 
        return new CallToolResult
        {
            Content = [new TextContentBlock { Text = sb.ToString() }]
        };
    }
}