Replace strings.Split with the lazy strings.SplitSeq iterator (Go 1.23+)
in loops that only range over the tokens, avoiding the intermediate
slice allocation. The yielded substrings are identical to Split, so
behavior is unchanged. Applies the suggestion from #5599 to its three
sites (CIDR parsing, WebDAV hidden-path, overlay path checks) and
extends it to two more split-and-iterate loops in the server compression
negotiator and MCP config-options builder for consistency. The slice
returning splitPath helper is intentionally left on strings.Split.
- Rework CliFlag.Default() to read the documented default through
cli.DocGenerationFlag.GetDefaultText() instead of GetValue(); urfave
snapshots the source-code default in Apply() before reading the
environment, so reports stay stable across deployments and no longer
echo operator-supplied env values for runtime-mutated string flags.
- Add a Secret annotation on CliFlag for sensitive options. When set,
Default() collapses to DocDefault (or "") so secrets like
admin-password, oidc-secret, database-password, auth-secret,
node-client-secret, join-token, download-token, preview-token, and
vision-key never appear in `photoprism show config-options` or
downstream consumers of the same report data.
- Convert index-workers from IntFlag to StringFlag with the new
IndexWorkersAuto = "auto" sentinel, matching the convention already
used by thumb-color, thumb-filter, and database-driver. Options.
IndexWorkers becomes a string; Config.IndexWorkers() parses it once
and keeps the existing CPU/SQLite caps. yaml.v2 silently coerces the
legacy `IndexWorkers: 4` form into the string field, so existing
operator config files load unchanged. Drops the dynamic
cpuid.CPU.PhysicalCores/2 default and the previous DocDefault hack.
Regenerated swagger.json picks up the new string type.
- Harden the Markdown report renderer (pkg/txt/report/markdown.go) by
backslash-escaping `<` and `>` in row and header cells alongside the
existing `|` and `* * *` escapes. Prevents arbitrary HTML from being
emitted into downstream HTML pipelines that render the table source.
- Fix two pre-existing lint findings surfaced by the newer
golangci-lint: misspell `marshalling` -> `marshaling` and replace a
field-by-field struct literal with a same-shape type conversion
(staticcheck S1016).
- Add coverage for every new code path: Default() Secret/env-override
regression, GetDefaultText/strconv.Unquote round-trip, parseIndexWorkers
branch matrix, ApplyCliContext index-workers string binding, the YAML
round-trip across `auto`/quoted/bare-int/empty forms, and the Markdown
angle-bracket escape.
Sweeps top-level CODEMAP/GLOSSARY, package READMEs under internal/,
and a handful of source-comment references that linked to the private
specs/ subrepo. AGENTS.md hints stay (agent-instruction document) and
the agent-skill linking targets in Makefile are guarded with
directory checks.
- Rewrite package doc, struct comments, log line, and route-registration
comment so they describe the MCP server as a first-class feature
rather than a pre-release prototype. The "Usage" strings on
MCPCommands / MCPServeCommand were updated separately and stay
unchanged.
- Drop "in this prototype" from the edition-advisory warning emitted by
list_config_keys; the message now reads "edition filtering is
advisory; results come from the current <edition> build metadata".
- Rewrite internal/mcp/README.md: new "Scope" section with
in-scope/out-of-scope invariants, corrected authorization summary
(admin + API client roles + manager in Pro/Portal, anonymous in
public mode for the registered read-only tools), and a clearer
"Current Capabilities" block.
Signed-off-by: Michael Mayer <michael@photoprism.app>
- Drop the public-mode 403 short-circuit in internal/api/mcp.go. In
public mode api.Session() returns the default public session, so
Auth(c, acl.ResourceMCP, acl.ActionView) + s.Abort(c) authorize
anonymous callers naturally. This enables the prototype to run on
demo.photoprism.app and similar showcase installations without
loosening the auth path or adding another toggle.
- The exemption is only safe because every currently registered tool
returns static reference metadata derived from config.Flags and
form.Report(&form.SearchPhotos{}) — no database access, no per-user
state, no secrets, no mutations. A handler-level comment captures
that contract so a future tool that does not fit cannot slip in
unnoticed.
- Flip the public-mode test case (ForbiddenPublicMode ->
AllowedPublicMode) in internal/api/mcp_test.go to a full anonymous
initialize + notifications/initialized + tools/call round-trip
against both registered tools, so any future tightening of the
policy regresses loudly.
- Update internal/mcp/README.md: the Authorization bullets now
describe the public-mode path, the Rate Limiting note reflects that
CE/Plus have no generic throttle in public mode, and a new
"Extending the Tool Surface" section documents the contract every
new tool must uphold plus the three supported extension paths
(two-server factory, per-tool context checks, SDK middleware).
Signed-off-by: Michael Mayer <michael@photoprism.app>