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.
52 lines
3.4 KiB
Markdown
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.
|