Skip to content

Expose Flag.SchemaType() for typed flag introspection #2326

@coilysiren

Description

@coilysiren

Summary

Expose typed-schema introspection on cli.Flag:

// SchemaType returns the JSON Schema type name for the value this flag
// accepts: "boolean", "integer", "number", "string", "array".
// Returns "" if the flag does not map cleanly to a JSON Schema type.
//
// For slice flags, the returned type is "array"; callers can use
// SchemaItemsType for the element type.
func (f Flag) SchemaType() string
func (f Flag) SchemaItemsType() string // optional, for slice flags

Motivation

cli-mcp projects a urfave/cli command tree as a Model Context Protocol server. MCP tools carry a JSON Schema for their input, derived from the command's flags. Today this is a mechanical type-switch:

switch f.(type) {
case *cli.BoolFlag:
    s.Type = "boolean"
case *cli.IntFlag, *cli.Int8Flag, *cli.Int16Flag, *cli.Int32Flag, *cli.Int64Flag:
    s.Type = "integer"
case *cli.UintFlag, *cli.Uint8Flag, ... :
    s.Type = "integer"
case *cli.FloatFlag:
    s.Type = "number"
case *cli.StringSliceFlag:
    s.Type = "array"  // items: string
case *cli.IntSliceFlag:
    s.Type = "array"  // items: integer
// ... etc
}

This is brittle - every new flag type urfave ships (or that consumers add via the third-party flag system) requires a code change in every extension. A SchemaType() method on Flag (or a Type constant) would let extensions stop pattern-matching on concrete types.

This same need exists for:

  • cli-web-ops — rendering JSON Schema input as HTML form fields (<input type="text|number|checkbox">)
  • cli-web-docs — rendering flag types in generated documentation
  • urfave/cli-docs itself — currently maps flag types in Markdown output by similar type switching

Alternatives considered

  • A standalone cli-schema-types helper. Forces a hard-coded import dependency just for type strings.
  • Reflection. Works but is fragile and slow.

The right home is the Flag interface itself, since the flag knows its own type.

Happy to send a PR if there's appetite. Could plausibly be hidden behind a feature flag or new DocFlag interface to preserve backwards compatibility with third-party flag types.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions