Replace Go RPC quicktype generation#1234
Merged
stephentoub merged 8 commits intogithub:mainfrom May 9, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR replaces Go RPC type generation from quicktype + post-processing with a schema-aware Go generator to preserve schema-level type identity (preventing structural deduplication collisions) and to keep the generated surface stable/sorted.
Changes:
- Reworked
scripts/codegen/go.tsto generate Go RPC types directly from schema definitions (no quicktype), including comment wrapping and union/object-flattening logic. - Updated Go SDK code and E2E tests for renamed generated types (e.g.,
SessionFs...,Mcp...) and updated shapes. - Adjusted schema post-processing documentation and added a local TS module type shim for
wordwrap.
Show a summary per file
| File | Description |
|---|---|
| scripts/codegen/utils.ts | Updates schema post-processing comments to reflect broader generator usage (not just quicktype Go). |
| scripts/codegen/types.d.ts | Adds a local TS module declaration for wordwrap to satisfy TS tooling. |
| scripts/codegen/go.ts | Replaces quicktype-based Go RPC generation with a custom generator; adds comment wrapping and new type-shape logic. |
| nodejs/package.json | Adds @types/wordwrap (currently appears misplaced relative to where wordwrap is used). |
| nodejs/package-lock.json | Lockfile updates for the added typings dependency. |
| go/types.go | Updates references to renamed generated RPC types (SessionFs...). |
| go/session.go | Updates UI elicitation defaults to use toRPCContent with new generated types. |
| go/session_fs_provider.go | Updates handler and types to renamed generated RPC SessionFs request/result/error types. |
| go/rpc/generated_rpc.go | Regenerated Go RPC types and wrappers using the new generator (major surface changes). |
| go/internal/e2e/session_fs_e2e_test.go | Updates SessionFs-related test references and messages for renamed types. |
| go/internal/e2e/rpc_session_state_e2e_test.go | Updates MCP OAuth request type name. |
| go/internal/e2e/rpc_server_e2e_test.go | Updates MCP discover request type name. |
| go/internal/e2e/rpc_mcp_config_e2e_test.go | Updates MCP config types/enums to new generated names and shapes. |
| go/internal/e2e/rpc_mcp_and_skills_e2e_test.go | Updates MCP enable/disable request type names. |
| go/generated_session_events.go | Regenerated session event types with more specific field types (notably elicitation/tool resource fields). |
| go/client.go | Updates SessionFs provider registration request type name. |
| go/client_test.go | Updates SessionFs conventions enum type name in tests. |
Copilot's findings
Files not reviewed (1)
- nodejs/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
nodejs/package.json:70
@types/wordwrapis added to the Node SDK package devDependencies, but there are no imports/usages ofwordwrapundernodejs/. The only usage is inscripts/codegen/go.ts, which is a different npm package (scripts/codegen/package.json). This dependency should be moved to the codegen package (or removed ifscripts/codegen/types.d.tsis sufficient).
"devDependencies": {
"@platformatic/vfs": "^0.3.0",
"@types/node": "^25.2.0",
"@types/wordwrap": "^1.0.3",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
"esbuild": "^0.27.2",
"eslint": "^9.0.0",
- Files reviewed: 14/17 changed files
- Comments generated: 3
Contributor
There was a problem hiding this comment.
Copilot's findings
Files not reviewed (2)
- nodejs/package-lock.json: Language not supported
- scripts/codegen/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
scripts/codegen/go.ts:1584
- The generated RPC union structs (e.g., from emitGoUnionStruct) call errors.New in UnmarshalJSON, but the import list only adds "errors" when schema.clientSession is present. If the schema ever omits clientSession (or it’s filtered out), the generated file will fail to compile due to missing errors import. Consider adding "errors" when generatedTypeCode references errors.New / "errors." (similar to the existing time.Time include check), rather than tying it to clientSession.
const imports = [`"context"`, `"encoding/json"`];
if (generatedTypeCode.includes("time.Time")) {
imports.push(`"time"`);
}
if (schema.clientSession) {
imports.push(`"errors"`, `"fmt"`);
}
- Files reviewed: 16/20 changed files
- Comments generated: 0 new
Contributor
|
Thanks @qmuntal! This looks like a great improvements. Just had a couple of comments but I'm sure we can get this merged soon. |
stephentoub
approved these changes
May 9, 2026
62e5a3a to
39a4786
Compare
Contributor
Author
|
@stephentoub this can be merged now, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Go RPC type generation currently depends on quicktype plus several post-processing passes. That breaks down when distinct schema definitions have the same structural shape: quicktype can merge those definitions into one Go type, which caused separate protocol concepts such as
MCPServerSourceandDiscoveredMCPServerSourceto be deduplicated. Quicktype does not expose a suitable Go option to disable that same-layout merging, so the generated API cannot reliably preserve schema-level type identity.The quicktype output also made casing harder to keep consistent with this repository's Go naming policy. Owning the Go generator lets us apply one explicit initialism list and avoid a mix of incidental quicktype casing plus local post-processing fixes.
This change follows the custom-generator approach used by other SDK codegen and replaces quicktype for Go RPC types with a schema-aware Go generator. The generator preserves named definitions, keeps generated declarations sorted, emits quicktype-like wrapped comments for RPC output, preserves enum ordering, and flattens object unions so the generated Go surface stays close to the existing quicktype shape where that behavior was desirable.
Dropping quicktype also makes the Go codegen easier to reason about: the generator now owns the schema-to-Go mapping directly instead of generating quicktype output and then repairing it with a pile of post-processing hacks. The end result is better-controlled codegen with an equivalent number of lines, but with the behavior expressed in the generator instead of scattered after-the-fact rewrites.
Python codegen still uses quicktype; this only removes quicktype from the Go RPC generation path.
Breaking changes
This changes the generated Go API surface. The breaking changes are intentionally limited to generated Go types, constants, fields, and method signatures that reference those generated types.
The main breaking-change patterns are:
mcp,fs, andsseare intentionally not initialisms in this PR, generatedMCP.../SessionFS...names becomeMcp.../SessionFs.... The same casing rule also applies to generated field names such asPIDandMSsuffixes.RPCTypesroot type is removed. It existed only as a quicktype input artifact and was not a real RPC schema concept.anyor broad primitive types are now generated as typed structs, typed maps, or schema-specific enum/string aliases when the schema provides that information. This affects areas such as embedded resources, UI elicitation values, and session-event payload details.Call sites and tests in the Go SDK were updated for the renamed generated RPC types, renamed fields, schema-specific helper types, and typed generated fields.
Why the breaks are done
The generated RPC package is derived from the protocol schema, so preserving the schema's named concepts is more important than preserving quicktype's incidental same-layout merging. Keeping separate named types avoids accidental aliasing between unrelated protocol concepts, makes future schema evolution safer, and removes fragile post-generation rewrites that were compensating for quicktype behavior.
The casing changes are done so generated names consistently follow the generator's explicit initialism list. The
McpandSessionFscasing is intentional for this PR: it keeps the current initialism policy unchanged, so addingmcp,fs, orssecan be reviewed separately if desired.Validation
npm run generate:gogo test ./... -run '^$'