Skip to content

Commit c9bf4db

Browse files
theletterfclaudecursoragent
authored
Add mcp subcommand to docs-builder CLI (#2687)
* Add `mcp` subcommand to docs-builder CLI The MCP server was a separate project (Elastic.Documentation.Mcp) but docs-builder had no `mcp` command, so `docs-builder mcp` crashed and wrote colored output to stdout, breaking the MCP JSON-RPC protocol. This adds an early intercept in Program.cs that boots the MCP server over stdio before ConsoleAppFramework initializes, keeping stdout clean for JSON-RPC. The MCP tool definitions (LinkTools, Responses) are shared via linked files to avoid duplication. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Add CLI documentation for `mcp` command Adds docs/cli/mcp.md with usage and links to the MCP server documentation. Updates the CLI index to include the new MCP section and adds a cross-link from the MCP docs back to the CLI reference. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Refactor `mcp` as a proper ConsoleAppFramework command Replace the early-intercept approach with a standard ConsoleAppFramework command registration. This integrates the MCP server into the existing CLI pipeline instead of bypassing it. Key changes: - Add IsMcp flag to GlobalCliArgs, detected during arg parsing. - Redirect all logging to stderr in MCP mode via LogToStandardErrorThreshold. - Skip heavy config registration (versions, products, search) in MCP mode. - Return no-op diagnostics collector in MCP mode (same pattern as help/version). - Update InfoLoggerFilter and CheckForUpdatesFilter to skip in MCP mode. - Replace McpHost with McpCommand registered via app.Add<McpCommand>("mcp"). Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Remove console logger in MCP mode instead of redirecting to stderr Register all common services normally and simply omit the console logging provider when IsMcp is true, keeping the logging pipeline open for OpenTelemetry and other providers. Silence ConsoleApp.* static log delegates via no-ops in ReplaceLogFilter. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Rename `isMcp` parameter to `noConsole` in logging setup The parameter describes behavior (suppress console logging), not the caller. Uses named argument at call sites for clarity. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Move MCP tool types from standalone project to assembler Move `LinkTools` and `Responses` into `Elastic.Documentation.Assembler.Mcp` so both docs-builder and the standalone MCP server consume them from a single source via the existing assembler project reference. This removes the linked files and explicit `ModelContextProtocol` package from docs-builder.csproj. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Fix imports ordering in McpCommand.cs Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent b910d18 commit c9bf4db

16 files changed

Lines changed: 106 additions & 18 deletions

File tree

docs/_docset.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ toc:
125125
- folder: cli
126126
children:
127127
- file: index.md
128+
- file: mcp.md
128129
- folder: docset
129130
children:
130131
- file: index.md

docs/cli/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ These commands can be roughly grouped into four main categories
1111
- [Link commands](#link-commands)
1212
- [Assembler commands](#assembler-commands)
1313
- [Changelog commands](#changelog-commands)
14+
- [MCP command](#mcp-command)
1415

1516
### Global options
1617

@@ -52,3 +53,9 @@ Assembler builds bring together all isolated documentation set builds and turn t
5253
Commands that pertain to creating and publishing product release documentation.
5354

5455
[See available CLI commands for release docs](release/index.md)
56+
57+
## MCP command
58+
59+
Starts an [MCP (Model Context Protocol)](../mcp/index.md) server that allows AI assistants to interact with documentation tooling directly.
60+
61+
[See the `mcp` command reference](mcp.md)

docs/cli/mcp.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# mcp
2+
3+
Starts an [MCP (Model Context Protocol)](../mcp/index.md) server over stdio, allowing AI assistants to interact with documentation tooling directly.
4+
5+
The MCP server communicates using JSON-RPC over stdin/stdout. All logging is directed to stderr to keep the protocol channel clean.
6+
7+
## Usage
8+
9+
```
10+
{{dbuild}} mcp [-h|--help] [--version]
11+
```
12+
13+
## Available tools
14+
15+
For a full list of available tools and IDE configuration instructions, see the [MCP server documentation](../mcp/index.md).
16+
17+
## Example
18+
19+
Test the MCP server using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
20+
21+
```bash
22+
{{dbuild}} mcp
23+
```

docs/mcp/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ The MCP server currently exposes the following tools:
1616
| `FindCrossLinks` | Finds all cross-links between repositories. Can filter by source or target repository. |
1717
| `ValidateCrossLinks` | Validates cross-links to a repository and reports any broken links. |
1818

19+
The MCP server is started using the [`{{dbuild}} mcp`](../cli/mcp.md) command.
20+
1921
## Configuration
2022

2123
To use the {{dbuild}} MCP server, add it to your IDE's MCP configuration.

src/Elastic.Documentation.Mcp/Elastic.Documentation.Mcp.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="ModelContextProtocol" />
109
<PackageReference Include="Microsoft.Extensions.Hosting" />
1110
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
1211
</ItemGroup>

src/Elastic.Documentation.Mcp/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information
44

55
using Elastic.Documentation.Assembler.Links;
6+
using Elastic.Documentation.Assembler.Mcp;
67
using Elastic.Documentation.LinkIndex;
78
using Elastic.Documentation.Links.InboundLinks;
89
using Microsoft.Extensions.DependencyInjection;
@@ -20,6 +21,6 @@
2021
builder.Services
2122
.AddMcpServer()
2223
.WithStdioServerTransport()
23-
.WithToolsFromAssembly();
24+
.WithTools<LinkTools>();
2425

2526
await builder.Build().RunAsync();

src/Elastic.Documentation.ServiceDefaults/AppDefaultsExtensions.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static TBuilder AddDocumentationServiceDefaults<TBuilder>(this TBuilder b
2929
GlobalCli.Process(ref args, out var globalArgs);
3030

3131
var services = builder.Services;
32-
_ = builder.Services.AddElasticDocumentationLogging(globalArgs.LogLevel);
32+
_ = builder.Services.AddElasticDocumentationLogging(globalArgs.LogLevel, noConsole: globalArgs.IsMcp);
3333
_ = services
3434
.AddConfigurationFileProvider(globalArgs.SkipPrivateRepositories, globalArgs.ConfigurationSource, (s, p) =>
3535
{
@@ -42,21 +42,24 @@ public static TBuilder AddDocumentationServiceDefaults<TBuilder>(this TBuilder b
4242
_ = s.AddSingleton(search);
4343
configure?.Invoke(s, p);
4444
});
45-
_ = builder.Services.AddElasticDocumentationLogging(globalArgs.LogLevel);
45+
_ = builder.Services.AddElasticDocumentationLogging(globalArgs.LogLevel, noConsole: globalArgs.IsMcp);
4646
_ = services.AddSingleton(globalArgs);
4747

4848
return builder.AddServiceDefaults();
4949
}
5050

51-
public static TServiceCollection AddElasticDocumentationLogging<TServiceCollection>(this TServiceCollection services, LogLevel logLevel)
51+
public static TServiceCollection AddElasticDocumentationLogging<TServiceCollection>(this TServiceCollection services, LogLevel logLevel, bool noConsole = false)
5252
where TServiceCollection : IServiceCollection
5353
{
54-
services.TryAddEnumerable(ServiceDescriptor.Singleton<ConsoleFormatter, CondensedConsoleFormatter>());
55-
_ = services.AddLogging(x => x
56-
.ClearProviders()
57-
.SetMinimumLevel(logLevel)
58-
.AddConsole(c => c.FormatterName = "condensed")
59-
);
54+
_ = services.AddLogging(x =>
55+
{
56+
_ = x.ClearProviders().SetMinimumLevel(logLevel);
57+
if (!noConsole)
58+
{
59+
services.TryAddEnumerable(ServiceDescriptor.Singleton<ConsoleFormatter, CondensedConsoleFormatter>());
60+
_ = x.AddConsole(c => c.FormatterName = "condensed");
61+
}
62+
});
6063
return services;
6164
}
6265

src/Elastic.Documentation/GlobalCommandLine.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public record GlobalCliArgs
1212
public ConfigurationSource? ConfigurationSource { get; init; }
1313
public bool SkipPrivateRepositories { get; init; }
1414
public bool IsHelpOrVersion { get; init; }
15+
public bool IsMcp { get; init; }
1516
}
1617
public static class GlobalCli
1718
{
@@ -61,6 +62,9 @@ public static void Process(ref string[] args, out GlobalCliArgs cli, out string[
6162

6263
args = [.. filteredArguments];
6364
globalArguments = [.. globalArgs];
65+
66+
if (filteredArguments.Count > 0 && filteredArguments[0] == "mcp")
67+
cli = cli with { IsMcp = true };
6468
}
6569

6670
private static LogLevel GetLogLevel(string? logLevel) => logLevel switch

src/services/Elastic.Documentation.Assembler/Elastic.Documentation.Assembler.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net10.0</TargetFramework>
@@ -8,6 +8,7 @@
88

99
<ItemGroup>
1010
<PackageReference Include="GitHub.Actions.Core" />
11+
<PackageReference Include="ModelContextProtocol" />
1112
</ItemGroup>
1213

1314
<ItemGroup>

src/Elastic.Documentation.Mcp/LinkTools.cs renamed to src/services/Elastic.Documentation.Assembler/Mcp/LinkTools.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
using System.ComponentModel;
66
using System.Text.Json;
77
using Elastic.Documentation.Assembler.Links;
8-
using Elastic.Documentation.Mcp.Responses;
8+
using Elastic.Documentation.Assembler.Mcp.Responses;
99
using ModelContextProtocol.Server;
1010

11-
namespace Elastic.Documentation.Mcp;
11+
namespace Elastic.Documentation.Assembler.Mcp;
1212

1313
[McpServerToolType]
1414
public class LinkTools(ILinkUtilService linkUtilService)

0 commit comments

Comments
 (0)