feat(mcp): give each account its own Forgejo instance #73

Merged
Claude-Run merged 1 commit from feat/FJ-55-per-account-forgejo-instances into main 2026-07-18 16:46:35 +02:00
Member

Over the HTTP transport, every tool call now acts as the authenticated account's own Forgejo instance instead of one process-wide identity, and the single-identity credential path is deleted from the serve path.

A new consumer-owned forgejo_instances table (chained onto mcp-web's generic migrations at version 1000) keys one host plus one encrypted personal access token per account, one-to-one on accounts(id) with ON DELETE CASCADE. The account-to-client seam (client_for_account / ForgejoInstances) that FJ-54 stubbed is implemented for real: it looks up the calling account's row, decrypts the token, and builds a Forgejo client from that host and token. ForgejoServer gains a ClientSource split so api() / api_and_token() resolve per request over HTTP (from the injected Principal) while stdio keeps its single identity; the ~150 tool methods thread the request context unchanged.

A new /instance UI lets an account set, test, and disconnect its instance. Saving or testing probes the Forgejo user endpoint, reports the resolved login, and records verified_at; failures distinguish a rejected token, an unreachable host, and a non-Forgejo URL without leaking the upstream body. The token is write-only and never rendered back. Every handler is scoped to the signed-in account, so no account can read or modify another's instance, and deleting an account cascades to its instance row.

On HTTP nothing degrades to unauthenticated or to a host-level identity: FORGEJO_TOKEN, the keys.json fallback, Auth::None, DEFAULT_HOST, and $FORGEJO_HOST are no longer read on the serve path, and the inert FORGEJO_MCP_HTTP_TOKEN static bearer is removed from fj mcp service install (the unit bakes in no host and no token). An account with no instance gets an error naming where to add one. fj mcp stdio still resolves FORGEJO_TOKEN, keys.json, and $FORGEJO_HOST exactly as before.

#FJ-55

Over the HTTP transport, every tool call now acts as the authenticated account's own Forgejo instance instead of one process-wide identity, and the single-identity credential path is deleted from the serve path. A new consumer-owned `forgejo_instances` table (chained onto mcp-web's generic migrations at version 1000) keys one host plus one encrypted personal access token per account, one-to-one on `accounts(id)` with `ON DELETE CASCADE`. The account-to-client seam (`client_for_account` / `ForgejoInstances`) that FJ-54 stubbed is implemented for real: it looks up the calling account's row, decrypts the token, and builds a `Forgejo` client from that host and token. `ForgejoServer` gains a `ClientSource` split so `api()` / `api_and_token()` resolve per request over HTTP (from the injected `Principal`) while stdio keeps its single identity; the ~150 tool methods thread the request context unchanged. A new `/instance` UI lets an account set, test, and disconnect its instance. Saving or testing probes the Forgejo user endpoint, reports the resolved login, and records `verified_at`; failures distinguish a rejected token, an unreachable host, and a non-Forgejo URL without leaking the upstream body. The token is write-only and never rendered back. Every handler is scoped to the signed-in account, so no account can read or modify another's instance, and deleting an account cascades to its instance row. On HTTP nothing degrades to unauthenticated or to a host-level identity: `FORGEJO_TOKEN`, the `keys.json` fallback, `Auth::None`, `DEFAULT_HOST`, and `$FORGEJO_HOST` are no longer read on the serve path, and the inert `FORGEJO_MCP_HTTP_TOKEN` static bearer is removed from `fj mcp service install` (the unit bakes in no host and no token). An account with no instance gets an error naming where to add one. `fj mcp stdio` still resolves `FORGEJO_TOKEN`, `keys.json`, and `$FORGEJO_HOST` exactly as before. #FJ-55
feat(mcp): give each account its own Forgejo instance
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 1m7s
Create release / Create release from merged PR (pull_request) Has been skipped
4261fe27d8
Over the HTTP transport, every tool call now acts as the authenticated account's own Forgejo instance instead of one process-wide identity, and the single-identity credential path is deleted from the serve path.

A new consumer-owned `forgejo_instances` table (chained onto mcp-web's generic migrations at version 1000) keys one host plus one encrypted personal access token per account, one-to-one on `accounts(id)` with `ON DELETE CASCADE`. The account-to-client seam (`client_for_account` / `ForgejoInstances`) that FJ-54 stubbed is implemented for real: it looks up the calling account's row, decrypts the token, and builds a `Forgejo` client from that host and token. `ForgejoServer` gains a `ClientSource` split so `api()` / `api_and_token()` resolve per request over HTTP (from the injected `Principal`) while stdio keeps its single identity; the ~150 tool methods thread the request context unchanged.

A new `/instance` UI lets an account set, test, and disconnect its instance. Saving or testing probes the Forgejo user endpoint, reports the resolved login, and records `verified_at`; failures distinguish a rejected token, an unreachable host, and a non-Forgejo URL without leaking the upstream body. The token is write-only and never rendered back. Every handler is scoped to the signed-in account, so no account can read or modify another's instance, and deleting an account cascades to its instance row.

On HTTP nothing degrades to unauthenticated or to a host-level identity: `FORGEJO_TOKEN`, the `keys.json` fallback, `Auth::None`, `DEFAULT_HOST`, and `$FORGEJO_HOST` are no longer read on the serve path, and the inert `FORGEJO_MCP_HTTP_TOKEN` static bearer is removed from `fj mcp service install` (the unit bakes in no host and no token). An account with no instance gets an error naming where to add one. `fj mcp stdio` still resolves `FORGEJO_TOKEN`, `keys.json`, and `$FORGEJO_HOST` exactly as before.

#FJ-55
Claude-Run deleted branch feat/FJ-55-per-account-forgejo-instances 2026-07-18 16:46:35 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pandoras-box/forgejo-cli!73
No description provided.