using System.Net;
using System.Text;
using ModelContextProtocol.Client;
using RackPeek.Mcp.Tools;
namespace Tests.Mcp;
///
/// /mcp sits behind the same X-Api-Key gate as /api/inventory: 503 until the
/// server has a key configured (MCP is off by default), 401 on a wrong key.
/// The raw-HTTP tests pin the status codes; the client-level tests prove the
/// gate actually stops an MCP session, not just a request.
///
public class AuthTests {
private const string _initializeBody =
"""
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}
""";
private static HttpRequestMessage InitializeRequest() {
var request = new HttpRequestMessage(HttpMethod.Post, "/mcp") {
Content = new StringContent(_initializeBody, Encoding.UTF8, "application/json")
};
request.Headers.Add("Accept", "application/json, text/event-stream");
return request;
}
[Fact]
public async Task Without_a_configured_key_the_endpoint_answers_503_and_stays_shut() {
using var api = new McpFixture(extraConfig: new Dictionary {
["RPK_API_KEY"] = null
});
using HttpClient client = api.CreateHttpClient(apiKey: null);
using HttpResponseMessage response = await client.SendAsync(InitializeRequest());
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}
[Fact]
public async Task A_missing_key_is_rejected_with_401() {
using var api = new McpFixture();
using HttpClient client = api.CreateHttpClient(apiKey: null);
using HttpResponseMessage response = await client.SendAsync(InitializeRequest());
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task A_wrong_key_is_rejected_with_401() {
using var api = new McpFixture();
using HttpClient client = api.CreateHttpClient("not-the-key");
using HttpResponseMessage response = await client.SendAsync(InitializeRequest());
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task An_mcp_client_without_the_key_cannot_even_finish_the_handshake() {
using var api = new McpFixture();
await Assert.ThrowsAnyAsync(() => api.ConnectAsync(apiKey: null));
}
[Fact]
public async Task The_right_key_opens_the_full_tool_surface() {
using var api = new McpFixture();
await using McpClient client = await api.ConnectAsync();
ResourceList resources = await client.CallOkAsync("list_resources");
Assert.Equal(0, resources.Count);
}
}