Skip to content

feat(mcp): add posthogmcpgo, MCP analytics for mark3labs/mcp-go servers - #409

Merged
lucasheriques merged 9 commits into
mainfrom
lucas/mcp-mark3labs-adapter
Nov 6, 2026
Merged

lucasheriques merged 9 commits into
mainfrom
lucas/mcp-mark3labs-adapter

Conversation

@lucasheriques

@lucasheriques lucasheriques commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

posthog-go can instrument MCP servers built on the official Go SDK (posthogmcpsdk), but many Go MCP servers in production are built on mark3labs/mcp-go. Those servers get no MCP analytics today.

This adds posthogmcpgo, a module for mark3labs/mcp-go. Instrument returns one server.ServerOption:

  • a tool filter adds the context and llm_model arguments to listed tool schemas
  • a tool handler middleware strips them before the handler runs
  • mcp-go call hooks, added to the server's existing hooks, capture each call with the result the client actually receives, so calls rejected by WithInputSchemaValidation or WithOutputSchemaValidation are recorded as failures, like posthogmcpsdk records them

Events go through the shared posthogmcp core, so they match posthogmcpsdk.

s := server.NewMCPServer("weather-server", "1.0.0",
	server.WithToolCapabilities(true),
	posthogmcpgo.Instrument(posthogmcp.New(client), posthogmcpgo.WithServerInfo("weather-server", "1.0.0")),
)

Not in this pass: conversation anchoring, the missing-capability tool, $mcp_unknown_tool, $mcp_input_required, intent fallback.

Decisions worth a look:

  • Capture lives in hooks, not middleware. mcp-go validates input before tool middleware and output after it, so only the call hooks see what the client got. Hooks act only on their own server's requests, so servers sharing one *server.Hooks don't double-capture. If the host passes WithHooks after Instrument (replacing ours), the middleware detects it, falls back to capturing, and reports it once through the error handler.
  • Resolvers get the request context. WithIdentity/WithProperties run from the hooks, so values added by host tool middleware aren't visible; request-scoped values go on the context with WithHTTPContextFunc/WithStdioContextFunc. Documented in the README.
  • Schemas that could reject an extra property are left unchanged (an allowlist of root keywords), and task tools (AddTaskTool) are listed unchanged and not captured, since mcp-go never runs middleware for them. Those calls carry no intent.
  • Follows sdk-specs where posthogmcpsdk doesn't: a tool's own context/llm_model is tool data (kept in $mcp_parameters, never read as intent), and calls run as tasks emit nothing until the task's terminal status can be observed. HTTP+SSE sessions derive their id like streamable HTTP. Aligning posthogmcpsdk on tool-owned arguments is a follow-up.
  • In-flight state is bounded by count (1024 calls, oldest first), as the spec requires, rather than by age, so long-running calls aren't dropped.
  • No custom $mcp_error_type for tool error results, same as posthogmcpsdk. Letting servers classify errors is a cross-SDK question.
  • Schemas are re-derived per call, not cached. Microseconds of JSON work against a network round trip, and caching would need invalidation for tools mcp-go lets you replace at runtime.

CI: adds a unit-test job (Go 1.25 and 1.x, race, plus a build against the pinned posthog-go release), a format and tidy check, and adds the module to the release workflow's sync and tag loops so releases tag posthogmcpgo/vX.Y.Z.

💚 How did you test it?

  • go vet ./... and go test -race ./... in posthogmcpgo, including a parity test that runs the same call through posthogmcpsdk and compares the captured properties, and a strict validating server test (WithInputSchemaValidation + WithStrictInputSchemaDefault) that failed before the closed-schema fix.
  • The module builds and vets against the pinned posthog-go release with the replace directives dropped, as consumers will.
  • End to end, before and after the hooks change: a public mark3labs streamable HTTP server instrumented with this module, driven by Claude Code sessions. $mcp_tool_call events arrived with intents, error text, and session ids derived from Mcp-Session-Id.

📝 Checklist

  • All commits are signed (see Commit signing)
  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written with Claude Code (Claude Opus). Design choice: mcp-go has no receiving middleware like the official SDK, so the adapter uses WithToolFilter for schema injection and WithToolHandlerMiddleware for capture, reusing the posthogmcp core for event shape, redaction and session id hashing. Reviewed by Lucas, then two rounds of adversarial pre-PR review (Claude Opus and Sonnet). Each verified finding became a regression test that failed before its fix: constrained schemas, task tools, input/output validation failures, shared hooks, absent arguments, typed schemas, protocol version per transport, session cleanup.

Adds a posthogmcpgo module next to posthogmcpsdk. Instrument returns a
server.ServerOption: a tool filter injects the context and llm_model
arguments into listed schemas, and a tool handler middleware strips them,
times the call and captures $mcp_tool_call (and $exception on failure)
through the shared posthogmcp core, so events match posthogmcpsdk.

Out of scope for this pass: conversation anchoring, the missing-capability
tool, $mcp_unknown_tool, $mcp_input_required, intent fallback.

Tested: go vet ./... and go test ./... in posthogmcpgo pass, including a
parity test against posthogmcpsdk; end to end, hashicorp/terraform-mcp-server's
streamable HTTP server sent $mcp_tool_call events with session ids derived
from Mcp-Session-Id.
@lucasheriques lucasheriques self-assigned this Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

posthog-go Compliance Report

Date: 2026-11-05 20:55:06 UTC
Duration: 169219ms

✅ All Tests Passed!

111/111 tests passed


Capture_V1 Tests

✅ 94/94 tests passed

View Details
Test Status Duration
Endpoint And Method.Targets V1 Endpoint ✅ 18ms
Endpoint And Method.Does Not Use Legacy Endpoints ✅ 7ms
Required Headers.Has Authorization Bearer Header ✅ 6ms
Required Headers.Has Content Type Json ✅ 6ms
Required Headers.Has Posthog Sdk Info Format ✅ 7ms
Required Headers.Has Posthog Attempt Header ✅ 6ms
Required Headers.Has Posthog Request Id ✅ 6ms
Required Headers.Has Posthog Request Timestamp ✅ 6ms
Required Headers.Has User Agent ✅ 16ms
Body Format.Body Has Created At And Batch ✅ 6ms
Body Format.No Api Key In Body ✅ 6ms
Body Format.No Sent At In Body ✅ 16ms
Event Format.Event Has Required Root Fields ✅ 6ms
Event Format.Event Uuid Is Valid ✅ 6ms
Event Format.Event Timestamp Is Rfc3339 ✅ 6ms
Event Format.Distinct Id Is String ✅ 6ms
Event Format.Distinct Id At Root Not Properties ✅ 6ms
Event Format.Custom Properties Preserved ✅ 6ms
Event Format.Set Properties Preserved ✅ 6ms
Event Format.Set Once Properties Preserved ✅ 6ms
Event Format.Groups Properties Preserved ✅ 6ms
Event Format.Sdk Generates Uuid If Not Provided ✅ 5ms
Event Format.Event Has Required Root Fields Batch ✅ 9ms
Event Format.Event Uuid Is Valid Batch ✅ 9ms
Event Format.Event Timestamp Is Rfc3339 Batch ✅ 8ms
Event Format.Distinct Id Is String Batch ✅ 9ms
Event Format.Distinct Id At Root Not Properties Batch ✅ 8ms
Event Format.Custom Properties Preserved Batch ✅ 9ms
Event Format.Set Properties Preserved Batch ✅ 8ms
Event Format.Set Once Properties Preserved Batch ✅ 9ms
Event Format.Groups Properties Preserved Batch ✅ 8ms
Event Format.Sdk Generates Uuid If Not Provided Batch ✅ 9ms
Batch Behavior.Multiple Events In Single Batch ✅ 30ms
Batch Behavior.Batch Envelope Smoke ✅ 10ms
Batch Behavior.Flush With No Events Sends Nothing ✅ 4ms
Batch Behavior.Flush At Triggers Batch ✅ 1007ms
Batch Behavior.Created At Reflects Batch Creation Time ✅ 8ms
Deduplication.Generates Unique Uuids ✅ 14ms
Deduplication.Different Events Same Content Different Uuids ✅ 8ms
Deduplication.Preserves Uuid On Retry ✅ 5134ms
Deduplication.Preserves Timestamp On Retry ✅ 5136ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5135ms
Deduplication.No Duplicate Events In Batch ✅ 32ms
Header Behavior On Retry.Attempt Header Starts At One ✅ 6ms
Header Behavior On Retry.Attempt Header Increments On Retry ✅ 10139ms
Header Behavior On Retry.Request Id Preserved On Retry ✅ 5135ms
Header Behavior On Retry.Different Requests Have Different Request Ids ✅ 2025ms
Header Behavior On Retry.Request Timestamp Changes On Retry ✅ 5135ms
Response Format Validation.Success Response Has Uuid Keyed Results ✅ 17ms
Response Format Validation.Success Response Has Ok For Each Event ✅ 29ms
Response Format Validation.Success No Retry After When All Ok ✅ 28ms
Response Format Validation.Success Retry After Present When Retry Events ✅ 129ms
Response Format Validation.Success No Retry After When Drop Only ✅ 27ms
Response Format Validation.Response Echoes Request Id ✅ 7ms
Retry Behavior.Retries On 408 ✅ 5132ms
Retry Behavior.Retries On 500 ✅ 5133ms
Retry Behavior.Retries On 503 ✅ 5136ms
Retry Behavior.Retries On 504 ✅ 5135ms
Retry Behavior.Retryable Errors Have Retry After ✅ 2133ms
Retry Behavior.Respects Retry After On Retryable Error ✅ 8138ms
Retry Behavior.Does Not Retry On 400 ✅ 2131ms
Retry Behavior.Does Not Retry On 401 ✅ 2133ms
Retry Behavior.Does Not Retry On 402 ✅ 2132ms
Retry Behavior.Does Not Retry On 413 ✅ 2132ms
Retry Behavior.Does Not Retry On 415 ✅ 2133ms
Retry Behavior.Non Retryable Errors Have No Retry After ✅ 2134ms
Retry Behavior.Implements Backoff ✅ 15145ms
Retry Behavior.Max Retries Respected ✅ 15144ms
Partial Batch Handling.Handles 200 Full Success ✅ 2009ms
Partial Batch Handling.Handles 200 With All Ok ✅ 3032ms
Partial Batch Handling.Does Not Retry Dropped Events ✅ 3031ms
Partial Batch Handling.Does Not Retry Limited Events ✅ 3031ms
Partial Batch Handling.Prunes Ok Events On Partial Retry ✅ 5133ms
Partial Batch Handling.Prunes Dropped Events On Partial Retry ✅ 5135ms
Partial Batch Handling.Retries Only Retry Events From Partial ✅ 5137ms
Partial Batch Handling.Partial Retry Preserves Uuids ✅ 5134ms
Partial Batch Handling.Partial Retry Attempt Header Increments ✅ 5133ms
Partial Batch Handling.Partial Retry Request Id Preserved ✅ 5135ms
Partial Batch Handling.Respects Retry After On Partial ✅ 5134ms
Partial Batch Handling.Unknown Result Treated As Terminal ✅ 3031ms
Partial Batch Handling.Mixed Ok Drop Limited No Retry ✅ 3033ms
Compression.Sends Gzip Content Encoding ✅ 17ms
Compression.No Content Encoding When Disabled ✅ 5ms
Compression.Compressed Body Is Decompressible ✅ 16ms
Error Handling.Does Not Retry On Unknown 4Xx ✅ 2130ms
Event Options.Cookieless Mode Override ✅ 8ms
Event Options.Disable Skew Correction Override ✅ 5ms
Event Options.Process Person Profile Override ✅ 6ms
Event Options.Product Tour Id Override ✅ 6ms
Event Options.Unset Options Omitted ✅ 6ms
Event Options.Options Override In Batch ✅ 8ms
Geoip And Historical Migration.Geoip Disable Injected Into Properties ✅ 6ms
Geoip And Historical Migration.Historical Migration Set In Body ✅ 5ms
Geoip And Historical Migration.Historical Migration Absent By Default ✅ 6ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 16ms
Request Payload.Flags Request Uses V2 Query Param ✅ 15ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 16ms
Request Payload.Flags Request Omits Authorization Header ✅ 15ms
Request Payload.Token In Flags Body Matches Init ✅ 16ms
Request Payload.Groups Round Trip ✅ 16ms
Request Payload.Groups Default To Empty Object ✅ 15ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 16ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 15ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 16ms
Request Lifecycle.No Flags Request On Init Alone ✅ 2ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 6ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 29ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 16ms
Retry Behavior.Retries Flags On 502 ✅ 16ms
Retry Behavior.Retries Flags On 504 ✅ 17ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 17ms

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 8f4b257: 1 Must fix, 9 Should fix.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/arguments.go Resolved
Comment thread posthogmcpgo/sessions.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/tools.go Resolved
Comment thread posthogmcpgo/arguments.go Resolved
Comment thread posthogmcpgo/tools.go Resolved
Comment thread posthogmcpgo/tools.go Resolved
mcp-go's WithInputSchemaValidation checks calls against the registered schema
before tool middleware runs, so adding context/llm_model to a schema with
additionalProperties:false made every call fail (WithStrictInputSchemaDefault
closes every schema). Such schemas are now left unchanged.

CI had no job for the new module: add unit tests (Go 1.25 and 1.x, race, plus a
build against the pinned posthog-go release), a format/tidy check, and add it to
the release workflow's sync and tag loops. Add a changeset.

Tested: go test -race ./... in posthogmcpgo (new strict validating server test
failed before the fix, passes after); pinned build and go mod tidy clean.
…nto open schemas

What: posthogmcpgo now captures tool calls from mcp-go call hooks
(BeforeCallTool, AfterCallTool, OnError) appended to the server's existing
hooks, so events record the response the client received. Input and output
schema validation failures become failed calls. The middleware only strips
the analytics arguments. It captures instead when the call runs as a task,
or when a later server.WithHooks replaced the hooks (reported once).

Why: a pre-PR review found seven verified defects that could break a host
server or misreport calls:
- validating servers rejected advertised calls for schemas that can refuse
  extra properties. Injection now uses a root-keyword allowlist.
- task tools were advertised with the arguments but never stripped. They are
  now left unchanged and not captured.
- input validation failures sent no event, and output validation failures
  were captured as successes.
- absent arguments were captured as null (posthogmcpsdk sends {}).
- typed InputSchema became RawInputSchema, hiding properties from later
  tool filters. The representation is now kept, on a copy.
- $mcp_protocol_version was missing off HTTP. It now comes from
  AfterInitialize per session, dropped on unregister.

Tested: each defect has a table-driven test that fails on 882f191 and
passes now. gofmt -l . (clean), go vet ./... (clean),
go test -race -count=10 ./... (ok). go mod tidy leaves go.mod/go.sum
unchanged. Pinned-release build with both replaces dropped:
GOFLAGS=-mod=mod go build ./... && go vet ./... (ok).

Reviewer notes: per-call state is keyed by the *CallToolRequest that
mcp-go's hooks share, and entries older than an hour are swept, because a
handler panic recovered by a transport fires no after/error hook.
patternProperties is excluded from the allowlist: a pattern matching
"context" can reject a string value.
From a second adversarial review of the hooks-based capture:
- Servers sharing one *server.Hooks each captured every call (3 servers gave
  3 events per call, and an uninstrumented server sent events). Hooks now act
  only on their own server's requests (server.ServerFromContext).
- A synchronous call mcp-go rejects for a task tool was captured as a failure.
  Only calls to tools the middleware wraps are tracked now.
- A closed session's generated session id stayed in memory until a later
  sweep. Unregistering a session now drops it.
- A session closing mid-call lost $mcp_protocol_version. It is read when the
  call starts.
README documents what hook-based capture implies: resolvers get the request
context (use WithHTTPContextFunc/WithStdioContextFunc), an unrecovered handler
panic sends no event, and what a later WithHooks loses.

Tested: go test -race ./... (4 new tests, each failing before the fix); the
adversaries' repros now pass; pinned-release build and go mod tidy clean.
@lucasheriques
lucasheriques marked this pull request as ready for review November 5, 2026 13:00
@lucasheriques
lucasheriques requested a review from a team as a code owner November 5, 2026 13:00
main released v1.40.0 and posthogmcpsdk now requires it, so go mod tidy
raises posthogmcpgo's minimum to match. Tested: go test -race ./..., pinned
build.

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 7ed4cfd: 7 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.

Comment thread posthogmcpgo/tools.go Resolved
Comment thread posthogmcpgo/tools.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/calls.go Resolved
Comment thread posthogmcpgo/calls.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed f29d5e4: no findings. This pull request is large, so the review ran in 4 parts with less depth than usual.

What: tool-owned context/llm_model are the tool's data (passed through,
kept in $mcp_parameters, never intent/model); SSE sessions derive
$session_id from the transport id, only stdio and in-process get a
rotating generated id; schemas decode with UseNumber; minProperties and
root "$ref": "#" schemas are no longer extended; ErrToolNotFound from a
registered tool is a captured failure; task-run calls send no event;
in-flight calls are bounded by count (1024, oldest dropped) instead of a
1h sweep; advertise copies session tools once per listing.

Why: the cross-SDK contract (mcp-analytics spec) and never altering the
host server's behavior on production servers.

Tested: gofmt clean; go vet ./...; go test -race -count=2 ./...; go mod
tidy leaves go.mod/go.sum unchanged; pinned build (replaces dropped)
builds and vets. New table-driven tests fail before the fix.

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues remain in recursive-schema preservation and failure capture before task creation; details inline. The separate module, validation-aware hooks and release wiring otherwise look appropriate.

AI-assisted review.

Comment thread posthogmcpgo/tools.go Resolved
Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/options.go Resolved
@dustinbyrne
dustinbyrne requested a review from a team November 5, 2026 16:26
…s that may ref their root

Review on #409 found two gaps:
- beforeCall dropped every call run as a task, so a call mcp-go refuses
  before creating a task (e.g. a tool filter denial) sent no failed event.
  Calls are now tracked until mcp-go answers; errors are captured, and a
  CreateTaskResult still is not.
- Only a literal "$ref": "#" counted as recursion, so a $ref to the root's
  $id made nested objects require the analytics arguments. Any $ref other
  than a "#/..." pointer, $dynamicRef, or $recursiveRef now leaves the schema
  unchanged.
Also fixes the WithContextParameter doc, which said a tool's own context is
captured as intent.

Tested: go test -race -count=1 ./... in posthogmcpgo (new cases fail before
the fix), go vet, gofmt, go mod tidy (no diff).

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed f4c158b: 2 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.

This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.

Comment thread posthogmcpgo/instrument.go Resolved
Comment thread posthogmcpgo/sessions.go Resolved

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three previous findings are addressed and their original regressions pass. One additional lifecycle issue remains: tool deregistration during a call loses argument ownership, and real HTTP delivery confirms injected intent can enter captured parameters without intent-specific redaction. Details inline.

AI-assisted review.

Comment thread posthogmcpgo/instrument.go Resolved
@dustinbyrne
dustinbyrne requested a review from a team November 5, 2026 17:44
Capture re-read the registry and resolved the session after the handler ran.
Review on #409 found two consequences:
- A tool that unregisters itself in its handler lost argument ownership, so
  the injected context and llm_model landed in $mcp_parameters unredacted and
  no intent was sent.
- A stdio or in-process call running past the 30-minute inactivity timeout
  rotated $session_id at completion, splitting one conversation.
callStart now holds the tool info and $session_id taken at arrival, in both the
hook and middleware paths, and completion counts as session activity. Also
checks server ownership before looking up session tools in beforeCall.

Tested: go test -race -count=1 ./... in posthogmcpgo; both new tests fail
before the fix with their stable-tool and inactivity controls passing; go vet,
gofmt, go mod tidy (no diff).

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed f3b284f. The earlier findings are addressed, including ownership retention through tool deregistration and intent redaction. Focused regressions and queued HTTP delivery checks pass. One optional shared-guide update is noted inline.

AI-assisted review.

Comment thread posthogmcpgo/README.md Resolved
@lucasheriques
lucasheriques merged commit d4ea159 into main Nov 6, 2026
37 checks passed
@lucasheriques
lucasheriques deleted the lucas/mcp-mark3labs-adapter branch November 6, 2026 13:28
lucasheriques added a commit that referenced this pull request Nov 6, 2026
Follow-up to #409, from review: CONTRIBUTING.md listed only otel and posthogmcpsdk in the nested-module checks, and RELEASING.md left posthogmcpgo out of the shared release version, though the release workflow already includes it. Docs only; no code or CI change.
lucasheriques added a commit that referenced this pull request Nov 13, 2026
* docs: add posthogmcpgo to the contributing and releasing guides

Follow-up to #409, from review: CONTRIBUTING.md listed only otel and posthogmcpsdk in the nested-module checks, and RELEASING.md left posthogmcpgo out of the shared release version, though the release workflow already includes it. Docs only; no code or CI change.

* docs(contributing): remove both local replaces when copying posthogmcpgo

Review fix (dustinbyrne P2): posthogmcpgo replaces both the core and posthogmcpsdk, so the temporary-copy check must drop both, as CI does. Wording-only; no tests applicable.
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.

2 participants