Commit graph java-sdk/mcp-test
Author SHA1 Message Date
Dariusz Jędrzejczyk
5895b2edd2
fix: Return empty prompt completion result when prompt has no arguments (#934)
Recent changes don't coerce null completion arguments to empty lists so we have
to check for null when handling prompt completions.

Resolves #932

Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
2026-04-24 14:05:12 +02:00
Dariusz Jędrzejczyk
4c8596306d feat!: consistent JSON forward/backward compatibility - 2.0 foundation (#972)
The MCP specification evolves continuously; domain types must absorb
new fields and subtypes without breaking existing clients or servers.
On the 1.x line this is structurally prevented by sealed interfaces,
which make it impossible to add a permitted subtype without breaking
exhaustive pattern-match switch expressions in caller code. This
commit opens the 2.0 release line, where those constraints are lifted
and serialization is made self-contained — independent of any global
ObjectMapper configuration.

Breaking changes for users migrating from 1.x

- Sealed interfaces removed from JSONRPCMessage, Request, Result,
  Notification, ResourceContents, CompleteReference and Content.
  Exhaustive switch expressions over these types must add a default
  branch.
- Prompt(name, description, null) no longer silently coerces null
  arguments to an empty list. Use Prompt.withDefaults() to preserve
  the previous behaviour.
- CompleteCompletion.total and .hasMore are now absent from the wire
  when not set, rather than being emitted as null.
- ServerParameters no longer carries Jackson annotations; it is an
  internal configuration class, not a wire type.

What now works that did not before

- CompleteReference polymorphic dispatch (PromptReference vs
  ResourceReference) works through a plain readValue or convertValue
  call — no hand-rolled map inspection required.
- LoggingLevel deserialization is lenient: unknown level strings
  produce null instead of throwing.
- All domain records now tolerate unknown JSON fields, so a client
  built against an older SDK version will not fail when a newer server
  sends fields it does not yet recognise.
- Null optional fields are consistently absent from serialized output
  regardless of ObjectMapper configuration.

Documentation

- CONTRIBUTING adds an "Evolving wire-serialized records" section: a
  9-rule recipe and example for adding a field safely.
- MIGRATION-2.0 documents all breaking changes listed above.

Follow-up coming next

Several spec-required fields (e.g. JSONRPCError.code/message,
ProgressNotification.progress, CreateMessageRequest.maxTokens,
CallToolResult.content) are stored as nullable Java types without a
null guard. If constructed with null, the NON_ABSENT rule silently
omits them, producing invalid wire JSON without throwing. Fix: compact
canonical constructors with Assert.notNull, following the pattern
already in JSONRPCRequest.

Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
2026-04-23 17:34:55 +03:00
ashakirin
d1823389a9
feat!: add tool input arguments validation (#873)
added tool input arguments validation causes tool execution error. Breaking change, because validation is activated by default

closes #697

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-13 16:58:04 +02:00
Bilal Oumehdi
95203233c8
fix: Remove JsonSchema and use a Map for inputSchema to support json schemas dialect (#749)
* feat: remove JsonSchema an use a Map for inputSchema

- Fixes #886

Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-10 11:32:22 +02:00
Daniel Garnier-Moiroux
fcdc0d4c14 Polish gh-906 2026-04-09 11:11:07 +02:00
smohite04
eaa0c691f0
feat: add support for meta parameter in client paginated list queries (#906)
* feat: add support for meta parameter in client paginated list queries#

- resources/list
- resources/templates/list
- prompts/list
- tools/list

paginated list operations extended in this review:
- listResources(String cursor, Map<String, Object> meta)
- listResourceTemplates(String cursor, Map<String, Object> meta)
- listPrompts(String cursor, Map<String, Object> meta)

Closes #907

Co-authored-by: SHEETAL MOHITE <mohishee@amazon.com>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-09 10:40:35 +02:00
RameshReddy Adutla
8fd9903e62 Fix UTF-8 encoding for non-ASCII tool names in HTTP client transports
Both HttpClientSseClientTransport and HttpClientStreamableHttpTransport
set Content-Type to 'application/json' without specifying the charset.
While Java's BodyPublishers.ofString() uses UTF-8 by default, the
missing charset in the header can cause the server to interpret the
request body using a different encoding (e.g., ISO-8859-1), corrupting
non-ASCII characters such as Chinese tool names.

Explicitly set Content-Type to 'application/json; charset=utf-8' in
POST requests on both client transports.

Fixes #260

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-08 15:02:23 +02:00
Daniel Garnier-Moiroux
5e77762eeb HttpClientStreamableHttpTransport: handle HTTP 405
- Forward-port of #900

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-02 17:26:53 +02:00
Daniel Garnier-Moiroux
8c7774ad5f Server transports: remove deprecated methods from builder
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-02 15:50:57 +02:00
Christian Tzolov
cbb235fd32 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-03-13 13:31:03 +01:00
Christian Tzolov
c4b585795e
fix: prepare POMs for Maven Central release readiness (#863)
- Fix malformed SCM developerConnection URL (slash → colon) across all modules
- Add mcp-json-jackson3 to mcp-bom dependency management
- Update license URL to HTTPS
- Fix POM's scm definitions

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>



Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>

---------

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-03-13 12:41:49 +01:00
Daniel Garnier-Moiroux
abcd19c0c2
HttpClientStreamHttpTransport: add authorization error handler (#861)
HttpClientStreamHttpTransport: add authorization error handler

- Closes #240

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-03-13 10:12:57 +01:00
Dariusz Jędrzejczyk
6e4ce1c1a3
Fix elicitation and resource subscription tests that deadlock on a single CPU (#854)
Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2026-03-05 09:53:37 +01:00
조형준
05f37ad027
Use explicit UTF-8 charset in StdioServerTransportProvider (#826)
Also add a test simulating a different locale in an isolated process.

Resolves #295
2026-03-02 16:57:08 +01:00
Dariusz Jędrzejczyk
7f68ea5bc0
Support resource subscriptions (#839)
Clients can now subscribe to specific resources and receive targeted
notifications when those resources change. Previously, calling
`notifyResourceUpdated` on the server would broadcast the notification
to every connected client regardless of interest — now only sessions
that have explicitly subscribed to a given resource URI receive the
update, making resource change propagation both correct and efficient.
The subscription lifecycle is fully handled: clients can subscribe and
unsubscribe at any time, and the server cleans up subscription state
when a session closes.

Supersedes #838.
Resolves #837, #776.

---------

Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2026-03-02 15:26:03 +01:00
Christian Tzolov
d689cddd8b Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-23 10:32:26 +01:00
Christian Tzolov
7e08a8e63f Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 22:04:21 +01:00
Christian Tzolov
479e52e6d5 Release version 1.0.0-RC3
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 22:03:40 +01:00
Christian Tzolov
acb7e4d2a0 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 21:41:35 +01:00
Christian Tzolov
11b597cd77 Release version 1.0.0-RC2
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 21:37:56 +01:00
Dariusz Jędrzejczyk
4c1c3d8d5c
Remove deprecated APIs and modules for 1.0.0 release (#807)
- Remove mcp-json-jackson module (JacksonMcpJsonMapper, DefaultJsonSchemaValidator)
- Remove deprecated session interfaces (McpServerSession, McpClientSession methods)
- Remove deprecated server methods (loggingNotification, McpAsyncServerExchange constructor)
- Remove deprecated schema definitions and constructors (McpSchema, McpError, tool/content classes)
- Replace generic McpError with appropriate exception types (IllegalStateException, IllegalArgumentException)
- Update all tests to use current APIs

---------

Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2026-02-20 17:32:40 +01:00
Christian Tzolov
86cde46e6d Fix code formatting
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 13:25:31 +01:00
Christian Tzolov
90ad2be8f4 Make AbstractMcpAsyncClientResiliencyTests#host access public
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-20 08:42:58 +01:00
Daniel Garnier-Moiroux
77f59ad89b Stdio integration tests: increase initialize timeout to 25s
The initialize timeout was too short to be able to download the server
with NPX. As stated in the javadoc of `StdioMcpSyncClientTests`:

> These tests use npx to download and run the MCP "everything" server
> locally. The first test execution will download the everything server
> scripts and cache them locally, which can take more than 15 seconds.
> Subsequent test runs will use the cached version and execute faster.

Since the download happens on calling "connect", it is triggered during
the initialization of the client.

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-02-18 16:39:19 +01:00
Christian Tzolov
3ab829285d Bump version from 0.18.0-SNAPSHOT to 1.0.0-SNAPSHOT
Update project version across all POM files, documentation, and CI
workflow to prepare for the 1.0.x release

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-02-18 12:45:20 +01:00
Sébastien Deleuze
e60a0743a5
Refine McpJsonDefaults method names (#789)
As a follow-up of #779, this commit refines McpJsonDefaults
method names by shortening them to not repeat the qualifiers
already expressed at type level.
2026-02-13 16:54:01 +01:00
Daniel Garnier-Moiroux
f6c3fde7f4 DNS rebinding protection: check host header
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-02-12 11:00:42 +01:00
Daniel Garnier-Moiroux
6f3906480d Move mcp-core integration tests to mcp-test package
- The integration tests pass with both Jackson 2 and Jackson 3.
- Modified McpSchemaTests.testContentDeserializationWrongType to work
  with both Jackson 2 and Jackson 3.

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-02-12 09:13:38 +01:00
Scott Lewis
c3b9ab09ea Move mcp-json into mcp-core, add OSGi support
Co-authored-by: Luca Chang <131398524+LucaButBoring@users.noreply.github.com>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-02-12 09:13:38 +01:00
Dariusz Jędrzejczyk
0a8cb1e038
Decouple mcp-test and mcp-spring modules from Jackson implementation (#760)
This is a follow-up to #742.

The `mcp-test`, `mcp-spring-webflux`, and `mcp-spring-webmvc` depended
on `mcp` module which transitively brought in Jackson 3 dependencies.
These modules are now decoupled and only depend on `mcp-core`.

The test dependencies bring in Jackson 2 for the time being.

This is a breaking change but it is required to allow easily exchanging
Jackson2 and Jackson3 modules.

Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2026-01-27 15:47:28 +01:00
Filip Hrisafov
2456a0e433
Add Support for Jackson 3 (#742)
This change adds Jackson 3 support and aligns package naming in the existing Jackson 2 module.

Specific changes:
* Deprecated classes for removal in `io.modelcontextprotocol.json.jackson`/`io.modelcontextprotocol.json.schema.jackson`
* Copied the above to `io.modelcontextprotocol.json.jackson2`/`io.modelcontextprotocol.json.schema.jackson2` in non-deprecated form.
* Added tests for the default McpJsonMapper and JsonSchemaValidator
2026-01-26 11:43:35 +01:00
Dariusz Jędrzejczyk
af65356416
Fix everything-server-based integration tests (#756)
* Pin `npx @modelcontextprotocol/server-everything` version to `2025.12.18`.
* Replace `tzolov/mcp-everything-server` Docker image with `node:lts-alpine` + `npx` command.
* Handle HTTP 202 special case.
* Fix test assertions.

The recent rollout of everything-server broke integration tests which take the latest version from the node registry.
This PR unifies the everything-server usage - the Testcontainers Docker setup uses the same version as the STDIO npx-based tests and no longer relies on tzolov/mcp-everything-server.

Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2026-01-20 16:09:41 +01:00
Jordan Zimmerman
b518393cfd
Expose resourcesUpdateConsumer() in sync client (#735)
`resourcesUpdateConsumer()` was missing from the sync client. Add it.
2026-01-08 20:29:05 +01:00
Christian Tzolov
082444e18f Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-12-04 15:57:27 +01:00
codeboyzhou
7e950ebb6c
refactor: use builder pattern for CallToolResult and Resource (#652)
* use builder pattern for CallToolResult
* use builder pattern for Resource
* simplify lambda expressions in tests
2025-11-21 13:44:29 +01:00
Christian Tzolov
e3079270d5 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-11-12 16:13:08 +01:00
Christian Tzolov
6e9af40bcb Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-10-30 19:02:32 +01:00
Daniel Garnier-Moiroux
9bbfbe573a
Close McpTransportSession on transport close (#632)
* Client HTTP transports: use McpTransportSession interface instead of concrete types
* Streamable HTTP tranports: .closeGracefully closes the session

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2025-10-28 14:26:21 +01:00
Christian Tzolov
c734b2a5c1 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-10-02 00:03:36 +01:00
Christian Tzolov
c1cde20002
refactor: improve MCP server resilience and error handling (#579)
- Replace McpError with appropriate standard exceptions (IllegalArgumentException, IllegalStateException) for validation errors
- Change tool/prompt registration to replace existing items instead of rejecting duplicates with warningsi
  - Change addTool behavior to replace existing tools instead of throwing errors
  - Change addPrompt() to allow replacing existing prompts with warning instead of throwing error
- Make removal operations idempotent - log warnings instead of throwing errors for non-existent items
  - Change removePrompt() to log warning instead of throwing error for non-existent prompts
  - Change removeTool() to gracefully handle non-existent tools with warnings instead of errors
- Add listTools() and listPrompts() methods to all server variants (async, sync, stateless)
  - Add listTools() method to all server classes for tool enumeration
  - Add listPrompts() method to all server implementations for retrieving registered prompts
- Improve error construction using McpError.builder() pattern for protocol-specific errors
- Update error handling in session classes to properly propagate McpError JSON-RPC errors
  - Use proper error codes (INVALID_PARAMS) for prompt not found scenarios
- Update tests to reflect new lenient behavior for duplicate registrations and removals
- Add aggregateExceptionMessages() utility method utility to aggregate the exception chains
- Update McpServerSession and McpStreamableServerSession to use the aggregated errors in the json-rpc-error data section

This change makes the MCP server APIs more resilient and user-friendly by using appropriate exception types,
supporting item replacement, and providing listing capabilities while maintaining backward compatibility.

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-30 11:10:04 +02:00
Christian Tzolov
ff98e294f5 refactor: Improve resource template support (#576)
- Provide separation of concerns between static resources and parameterized resource templates.
- Add AsyncResourceTemplateSpecification and SyncResourceTemplateSpecification for both McpServerFeatures and McpStatelessServerFeatures
- Change resource template storage from List to Map to acomodate the resource read handler.
- Add runtime management methods: addResourceTemplate(), removeResourceTemplate(), listResourceTemplates()
- Improve error handling by using IllegalArgumentException/IllegalStateException instead of McpError
- Add new interfaces (Meta, Identifier) and reorganize schema hierarchy
- Enhance completion request validation with better error messages
- Add ResourceTemplate.Builder for easier template construction
- Update all server implementations (Async, Sync, Stateless) consistently
- Add type-safe constants for reference types (PromptReference.TYPE, ResourceReference.TYPE)
- Add tests for new resource template management functionality
- Clean up imports and remove unused dependencies

Co-authored-by: Pascal Vantrepote <pascal@confluent.io>

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-28 09:17:24 +02:00
Christian Tzolov
a0afdcd493 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-18 19:28:56 +02:00
Christian Tzolov
8ac7eae47c
refactor: standardize test parameterization and fix package naming (#556)
- Replace @ValueSource with @MethodSource for parameterized tests
- Add clientsForTesting() methods to provide test arguments consistently
- Remove hardcoded Spring-related labels from framework-agnostic mcp-test module
- Move mcp-test's utility classes from io.modelcontextprotocol.utils to io.modelcontextprotocol.util

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-17 12:26:55 +02:00
Graeme Rocher
80d0ad82a6 feat: Introduce McpJsonMapper interface to decouple from Jackson (#543)
This pull request creates two modules, `mcp-json` and `mcp-json-jackson`. It removes the `com.fasterxml.jackson.core:jackson-databind` and `com.networknt:json-schema-validator` dependencies from the `mcp` module. The `mcp` module now only depends on `com.fasterxml.jackson.core:jackson-annotations`.

To use Jackson, you have to add `mcp-jackson` to your dependencies in addition to `mcp`. I added the dependency `mcp-jackson` to both `mcp-spring-mvc` and `mcp-spring-webflux` to avoid a breaking change in those modules.

It provides two [SPI](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) `JsonSchemaValidatorSupplier` and `JacksonJsonSchemaValidatorSupplier` to allow easy replacement for consumers who don't want to use Jackson.

This pull request also ensures no `McpJsonMapper` is instantiated if one is provided via a builder method. Only if the builders don't receive a `McpJsonMapper` mapper, one is instantiated in the `build` method of the builder.
The logic behind this is to allow frameworks to provide a `McpJsonMapper` mapper singleton implementation and feed it to the builders without paying the price of instantiating `McpJsonMappers`, which will not be used. The goal is to be able to use the `ObjectMapper` singleton of an application also for the MCP code.

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-15 15:51:06 +02:00
Christian Tzolov
d8959ef854
fix: support valid JSON value in tool structured content output (#551)
- Change CallToolResult.structuredContent type from Map<String,Object> to Object
  to support both objects and arrays
- Update JsonSchemaValidator to validate any Object type, not just Maps
- Add test cases for array-type structured output validation
- Fix type casting in existing tests to handle the more generic Object type
- Deprecate CallToolResult constructors in favor of builder pattern
- Update server implementations to use CallToolResult builder

This allows tools to return arrays as structured content, not just objects,
which is required by the MCP specification for tools with array-type output schemas.

It is realated to MPC spec fix: https://github.com/modelcontextprotocol/modelcontextprotocol/issues/834

Fixes #550

BREAKING CHANGE!

Migration Guide:
----------------
1. If you're accessing CallToolResult.structuredContent():
   - Add explicit casting when you know it's a Map:
     Before: result.structuredContent().get("key")
     After:  ((Map<String,Object>) result.structuredContent()).get("key")

   - Or check the type first:
     if (result.structuredContent() instanceof Map) {
         Map<String,Object> map = (Map<String,Object>) result.structuredContent();
         // use map
     } else if (result.structuredContent() instanceof List) {
         List<?> list = (List<?>) result.structuredContent();
         // use list
     }

2. If you're creating CallToolResult instances:
   - Switch to using the builder pattern:
     Before: new CallToolResult(content, isError, structuredContent)
     After:  CallToolResult.builder()
               .content(content)
               .isError(isError)
               .structuredContent(structuredContent)
               .build()

3. If you're implementing JsonSchemaValidator:
   - Update your validate() method signature:
     Before: validate(Map<String,Object> schema, Map<String,Object> structuredContent)
     After:  validate(Map<String,Object> schema, Object structuredContent)

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-15 14:22:06 +02:00
Christian Tzolov
c7736b6ec6 fix: Skip structured output validation for error tool results
This ensures that when a tool handler returns an error result, the structured
output schema validation is skipped, preventing validation failures on error
responses that don't conform to the expected output schema.

- Add validation bypass when CallToolResult.isError() is true in async/stateless servers
- Fix async tool handler chaining to properly use then() instead of block()
- Add comprehensive tests for structured output with in-handler errors
- Improve error handling to use proper JSON-RPC error codes for unknown tools
- Add findRootCause utility method for better error diagnostics
- Increase test timeouts for stability in StdioMcp client tests. These tests use npx
  to download and run the MCP "everything" server locally. The first
  test execution will download the everything server scripts and cache them locally,
  which can take more than 15 seconds. Subsequent test runs will use the cached version
  and execute faster.

Resolves #538
Related to #422

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-08 13:48:53 +02:00
Christian Tzolov
7cf5907da4 Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-04 22:33:14 +02:00
Christian Tzolov
681fe7f90b
test: ensure proper resource cleanup in integration tests (#537)
- Add try-finally blocks to guarantee server cleanup on test completion
- Call closeGracefully().block() to ensure synchronous shutdown
- Use try-with-resources for client lifecycle management where applicable
- Prevent resource leaks and potential test flakiness

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2025-09-04 16:52:21 +02:00
Christian Tzolov
ec4b329699
test: upgrade mcp-everything-server to v3 and fix resiliency test race condition (#536)
- Upgrade Docker test server image from v2 to v3 across all test files
- Updates all test files to use the latest version of the mcp-everything-server
Docker image (v3) for integration testing.
- Fix race condition in async client tests by not advertising roots capability during initialization
  - Prevents server from listing roots during init which could cause timing issues when disconnecting immediately after initialization
- Applied fix to AbstractMcpAsyncClientResiliencyTests (both mcp and mcp-test modules) and HttpSseMcpAsyncClientLostConnectionTests

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
2025-09-04 14:46:08 +02:00
Daniel Garnier-Moiroux
a5fd1ebff5
Use static container in all client and transport tests (#531)
- This allows reusing the containerized MCP server for all tests in a
  single class, significantly speeding up the tests, roughly 10x.

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2025-09-03 16:36:46 +02:00