Add RegionUsers tool and update README; enhance endpoint documentation

This commit is contained in:
2026-05-16 13:12:37 +02:00
parent a9b59567b7
commit 3b56aa5149
5 changed files with 107 additions and 1 deletions

View File

@@ -4,6 +4,9 @@ Use this prompt when adding a new MCP tool to this project.
---
Here is your documentation of the available endpoints (openapi)
https://beta.foodsharing.de/api/doc
You are working in the `fsmcp` workspace.
## Goal

View File

@@ -5,6 +5,7 @@ public static class Endpoints
public static string UserLogin => $"{ApiBase}/api/login";
public static string UserCurrentDetails => $"{ApiBase}/api/users/current/details";
public static string RegionStores(int regionId) => $"{ApiBase}/api/regions/{regionId}/stores";
public static string RegionUsers(int regionId) => $"{ApiBase}/api/regions/{regionId}/users";
public static string StoreMembers(int storeId) => $"{ApiBase}/api/stores/{storeId}/members";
private static string ApiBase => "https://beta.foodsharing.de";

View File

@@ -15,6 +15,7 @@ builder.Services
.WithStdioServerTransport()
.WithTools<CurrentUserTools>()
.WithTools<RegionStoresTools>()
.WithTools<StoreMembersTools>();
.WithTools<StoreMembersTools>()
.WithTools<FsMcp.Tools.RegionUsersTools>();
await builder.Build().RunAsync();

View File

@@ -122,6 +122,26 @@ Notes for consumers:
The tool is strongly typed in `Tools/StoreMembersTools.cs`, with per-field `Description` attributes so MCP clients can surface schema-aware guidance directly in tool UIs.
### Region users tool
This server also exposes `get_region_users`.
- Purpose: Returns all members of a region from `GET /api/regions/{regionId}/users`.
- Input:
- `regionId` (required, positive integer; OpenAPI path pattern: `[1-9][0-9]*`)
- Auth: Uses `USERNAME` and `PASSWORD` environment variables to log in and then sends the `X-CSRF-Token` header.
- Output: Array of typed member entries including:
- identity fields (`id`, `name`, `lastName`, `avatar`, `isSleeping`, `isAdminOrAmbassadorOfRegion`, `isVerified`, `role`)
- extra observed fields (`isHomeRegion`, `lastActivity`, `lastPassDate`)
Notes for consumers:
- `isSleeping` indicates whether the member currently uses the sleeping hat function.
- `isAdminOrAmbassadorOfRegion` indicates if the member has admin/ambassador privileges in this region.
- Some fields (`lastName`, `isHomeRegion`, `lastActivity`, `role`, `lastPassDate`, `isVerified`) are added to handle varying response payloads.
The tool is strongly typed in `Tools/RegionUsersTools.cs`, with per-field `Description` attributes so MCP clients can surface schema-aware guidance directly in tool UIs.
## Publishing to NuGet.org
1. Run `dotnet pack -c Release` to create the NuGet package

View File

@@ -0,0 +1,81 @@
using System.ComponentModel;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using FsMcp;
using ModelContextProtocol.Server;
namespace FsMcp.Tools;
internal sealed class RegionUsersTools
{
private readonly FoodsharingApiClient _apiClient;
public RegionUsersTools(FoodsharingApiClient apiClient)
{
_apiClient = apiClient;
}
[McpServerTool]
[Description("Returns a list of all members for a region. Useful for discovering users within a specific foodsharing region.")]
public async Task<IReadOnlyList<UnitMemberListItem>> GetRegionUsersAsync(
[Description("Region ID as positive integer (OpenAPI path pattern: [1-9][0-9]*).")]
int regionId)
{
if (regionId <= 0)
{
throw new ArgumentOutOfRangeException(nameof(regionId), "regionId must be a positive integer.");
}
await _apiClient.EnsureLoginAsync();
var users = await _apiClient.HttpClient.GetFromJsonAsync<IReadOnlyList<UnitMemberListItem>>(Endpoints.RegionUsers(regionId));
return users ?? [];
}
}
public sealed record UnitMemberListItem
{
[Description("Unique user ID of the member.")]
[JsonPropertyName("id")]
public int Id { get; init; }
[Description("Display name of the member.")]
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[Description("Relative API path of the member avatar image.")]
[JsonPropertyName("avatar")]
public string? Avatar { get; init; }
[Description("Whether the user is currently using the sleeping hat function.")]
[JsonPropertyName("isSleeping")]
public bool? IsSleeping { get; init; }
[Description("Whether the user is an admin or ambassador of the region.")]
[JsonPropertyName("isAdminOrAmbassadorOfRegion")]
public bool IsAdminOrAmbassadorOfRegion { get; init; }
[Description("Last name of the member (if available or returned by the API).")]
[JsonPropertyName("lastName")]
public string? LastName { get; init; }
[Description("Whether the region is the user's home region (if available).")]
[JsonPropertyName("isHomeRegion")]
public bool? IsHomeRegion { get; init; }
[Description("Last activity timestamp of the user (if available).")]
[JsonPropertyName("lastActivity")]
public DateTimeOffset? LastActivity { get; init; }
[Description("Numeric role enum from OpenAPI Role: 0, 1, 2, 3, 4, 5.")]
[JsonPropertyName("role")]
public int? Role { get; init; }
[Description("Date and time of the last generated pass, format: YYYY-MM-DD HH:mm:ss.")]
[JsonPropertyName("lastPassDate")]
public string? LastPassDate { get; init; }
[Description("Whether the member account is verified.")]
[JsonPropertyName("isVerified")]
public bool? IsVerified { get; init; }
}