Files
Flash5/flash-extensions/flash-ext-mcp/docs/jackson-interop.md
T
Zakaria El Orche 9d39e24ccb refactor(ext-auth): generic sessions, shared annotation wiring, rename to flash-ext-auth-oidc
AuthMiddleware.install(ctx, config, source) now owns the annotation processor and
the flash.auth.policy key, so a second credential source gets annotation-driven
authorization without copying the wiring. The key is public: an extension that
contributes middleware can order itself around authentication.

OidcSession becomes Session in auth-core, carrying claims, an expiry and an opaque
attribute map. OpenID Connect keeps its access, id and refresh tokens in that map
under its own keys, so renewal stays its business and core has no OAuth2 vocabulary
in it. isAccessTokenExpired() becomes isExpired(), with the 30s eager-renewal
window it always had and now a test for it.

flash-ext-oidc is renamed flash-ext-auth-oidc, matching cache-core/cache-caffeine
and data-core/data-hibernate.
2026-09-10 19:06:15 +00:00

52 lines
3.4 KiB
Markdown

# Why no `flash-ext-jackson` interop (yet)
## The decision
`flash-ext-mcp` does not depend on, or integrate with, `flash-ext-jackson`. It brings its own
JSON handling (`jackson-databind`/`jackson-core` as a plain library dependency, wrapped by the
internal `McpJson` utility) and never touches `flash-ext-jackson`'s `Json`/`JacksonMiddleware`/
shared `ObjectMapper`, even if the host app has `flash-ext-jackson` installed. This was a
deliberate choice, discussed and made explicitly — not an oversight — and is written down here
so it isn't accidentally "fixed" later without re-litigating the trade-off.
## Why
`flash-ext-jackson`'s `Json` class is built around full databinding:
`mapper.readValue(bytes, SomeDto.class)` / `mapper.writeValueAsBytes(obj)` — reflection-driven
property matching in both directions. The MCP JSON-RPC envelope has a **fixed, known shape**
(`{jsonrpc, id, method, params}` in, `{jsonrpc, id, result|error}` out) defined by a spec, not by
application DTOs. Given that, hand-writing it with `JsonGenerator` directly is both simpler and
strictly cheaper than round-tripping through databinding: no property-name matching, no
reflection, no intermediate POJO graph for the parts of the response this extension controls
(the envelope itself, `tools/list`/`resources/list`/`prompts/list` — precompiled once at boot,
see `tools-resources-prompts.md` — and the fixed `TextContent`/`TextResourceContents`/
`PromptMessage` shapes). `ToolArguments`/`PromptArguments` read the incoming `arguments` object
as a `JsonNode` tree, not as a databound class, for the same reason — a JSON-RPC tool call's
arguments aren't a DTO with getters/setters, they're a dynamic, per-tool-defined bag of values.
This mirrors how `flash-ext-auth-oidc` already handles its own internal JSON needs (`json-smart` for
token-endpoint responses) independently of `flash-ext-jackson` — extensions with protocol-level
JSON needs that are shaped by a spec, not by user code, own that JSON handling themselves rather
than routing it through the app's general-purpose JSON extension.
## What this means practically
- Installing `flash-ext-mcp` never requires installing `flash-ext-jackson`. A pure MCP server
with no other JSON REST routes has zero unrelated dependencies to configure.
- If the host app *does* have `flash-ext-jackson` installed for its own REST routes, that
`ObjectMapper`'s configuration (custom modules, date formatting, naming strategy, etc.) is
**not** consulted by `flash-ext-mcp` — the two JSON paths are entirely independent today.
## What a future opt-in reuse could look like
Nothing here rules out a later, additive convenience layer: `McpExtension.routes()` could check
`ctx.find(ObjectMapper.class)` (populated by `JacksonExtension.provide()`) and, if present, use
that shared mapper as the backing for an escape hatch such as `ToolArguments.as(Class<T>)` or
for a tool that wants to `ToolResponse.success(someRecord)` and have it serialized with the
app's own conventions — falling back to a locally-constructed default `ObjectMapper` when
`flash-ext-jackson` isn't installed, the same "prefer shared, degrade to sane default" shape
already used for `McpSecurity.AUTO`. That would be purely additive on top of the
`JsonGenerator`-based envelope/content writing described above, not a replacement for it — the
fixed-shape protocol plumbing has no reason to ever go through databinding, regardless of what
convenience layer gets added around it.