Bug description
When the registry server ingests upstream server definitions, all fields on model.Argument except Name are discarded for both packageArguments and runtimeArguments. Only the flag name is stored; value, type, default, valueHint, and all other fields are permanently lost at ingest time.
Steps to reproduce
- Define a server YAML with
packageArguments or runtimeArguments containing value fields, e.g.:
"packageArguments": [
{"type": "named", "name": "--url", "value": "https://example.com/mcp"},
{"type": "named", "name": "--timeout", "value": "180"}
]
- Ingest the server into the registry
- Call GET
/registry/<name>/v0.1/servers and inspect the returned packageArguments
Expected behavior
The full model.Argument objects are preserved and returned by the API, including value, type, default, and valueHint fields:
"packageArguments": [
{"type": "named", "name": "--url", "value": "https://example.com/mcp"},
{"type": "named", "name": "--timeout", "value": "180"}
]
Actual behavior
Only flag names are returned. Positional arguments (no name) are reduced to {"type": ""} with no recoverable information:
"packageArguments": [
{"type": "", "name": "--url"},
{"type": "", "name": "--timeout"}
]
This makes it impossible for clients to render correct launch commands from the registry data.
Environment
- ToolHive Registry API version:
v1.5.0 (latest release, confirmed still present as of 2026-07-20)
Additional context
Root cause: The package_arguments and runtime_arguments DB columns are typed as TEXT[]. On write, extractArgumentValues discards everything except the flag name. On read, toArguments reconstructs with only Name populated:
// internal/sync/writer/db.go and internal/service/db/types.go
func extractArgumentValues(arguments []model.Argument) []string {
result := make([]string, len(arguments))
for i, arg := range arguments {
result[i] = arg.Name // value, type, default, valueHint all discarded
}
return result
}
func toArguments(strings []string) []model.Argument {
result := make([]model.Argument, len(strings))
for i, str := range strings {
result[i] = model.Argument{Name: str} // only Name restored
}
return result
}
Proposed fix: This is the same class of bug fixed for env_vars in PR #371, which changed that column from TEXT to JSONB and updated storage/retrieval to preserve the full object. The fix is identical — migrate package_arguments and runtime_arguments from TEXT[] to JSONB, update extractArgumentValues to serialise the full model.Argument as JSON, and update toArguments to deserialise back to []model.Argument:
func extractArgumentValues(arguments []model.Argument) []byte {
bytes, _ := json.Marshal(arguments)
return bytes
}
func toArguments(data []byte) []model.Argument {
var result []model.Argument
_ = json.Unmarshal(data, &result)
return result
}
Impact: Any server relying on packageArguments or runtimeArguments value fields renders incorrectly for all clients. We have worked around this in our internal client by storing argument overrides in _meta.io., but this is not a sustainable solution as it requires duplicating data across both packageArguments and _meta for every affected server.
Bug description
When the registry server ingests upstream server definitions, all fields on
model.Argumentexcept Name are discarded for bothpackageArgumentsandruntimeArguments. Only the flag name is stored; value, type, default, valueHint, and all other fields are permanently lost at ingest time.Steps to reproduce
packageArgumentsorruntimeArgumentscontaining value fields, e.g.:/registry/<name>/v0.1/serversand inspect the returnedpackageArgumentsExpected behavior
The full
model.Argumentobjects are preserved and returned by the API, including value, type, default, and valueHint fields:Actual behavior
Only flag names are returned. Positional arguments (no name) are reduced to
{"type": ""}with no recoverable information:This makes it impossible for clients to render correct launch commands from the registry data.
Environment
v1.5.0(latest release, confirmed still present as of 2026-07-20)Additional context
Root cause: The
package_argumentsandruntime_argumentsDB columns are typed asTEXT[]. On write,extractArgumentValuesdiscards everything except the flag name. On read,toArgumentsreconstructs with only Name populated:Proposed fix: This is the same class of bug fixed for
env_varsin PR #371, which changed that column fromTEXTtoJSONBand updated storage/retrieval to preserve the full object. The fix is identical — migratepackage_argumentsandruntime_argumentsfromTEXT[]toJSONB, updateextractArgumentValuesto serialise the full model.Argument as JSON, and updatetoArgumentsto deserialise back to[]model.Argument:Impact: Any server relying on
packageArgumentsorruntimeArgumentsvalue fields renders incorrectly for all clients. We have worked around this in our internal client by storing argument overrides in _meta.io., but this is not a sustainable solution as it requires duplicating data across bothpackageArgumentsand_metafor every affected server.