Skip to content

feat(mcp): add JSON structured logging emitter and JWT sub claim (#373 stack 1/3)#375

Open
adriannoes wants to merge 4 commits into
devfrom
feat/373-json-log-emitter
Open

feat(mcp): add JSON structured logging emitter and JWT sub claim (#373 stack 1/3)#375
adriannoes wants to merge 4 commits into
devfrom
feat/373-json-log-emitter

Conversation

@adriannoes

@adriannoes adriannoes commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Part of #373 (stack 1/3).

Summary

  • Introduces allowlisted JSON event builders and a dedicated stdout logger (propagate=False) for hosted observability.
  • Adds PIPEFY_MCP_LOG_LEVEL to McpSettings and wires it through FastMCP(log_level=...).
  • Extends PipefyAccessToken with optional sub from JWT claims for caller subject in request logs (D16).
  • Hardens log level normalization (explicit map) and degrades non-string sub to null instead of rejecting the token.

What does not land yet

No structured lines are emitted until stack 2/3 (#376) and 3/3 (#377) merge. This PR only lays the emitter and identity groundwork.

Stack status

Test plan

  • uv run pytest packages/mcp/tests/observability/test_json_logging.py -q
  • uv run pytest packages/mcp/tests/auth/test_resource_server.py -q
  • uv run ruff check packages/mcp && uv run ruff format --check packages/mcp

Introduce allowlisted JSON event builders and a dedicated stdout logger
with propagate=False so hosted observability coexists with FastMCP's
RichHandler. Add PIPEFY_MCP_LOG_LEVEL to McpSettings and wire it through
run_server and FastMCP construction.
Extend the resource-server token mapping with an optional sub field so
hosted HTTP request logs can emit caller subject alongside client_id
without re-decoding the bearer.
normalize_log_level resolved names via getattr(logging, ...), which returns
non-level module attributes (BASIC_FORMAT) and accepts aliases the settings
Literal rejects (WARN, FATAL); an explicit map fails loudly on both. The
observability package now re-exports its stdlib-only emitter surface per the
package convention, and a suite-wide autouse fixture drops leftover stdout
handlers so a test that configures the process-global logger cannot leak a
closed-stream handler into later tests.
…he token

PipefyAccessToken.sub is str | None, so a validly-signed token carrying a
numeric sub raised ValidationError inside _to_access_token and verify_token
turned it into a 401, a token dev accepted before the field existed. sub
feeds request logging only; a malformed value must not gate authentication.
RFC 7519 requires StringOrURI, so only non-compliant IdPs ever hit this.
@adriannoes adriannoes force-pushed the feat/373-json-log-emitter branch from 651dec7 to 932c9f2 Compare July 8, 2026 14:34
@adriannoes adriannoes marked this pull request as ready for review July 8, 2026 14:34
@adriannoes adriannoes requested a review from Danielmoraisg July 8, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant