svrnty-mcp-server/samples/CodexMcpServer/Tools/ListDocumentsTool.cs
Svrnty 516e1479c6 docs: comprehensive AI coding assistant research and MCP-first implementation plan
Research conducted on modern AI coding assistants (Cursor, GitHub Copilot, Cline,
Aider, Windsurf, Replit Agent) to understand architecture patterns, context management,
code editing workflows, and tool use protocols.

Key Decision: Pivoted from building full CLI (40-50h) to validation-driven MCP-first
approach (10-15h). Build 5 core CODEX MCP tools that work with ANY coding assistant,
validate adoption over 2-4 weeks, then decide on full CLI if demand proven.

Files:
- research/ai-systems/modern-coding-assistants-architecture.md (comprehensive research)
- research/ai-systems/codex-coding-assistant-implementation-plan.md (original CLI plan, preserved)
- research/ai-systems/codex-mcp-tools-implementation-plan.md (approved MCP-first plan)
- ideas/registry.json (updated with approved MCP tools proposal)

Architech Validation: APPROVED with pivot to MCP-first approach
Human Decision: Approved (pragmatic validation-driven development)

Next: Begin Phase 1 implementation (10-15 hours, 5 core MCP tools)

🤖 Generated with CODEX Research System

Co-Authored-By: The Archivist <archivist@codex.svrnty.io>
Co-Authored-By: The Architech <architech@codex.svrnty.io>
Co-Authored-By: Mathias Beaulieu-Duncan <mat@svrnty.io>
2025-10-22 21:00:34 -04:00

143 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using OpenHarbor.MCP.Core;
namespace CodexMcpServer.Tools;
/// <summary>
/// MCP tool for listing CODEX documents with pagination support.
/// Calls CODEX API GET /api/documents endpoint.
/// </summary>
public class ListDocumentsTool : IMcpTool
{
private readonly HttpClient _httpClient;
private static readonly JsonDocument _schema = JsonDocument.Parse("""
{
"type": "object",
"properties": {
"page": {
"type": "integer",
"description": "Page number for pagination (1-based)"
},
"pageSize": {
"type": "integer",
"description": "Number of items per page"
},
"limit": {
"type": "integer",
"description": "Maximum number of items to return"
},
"offset": {
"type": "integer",
"description": "Number of items to skip"
}
}
}
""");
public ListDocumentsTool(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
// Set base address if not already set
if (_httpClient.BaseAddress == null)
{
_httpClient.BaseAddress = new Uri("http://localhost:5050");
}
}
/// <inheritdoc/>
public string Name => "list_documents";
/// <inheritdoc/>
public string Description => "List all CODEX documents with optional pagination. Returns document summaries with metadata.";
/// <inheritdoc/>
public JsonDocument Schema => _schema;
/// <inheritdoc/>
public async Task<JsonDocument> ExecuteAsync(JsonDocument? arguments)
{
try
{
// Build query string from optional pagination parameters
var queryParams = new List<string>();
if (arguments != null)
{
var root = arguments.RootElement;
if (root.TryGetProperty("page", out var pageElement) && pageElement.ValueKind == JsonValueKind.Number)
{
queryParams.Add($"page={pageElement.GetInt32()}");
}
if (root.TryGetProperty("pageSize", out var pageSizeElement) && pageSizeElement.ValueKind == JsonValueKind.Number)
{
queryParams.Add($"pageSize={pageSizeElement.GetInt32()}");
}
if (root.TryGetProperty("limit", out var limitElement) && limitElement.ValueKind == JsonValueKind.Number)
{
queryParams.Add($"limit={limitElement.GetInt32()}");
}
if (root.TryGetProperty("offset", out var offsetElement) && offsetElement.ValueKind == JsonValueKind.Number)
{
queryParams.Add($"offset={offsetElement.GetInt32()}");
}
}
// Build final URL with query string
var url = "/api/documents";
if (queryParams.Any())
{
url += "?" + string.Join("&", queryParams);
}
// Call CODEX API
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
return CreateErrorResponse(
$"CODEX API returned error: {response.StatusCode}. {errorContent}"
);
}
// Parse and return response
var responseContent = await response.Content.ReadAsStringAsync();
try
{
return JsonDocument.Parse(responseContent);
}
catch (JsonException ex)
{
return CreateErrorResponse($"Failed to parse CODEX API response: {ex.Message}");
}
}
catch (HttpRequestException ex)
{
return CreateErrorResponse($"HTTP request failed: {ex.Message}");
}
catch (Exception ex)
{
return CreateErrorResponse($"Unexpected error: {ex.Message}");
}
}
private static JsonDocument CreateErrorResponse(string message)
{
var error = new
{
error = message
};
return JsonDocument.Parse(JsonSerializer.Serialize(error));
}
}