← back to Cli Printing Press
fix(cli): emit WithNumber/WithBoolean for OpenAPI-parsed numeric MCP params (#1372)
1f1b0bdb20325f512dce35283d724602c72ebcdd · 2026-05-14 00:29:58 -0700 · Trevin Chow
* fix(cli): normalize numeric/bool spec types in MCP binding emission
The MCP tool and intent templates picked the `mcplib.With*` binder with
a literal `eq .Type "integer"` / `eq .Type "boolean"` check. That worked
for internal-spec literals but missed every OpenAPI-parsed numeric and
bool: `mapSchemaType` normalizes to `"int"`, `"float"`, `"bool"`, and
the templates fell through to `WithString` for those. The JSON-RPC
input then arrived as a quoted string, and any type-strict endpoint
(Pushover's update_highest_message.json was the trigger case) rejected
the payload with HTTP 400.
Funnel through a new `mcpBindingFunc(t)` helper that runs `primitiveKind`
and returns the `With*` name, so OpenAPI shapes and internal-spec
literals both produce the same binding. Collapses three duplicated
3-branch switches in the templates into one call each.
Refs #1362.
* docs(cli): learning doc for MCP template literal type-match miss
Captures the failure mode that #1362 fixed: a Go normalizer helper
(primitiveKind) existed but the MCP templates did their own literal
comparison against Param.Type, so OpenAPI-parser canonical shapes
("int"/"float"/"bool") missed the WithNumber/WithBoolean branches.
Includes the grep checks to spot the same pattern elsewhere in the
template tree.
Refs #1362.
Files touched
A docs/solutions/logic-errors/mcp-template-literal-type-match-missed-openapi-shapes-2026-05-14.mdM internal/generator/cursor_param_test.goM internal/generator/generator.goM internal/generator/generator_test.goM internal/generator/templates/mcp_intents.go.tmplM internal/generator/templates/mcp_tools.go.tmplM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
Diff
commit 1f1b0bdb20325f512dce35283d724602c72ebcdd
Author: Trevin Chow <trevin@trevinchow.com>
Date: Thu May 14 00:29:58 2026 -0700
fix(cli): emit WithNumber/WithBoolean for OpenAPI-parsed numeric MCP params (#1372)
* fix(cli): normalize numeric/bool spec types in MCP binding emission
The MCP tool and intent templates picked the `mcplib.With*` binder with
a literal `eq .Type "integer"` / `eq .Type "boolean"` check. That worked
for internal-spec literals but missed every OpenAPI-parsed numeric and
bool: `mapSchemaType` normalizes to `"int"`, `"float"`, `"bool"`, and
the templates fell through to `WithString` for those. The JSON-RPC
input then arrived as a quoted string, and any type-strict endpoint
(Pushover's update_highest_message.json was the trigger case) rejected
the payload with HTTP 400.
Funnel through a new `mcpBindingFunc(t)` helper that runs `primitiveKind`
and returns the `With*` name, so OpenAPI shapes and internal-spec
literals both produce the same binding. Collapses three duplicated
3-branch switches in the templates into one call each.
Refs #1362.
* docs(cli): learning doc for MCP template literal type-match miss
Captures the failure mode that #1362 fixed: a Go normalizer helper
(primitiveKind) existed but the MCP templates did their own literal
comparison against Param.Type, so OpenAPI-parser canonical shapes
("int"/"float"/"bool") missed the WithNumber/WithBoolean branches.
Includes the grep checks to spot the same pattern elsewhere in the
template tree.
Refs #1362.
---
...-type-match-missed-openapi-shapes-2026-05-14.md | 109 +++++++++++++++++++++
internal/generator/cursor_param_test.go | 29 ++++++
internal/generator/generator.go | 19 ++++
internal/generator/generator_test.go | 51 ++++++++++
internal/generator/templates/mcp_intents.go.tmpl | 8 +-
internal/generator/templates/mcp_tools.go.tmpl | 32 +-----
.../printing-press-golden/internal/mcp/tools.go | 12 +--
7 files changed, 219 insertions(+), 41 deletions(-)
diff --git a/docs/solutions/logic-errors/mcp-template-literal-type-match-missed-openapi-shapes-2026-05-14.md b/docs/solutions/logic-errors/mcp-template-literal-type-match-missed-openapi-shapes-2026-05-14.md
new file mode 100644
index 00000000..79166b53
--- /dev/null
+++ b/docs/solutions/logic-errors/mcp-template-literal-type-match-missed-openapi-shapes-2026-05-14.md
@@ -0,0 +1,109 @@
+---
+title: "MCP template's literal `eq .Type \"integer\"` check missed OpenAPI-parsed `\"int\"` shape — every numeric body/query param bound as JSON string"
+date: 2026-05-14
+category: logic-errors
+module: internal/generator/templates
+problem_type: logic_error
+component: tooling
+symptoms:
+ - "Pushover's update_highest_message.json endpoint rejected every direct CLI invocation and every MCP tool call with HTTP 400 (`\"message\":\"789\"` instead of `\"message\":789`)."
+ - "Surfaced by Greptile on printing-press-library#511; local fixes shipped on commits 19bc3147 (inline novel-cmd) and 49156f77 (standalone CLI + MCP), filed upstream as #1362."
+ - "Visible in golden output: `WithString(\"limit\", ...)`, `WithString(\"year\", ...)`, `WithString(\"overwrite\", ...)`, `WithString(\"notify\", ...)` against an OpenAPI golden spec that declared those params as `type: integer` / `type: boolean`."
+root_cause: logic_error
+resolution_type: code_fix
+severity: high
+tags:
+ - generator-template
+ - mcp
+ - openapi-parser
+ - type-normalization
+ - primitive-kind
+ - withnumber
+ - withboolean
+ - integer-body-fields
+ - golden-harness
+---
+
+# MCP template's literal `eq .Type "integer"` check missed OpenAPI-parsed `"int"` shape
+
+## Problem
+
+`mcp_tools.go.tmpl` and `mcp_intents.go.tmpl` decided which `mcplib.With*` binder to emit using literal string comparison on `spec.Param.Type`:
+
+```gotemplate
+{{- if eq .Type "integer"}}
+ mcplib.WithNumber(...)
+{{- else if eq .Type "boolean"}}
+ mcplib.WithBoolean(...)
+{{- else}}
+ mcplib.WithString(...)
+{{- end}}
+```
+
+Two parser code paths populate `Param.Type`:
+
+- The **internal-spec** YAML parser preserves whatever the author wrote, so `type: integer` flows through verbatim.
+- The **OpenAPI** parser at `internal/openapi/parser.go:3616` (`mapSchemaType`) normalizes to canonical Go-shaped tokens: `openapi3.TypeInteger -> "int"`, `openapi3.TypeNumber -> "float"`, `openapi3.TypeBoolean -> "bool"`.
+
+The `if eq .Type "integer"` branch only matched the internal-spec literal. Every OpenAPI-parsed numeric body/query/path param fell through to `WithString`, so the JSON-RPC client sent `{"message":"789"}` and any type-strict endpoint (Pushover, several Stripe write paths, Linear filters, anything declaring `type: integer` body fields) returned HTTP 400.
+
+The CLI surface was *not* affected: `bodyVarDecls` / `bodyFlagRegs` / `bodyMapForEndpoint` route through `cobraFlagFunc` and `goType`, which both call `primitiveKind` — that helper already collapses `"integer"`/`"int"` to the same kind. The MCP template was the only emitter doing literal-match without normalization.
+
+## Symptoms
+
+- Pushover `update_highest_message.json` rejected `"message":"789"` (the StringVar flag value flowed straight into the body map and into the MCP wire payload).
+- Five sibling Pushover fields exhibited the same shape: `glances_update` `count` and `percent`; `messages_send` `priority`/`retry`/`expire`/`timestamp`; the `html`/`monospace`/`encrypted` integer-as-bool flags.
+- Visible in the golden harness once the fix landed: `testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go` flipped 6 lines from `WithString` to `WithNumber` (`limit`, `year`) and `WithBoolean` (`overwrite`, `notify`, `completed`).
+- Sampling against the published library by grep: every published CLI generated from an OpenAPI vendor spec emitted `WithString` for `type: integer` query/path params, so the bug was uniform across the catalog, not specific to a single API.
+
+## What Didn't Work
+
+- Looking only at the CLI emission. A first reading of the issue assumed the CLI `StringVar` shape needed a typed `Int64Var` patch; closer inspection of `cobraFlagFunc` / `primitiveKind` showed the CLI side was already correct for both spec shapes. The Pushover CLI's `var bodyMessage string` was a spec-author bug (the internal YAML declared `type: string` for `message`), not a generator bug. The generator bug was confined to the MCP template.
+- Special-casing the Pushover-named field. The fix needed to land in the generator (one place), not in the printed CLI (one site per affected field per CLI). The `printing-press-library#511` patches `19bc3147` and `49156f77` are local printed-CLI workarounds that the upstream fix renders unnecessary on regen.
+
+## Solution
+
+Add a single `mcpBindingFunc(t string) string` helper that funnels the type through the existing `primitiveKind` normalizer and returns the `mcplib.With*` name. Replace the three duplicated inline switches in the MCP templates with one call each.
+
+**Helper** (`internal/generator/generator.go`, alongside `cobraFlagFunc`):
+
+```go
+func mcpBindingFunc(t string) string {
+ switch primitiveKind(t) {
+ case "int", "float":
+ return "WithNumber"
+ case "bool":
+ return "WithBoolean"
+ default:
+ return "WithString"
+ }
+}
+```
+
+Registered in the template FuncMap immediately after `cobraFlagFunc` / `cobraFlagFuncForParam` (same "kind-mapping helper" cluster).
+
+**Template change** (`mcp_tools.go.tmpl`, `mcp_intents.go.tmpl`) — five call sites total: top-level params, top-level body, sub-resource params, sub-resource body in `mcp_tools.go.tmpl`, and the intent params loop in `mcp_intents.go.tmpl`:
+
+```gotemplate
+{{- range $endpoint.Body}}
+ mcplib.{{mcpBindingFunc .Type}}({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
+{{- end}}
+```
+
+**Tests**:
+
+- `TestMCPBindingFunc` (`cursor_param_test.go`, table-driven): asserts every cross-product of `{integer, int, number, float, boolean, bool, string, "", object, array, INTEGER}` maps to the expected `With*` name.
+- `TestMCPBindingNumericTypesAcrossSpecShapes` (`generator_test.go`, integration): generates a two-endpoint spec — one with OpenAPI-shape types (`int`, `bool`) and one with internal-spec literals (`integer`, `boolean`) — and asserts both shapes emit `WithNumber` / `WithBoolean` on body and query surfaces.
+
+**Golden update**: one expected file (`generate-golden-api/.../mcp/tools.go`), 6 lines. The fixture was already an OpenAPI spec with `type: integer` and `type: boolean` params, so the golden diff *is* the bug shape rendered visible.
+
+## Why this matters / how to spot the pattern
+
+This is the same shape as any "literal-match in a template against a typed-but-non-canonical input field" bug. The signal is: a Go helper (here `primitiveKind`) that accepts multiple aliases for the same kind, used everywhere *except* the templates, which do their own literal compares instead.
+
+Two checks to apply on adjacent code:
+
+1. Grep template tree for `eq .Type "<literal>"` clauses. Each one is a candidate for the same bug if the source field can carry parser-canonical synonyms (`int`/`integer`, `float`/`number`, `bool`/`boolean`, `array`/`list`, etc.).
+2. When a normalizer helper exists in Go (`primitiveKind`, `oneOf`, `canonicalize…`), templates calling raw `.Field` instead of `(normalize .Field)` are smells. Push the normalization through a one-line FuncMap helper rather than duplicating the switch in template-language.
+
+The CLI surface stayed correct here because `cobraFlagFunc` and `goType` both call `primitiveKind` internally. The MCP template was the outlier — that's worth a project-wide grep next time someone changes a `Param.Type` consumer.
diff --git a/internal/generator/cursor_param_test.go b/internal/generator/cursor_param_test.go
index 67233be9..ed7ebebd 100644
--- a/internal/generator/cursor_param_test.go
+++ b/internal/generator/cursor_param_test.go
@@ -110,6 +110,35 @@ func TestCobraFlagFuncAcceptsSpecScalarAliases(t *testing.T) {
assert.Equal(t, "StringVar", cobraFlagFuncForParam("cursor", "integer"))
}
+// TestMCPBindingFunc pins that OpenAPI-parsed shapes ("int", "float",
+// "bool") and internal-spec literals ("integer", "number", "boolean")
+// produce the same MCP binding.
+func TestMCPBindingFunc(t *testing.T) {
+ t.Parallel()
+ tests := []struct {
+ typ string
+ want string
+ }{
+ {"integer", "WithNumber"},
+ {"int", "WithNumber"},
+ {"number", "WithNumber"},
+ {"float", "WithNumber"},
+ {"boolean", "WithBoolean"},
+ {"bool", "WithBoolean"},
+ {"string", "WithString"},
+ {"", "WithString"},
+ {"object", "WithString"},
+ {"array", "WithString"},
+ {"INTEGER", "WithNumber"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.typ, func(t *testing.T) {
+ t.Parallel()
+ assert.Equal(t, tt.want, mcpBindingFunc(tt.typ))
+ })
+ }
+}
+
func TestDefaultAndZeroValuesAcceptSpecScalarAliases(t *testing.T) {
t.Parallel()
diff --git a/internal/generator/generator.go b/internal/generator/generator.go
index 68d2e38e..3024e054 100644
--- a/internal/generator/generator.go
+++ b/internal/generator/generator.go
@@ -207,6 +207,7 @@ func New(s *spec.APISpec, outputDir string) *Generator {
"goStoreType": goStoreType,
"cobraFlagFunc": cobraFlagFunc,
"cobraFlagFuncForParam": cobraFlagFuncForParam,
+ "mcpBindingFunc": mcpBindingFunc,
"defaultVal": defaultVal,
"defaultValForParam": defaultValForParam,
"isConstDefault": paramIsConstDefault,
@@ -3054,6 +3055,24 @@ func cobraFlagFunc(t string) string {
}
}
+// mcpBindingFunc returns the mcplib.With* function name used in MCP tool
+// input-schema registration so numeric fields bind as JSON numbers (not
+// quoted strings) and pass through the generic makeAPIHandler intact.
+// Funnels through primitiveKind so OpenAPI-parsed shapes ("int", "float",
+// "bool") and internal-spec literals ("integer", "number", "boolean")
+// produce the same binding. Object/array bodies fall back to WithString
+// because they ride the --body-json fallback or a JSON-string flag.
+func mcpBindingFunc(t string) string {
+ switch primitiveKind(t) {
+ case "int", "float":
+ return "WithNumber"
+ case "bool":
+ return "WithBoolean"
+ default:
+ return "WithString"
+ }
+}
+
// goTypeForParam returns the Go type for a parameter, overriding int→string
// for ID-like parameters to avoid overflow and zero-value confusion,
// numeric→string for pagination cursors so they survive scientific-notation
diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index 182469b8..afb3263d 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -9340,6 +9340,57 @@ func TestMCPHandlerPassesBodyArgsMap(t *testing.T) {
"PATCH branch must forward bodyArgs directly to the client")
}
+// TestMCPBindingNumericTypesAcrossSpecShapes pins template wiring: both
+// OpenAPI-parsed shapes ("int", "bool") and internal-spec literals
+// ("integer", "boolean") flow through mcpBindingFunc to WithNumber /
+// WithBoolean across body and query surfaces.
+func TestMCPBindingNumericTypesAcrossSpecShapes(t *testing.T) {
+ t.Parallel()
+
+ apiSpec := minimalSpec("mcp-numeric-binding")
+ apiSpec.Resources["messages"] = spec.Resource{
+ Description: "Messages",
+ Endpoints: map[string]spec.Endpoint{
+ "openapi-shape": {
+ Method: "POST",
+ Path: "/messages",
+ Description: "Send a message (OpenAPI-parsed types)",
+ Params: []spec.Param{
+ {Name: "silent", Type: "bool", Description: "Suppress notifications"},
+ },
+ Body: []spec.Param{
+ {Name: "priority", Type: "int", Required: true, Description: "Priority level"},
+ },
+ },
+ "internal-shape": {
+ Method: "POST",
+ Path: "/messages/legacy",
+ Description: "Send a message (internal-spec types)",
+ Params: []spec.Param{
+ {Name: "enabled", Type: "boolean", Description: "Enabled"},
+ },
+ Body: []spec.Param{
+ {Name: "count", Type: "integer", Required: true, Description: "Count"},
+ },
+ },
+ },
+ }
+
+ outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+ require.NoError(t, New(apiSpec, outputDir).Generate())
+
+ mcpSource := readGeneratedFile(t, outputDir, "internal", "mcp", "tools.go")
+
+ assert.Contains(t, mcpSource, `mcplib.WithBoolean("silent"`,
+ "OpenAPI bool query param must bind WithBoolean")
+ assert.Contains(t, mcpSource, `mcplib.WithNumber("priority", mcplib.Required()`,
+ "OpenAPI int body field must bind WithNumber (Pushover trigger case)")
+ assert.Contains(t, mcpSource, `mcplib.WithBoolean("enabled"`,
+ "internal-spec boolean query param must bind WithBoolean")
+ assert.Contains(t, mcpSource, `mcplib.WithNumber("count", mcplib.Required()`,
+ "internal-spec integer body field must bind WithNumber")
+}
+
func TestGeneratePublicParamNamesInPromotedExamples(t *testing.T) {
t.Parallel()
diff --git a/internal/generator/templates/mcp_intents.go.tmpl b/internal/generator/templates/mcp_intents.go.tmpl
index f26dadb7..8931a7e0 100644
--- a/internal/generator/templates/mcp_intents.go.tmpl
+++ b/internal/generator/templates/mcp_intents.go.tmpl
@@ -33,13 +33,7 @@ func RegisterIntents(s *server.MCPServer) {
mcplib.NewTool("{{.Name}}",
mcplib.WithDescription({{printf "%q" .Description}}),
{{- range .Params}}
-{{- if eq .Type "integer"}}
- mcplib.WithNumber("{{.Name}}"{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" .Description}})),
-{{- else if eq .Type "boolean"}}
- mcplib.WithBoolean("{{.Name}}"{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" .Description}})),
-{{- else}}
- mcplib.WithString("{{.Name}}"{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" .Description}})),
-{{- end}}
+ mcplib.{{mcpBindingFunc .Type}}("{{.Name}}"{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" .Description}})),
{{- end}}
),
handle{{pascal .Name}},
diff --git a/internal/generator/templates/mcp_tools.go.tmpl b/internal/generator/templates/mcp_tools.go.tmpl
index eec0339d..46a507ec 100644
--- a/internal/generator/templates/mcp_tools.go.tmpl
+++ b/internal/generator/templates/mcp_tools.go.tmpl
@@ -47,22 +47,10 @@ func RegisterTools(s *server.MCPServer) {
mcplib.NewTool({{printf "%q" (printf "%s_%s" (snake $name) (snake $eName))}},
mcplib.WithDescription({{printf "%q" (composeMCPDesc $.APISpec $resource $endpoint $.MCPPublicCount $.MCPTotalCount)}}),
{{- range $endpoint.Params}}
-{{- if eq .Type "integer"}}
- mcplib.WithNumber({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else if eq .Type "boolean"}}
- mcplib.WithBoolean({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else}}
- mcplib.WithString({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- end}}
+ mcplib.{{mcpBindingFunc .Type}}({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
{{- end}}
{{- range $endpoint.Body}}
-{{- if eq .Type "integer"}}
- mcplib.WithNumber({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else if eq .Type "boolean"}}
- mcplib.WithBoolean({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else}}
- mcplib.WithString({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- end}}
+ mcplib.{{mcpBindingFunc .Type}}({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
{{- end}}
{{- if $endpoint.BodyJSONFallback}}
mcplib.WithString("body_json"{{if $endpoint.BodyRequired}}, mcplib.Required(){{end}}, mcplib.Description("Request body as a JSON object string (this endpoint accepts a polymorphic schema: oneOf/anyOf)")),
@@ -94,22 +82,10 @@ func RegisterTools(s *server.MCPServer) {
mcplib.NewTool({{printf "%q" (printf "%s_%s_%s" (snake $name) (snake $subName) (snake $eName))}},
mcplib.WithDescription({{printf "%q" (composeMCPSubDesc $.APISpec $resource $subResource $endpoint $.MCPPublicCount $.MCPTotalCount)}}),
{{- range $endpoint.Params}}
-{{- if eq .Type "integer"}}
- mcplib.WithNumber({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else if eq .Type "boolean"}}
- mcplib.WithBoolean({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else}}
- mcplib.WithString({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- end}}
+ mcplib.{{mcpBindingFunc .Type}}({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
{{- end}}
{{- range $endpoint.Body}}
-{{- if eq .Type "integer"}}
- mcplib.WithNumber({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else if eq .Type "boolean"}}
- mcplib.WithBoolean({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- else}}
- mcplib.WithString({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
-{{- end}}
+ mcplib.{{mcpBindingFunc .Type}}({{printf "%q" (mcpInputName .)}}{{if .Required}}, mcplib.Required(){{end}}, mcplib.Description({{printf "%q" (mcpParamDesc .)}})),
{{- end}}
{{- if $endpoint.BodyJSONFallback}}
mcplib.WithString("body_json"{{if $endpoint.BodyRequired}}, mcplib.Required(){{end}}, mcplib.Description("Request body as a JSON object string (this endpoint accepts a polymorphic schema: oneOf/anyOf)")),
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
index 560ef840..67b50870 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
@@ -58,7 +58,7 @@ func RegisterTools(s *server.MCPServer) {
mcplib.NewTool("projects_list",
mcplib.WithDescription("List projects. Optional: status, limit (default: 25), cursor. Returns array of Project."),
mcplib.WithString("status", mcplib.Description("Status")),
- mcplib.WithString("limit", mcplib.Description("Limit")),
+ mcplib.WithNumber("limit", mcplib.Description("Limit")),
mcplib.WithString("cursor", mcplib.Description("Cursor")),
mcplib.WithReadOnlyHintAnnotation(true),
mcplib.WithDestructiveHintAnnotation(false),
@@ -70,7 +70,7 @@ func RegisterTools(s *server.MCPServer) {
mcplib.NewTool("projects_avatar_upload-project",
mcplib.WithDescription("Upload project avatar. Required: projectId. Optional: overwrite, caption, file."),
mcplib.WithString("projectId", mcplib.Required(), mcplib.Description("Project id")),
- mcplib.WithString("overwrite", mcplib.Description("Overwrite")),
+ mcplib.WithBoolean("overwrite", mcplib.Description("Overwrite")),
mcplib.WithString("caption", mcplib.Description("Caption")),
mcplib.WithString("file", mcplib.Description("File")),
mcplib.WithOpenWorldHintAnnotation(true),
@@ -82,7 +82,7 @@ func RegisterTools(s *server.MCPServer) {
mcplib.WithDescription("List project tasks. Required: projectId. Optional: priority, limit (default: 50), cursor. Returns array of Task."),
mcplib.WithString("projectId", mcplib.Required(), mcplib.Description("Project id")),
mcplib.WithString("priority", mcplib.Description("Priority")),
- mcplib.WithString("limit", mcplib.Description("Limit")),
+ mcplib.WithNumber("limit", mcplib.Description("Limit")),
mcplib.WithString("cursor", mcplib.Description("Cursor")),
mcplib.WithReadOnlyHintAnnotation(true),
mcplib.WithDestructiveHintAnnotation(false),
@@ -95,8 +95,8 @@ func RegisterTools(s *server.MCPServer) {
mcplib.WithDescription("Update project task. Required: projectId, taskId. Optional: notify, completed, priority (plus 1 more). Partial update."),
mcplib.WithString("projectId", mcplib.Required(), mcplib.Description("Project id")),
mcplib.WithString("taskId", mcplib.Required(), mcplib.Description("Task id")),
- mcplib.WithString("notify", mcplib.Description("Notify")),
- mcplib.WithString("completed", mcplib.Description("Completed")),
+ mcplib.WithBoolean("notify", mcplib.Description("Notify")),
+ mcplib.WithBoolean("completed", mcplib.Description("Completed")),
mcplib.WithString("priority", mcplib.Description("Priority")),
mcplib.WithString("title", mcplib.Description("Title")),
mcplib.WithOpenWorldHintAnnotation(true),
@@ -115,7 +115,7 @@ func RegisterTools(s *server.MCPServer) {
s.AddTool(
mcplib.NewTool("reports_summary_get-report-year",
mcplib.WithDescription("Get a report summary for a year. Required: year."),
- mcplib.WithString("year", mcplib.Required(), mcplib.Description("Year")),
+ mcplib.WithNumber("year", mcplib.Required(), mcplib.Description("Year")),
mcplib.WithReadOnlyHintAnnotation(true),
mcplib.WithDestructiveHintAnnotation(false),
mcplib.WithOpenWorldHintAnnotation(true),
← 725e063f chore(main): release 4.6.1 (#1363)
·
back to Cli Printing Press
·
test(cli): regression tests for body-flag identifier collisi d44587e9 →