File: Mcp\Tools\GetDocTool.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.Text.Json;
using Aspire.Cli.Mcp.Docs;
using ModelContextProtocol.Protocol;
 
namespace Aspire.Cli.Mcp.Tools;
 
/// <summary>
/// MCP tool for retrieving a specific Aspire documentation page or section.
/// </summary>
internal sealed class GetDocTool(IDocsIndexService docsIndexService) : CliMcpTool
{
    private readonly IDocsIndexService _docsIndexService = docsIndexService;
 
    public override string Name => KnownMcpTools.GetDoc;
 
    public override string Description => """
        Retrieves the full content of a specific Aspire documentation page by its slug.
        Optionally filter to a specific section by providing a section heading.
        Use list_docs to browse available pages, or search_docs to find relevant content by keyword.
        """;
 
    public override JsonElement GetInputSchema()
    {
        return JsonDocument.Parse("""
            {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string",
                  "description": "The slug of the documentation page to retrieve (e.g., 'redis-integration', 'getting-started')."
                },
                "section": {
                  "type": "string",
                  "description": "Optional. The heading of a specific section to return. If omitted, returns the entire page."
                }
              },
              "required": ["slug"],
              "additionalProperties": false,
              "description": "Retrieves documentation content by slug, optionally filtered to a specific section."
            }
            """).RootElement;
    }
 
    public override async ValueTask<CallToolResult> CallToolAsync(
        ModelContextProtocol.Client.McpClient mcpClient,
        IReadOnlyDictionary<string, JsonElement>? arguments,
        CancellationToken cancellationToken)
    {
        _ = mcpClient;
 
        if (arguments is null || !arguments.TryGetValue("slug", out var slugElement))
        {
            return new CallToolResult
            {
                IsError = true,
                Content = [new TextContentBlock { Text = "The 'slug' parameter is required. Use list_docs to see available pages." }]
            };
        }
 
        var slug = slugElement.GetString();
        if (string.IsNullOrWhiteSpace(slug))
        {
            return new CallToolResult
            {
                IsError = true,
                Content = [new TextContentBlock { Text = "The 'slug' parameter cannot be empty." }]
            };
        }
 
        string? section = null;
        if (arguments.TryGetValue("section", out var sectionElement))
        {
            section = sectionElement.GetString();
        }
 
        var doc = await _docsIndexService.GetDocumentAsync(slug, section, cancellationToken).ConfigureAwait(false);
 
        if (doc is null)
        {
            return new CallToolResult
            {
                IsError = true,
                Content = [new TextContentBlock { Text = $"No documentation found for slug '{slug}'. Use list_docs to see available pages." }]
            };
        }
 
        return new CallToolResult
        {
            Content = [new TextContentBlock { Text = doc.Content }]
        };
    }
}