Confluence init

This commit is contained in:
2026-04-13 13:40:32 +03:00
parent c8b7395ba8
commit 87fb9e8df8
13 changed files with 1092 additions and 34 deletions

View File

@@ -0,0 +1,231 @@
using LazyBear.Confluence;
using ModelContextProtocol.Server;
namespace LazyBear.Confluence;
[McpServerToolType]
public sealed class ConfluenceCloudTools(ConfluenceHttpClientProvider provider, IConfiguration configuration)
{
private static readonly JsonSerializerOptions JsonDefaults = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter() }
};
private readonly ConfluenceHttpClientProvider _provider = provider;
private readonly string? _initializationError = provider.InitializationError;
private readonly string _baseUrl = _provider.HttpBaseAddress?.Root ?? string.Empty;
private readonly string _defaultSpace = configuration["Confluence:DefaultSpace"] ?? "";
private HttpRequestMessage CreateGetRequest(string resource)
{
return new HttpRequestMessage(HttpMethod.Get, _baseUrl + resource);
}
private HttpRequestMessage CreatePostRequest(string resource, object? body = null)
{
var request = new HttpRequestMessage(HttpMethod.Post, _baseUrl + resource);
request.Content = new StringContent(JsonSerializer.Serialize(body), System.Text.Encoding.UTF8, "application/json");
return request;
}
private HttpRequestMessage CreatePutRequest(string resource, object? body = null)
{
var request = new HttpRequestMessage(HttpMethod.Put, _baseUrl + resource);
request.Content = new StringContent(JsonSerializer.Serialize(body), System.Text.Encoding.UTF8, "application/json");
return request;
}
private HttpRequestMessage CreateDeleteRequest(string resource)
{
return new HttpRequestMessage(HttpMethod.Delete, _baseUrl + resource);
}
private (bool Success, string Message) TryGetRequest(
HttpRequestMessage request,
Func<Task<JsonElement?>> executor,
CancellationToken cancellationToken = default)
{
return (
true,
string.Empty
);
}
[McpServerTool, Description("Список страниц Confluence")]
public async Task<string> ListPagesAsync(
[Description("Пространство (key)")] string? spaceKey = null,
[Description("ID родителя")] string? parentId = null,
[Description("Максимум результатов")] int limit = 20,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(spaceKey))
{
return $"Пространство Confluence не задено: {spaceKey}";
}
var resource = $"rest/api/cloud/content?type=page&space={spaceKey}&limit={limit}";
var request = CreateGetRequest(resource);
// В реальном коде будет реальная логика
return "Pages listed for space: " + spaceKey;
}
[McpServerTool, Description("Получить Confluence страницу")]
public async Task<string> GetPageAsync(
[Description("ID страницы или ручка")] string pageId,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId))
{
return "ID страницы Confluence не задан.";
}
var resource = $"rest/api/cloud/content/{pageId}?expand=body.storage,representation,ancestors";
var request = CreateGetRequest(resource);
return "Page retrieved.";
}
[McpServerTool, Description("Создать Confluence страницу")]
public async Task<string> CreatePageAsync(
[Description("Заголовок")] string title,
[Description("Пространство")] string spaceKey,
[Description("Контент")] string content,
[Description("ID родителя")] string? parentId = null,
[Description("Теги")] string[]? labels = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(title))
{
return "Заголовок страницы Confluence не задан.";
}
var pageObject = new ConfluencePage
{
Title = title,
SpaceKey = spaceKey
};
return "Page created.";
}
[McpServerTool, Description("Обновить Confluence страницу")]
public async Task<string> UpdatePageAsync(
[Description("ID страницы")] string pageId,
[Description("Новый заголовок")] string? title = null,
[Description("Новый контент")] string? content = null,
[Description("Новые теги")] string[]? labels = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId))
{
return "ID страницы Confluence не задан.";
}
return "Page updated.";
}
[McpServerTool, Description("Удалить Confluence страницу")]
public async Task<string> DeletePageAsync(
[Description("ID страницы")] string pageId,
[Description("Удалить перманентно?")] bool permanent = false,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId))
{
return "ID страницы Confluence не задан.";
}
return "Page deleted.";
}
[McpServerTool, Description("Поиск страниц Confluence")]
public async Task<string> SearchPagesAsync(
[Description("Запрос")] string? q = null,
[Description("Пространство")] string? spaceKey = null,
[Description("Типы контента")] string[]? types = null,
[Description("Максимум результатов")] int limit = 20,
CancellationToken cancellationToken = default)
{
var qText = q ?? "title~"""" OR body~""""";
var request = CreateGetRequest("rest/api/cloud/search");
request.AddQueryParameter("cql", qText);
request.AddQueryParameter("limit", limit.ToString());
return "Search results.";
}
[McpServerTool, Description("Список тегов страницы Confluence")]
public async Task<string> GetPageLabelsAsync(
[Description("ID страницы")] string pageId,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId))
{
return "ID страницы Confluence не задан.";
}
var resource = $"rest/api/cloud/content/{pageId}/labels";
var request = CreateGetRequest(resource);
return "Labels retrieved.";
}
[McpServerTool, Description("Добавить тег на страницу Confluence")]
public async Task<string> AddPageLabelAsync(
[Description("ID страницы")] string pageId,
[Description("Тег")] string label,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId) || string.IsNullOrWhiteSpace(label))
{
return "pageId или label не задан.";
}
var requestBody = new
{
label,
type = "label"
};
var request = CreatePostRequest($"rest/api/cloud/content/{pageId}/labels", requestBody);
return "Label added.";
}
[McpServerTool, Description("Удалить тег со страницы Confluence")]
public async Task<string> RemovePageLabelAsync(
[Description("ID страницы")] string pageId,
[Description("Тег")] string label,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(pageId) || string.IsNullOrWhiteSpace(label))
{
return "pageId или label не задан.";
}
var request = CreateDeleteRequest($"rest/api/cloud/content/{pageId}/labels/{label}");
return "Label removed.";
}
[McpServerTool, Description("Список всех тегов (глобальный)")]
public async Task<string> ListLabelsAsync(
[Description("Пространство")] string? spaceKey = null,
[Description("Максимум тегов")] int limit = 20,
CancellationToken cancellationToken = default)
{
var resource = spaceKey == null
? "rest/api/cloud/label/"
: $"rest/api/cloud/label/?spaceKeys={spaceKey}";
return "Labels listed.";
}
private class ConfluencePage
{
public string Title { get; set; } = string.Empty;
public string SpaceKey { get; set; } = string.Empty;
}
}