Skip to content

Add stateless field to registry server types#89

Open
gkatz2 wants to merge 1 commit intostacklok:mainfrom
gkatz2:fix/registry-stateless-field-88
Open

Add stateless field to registry server types#89
gkatz2 wants to merge 1 commit intostacklok:mainfrom
gkatz2:fix/registry-stateless-field-88

Conversation

@gkatz2
Copy link
Copy Markdown

@gkatz2 gkatz2 commented Apr 15, 2026

Summary

  • Registry entries cannot declare that a server is stateless (POST-only, no SSE/GET). Users must pass --stateless manually on every thv run invocation. Adding the field to the type system lets registries declare this property so it applies automatically.
  • Adds Stateless bool to BaseServerMetadata, ServerExtensions, both legacy registry schema definitions (server and remote_server), and the publisher-provided schema. Updates bidirectional converters to preserve the field through round-trips.

Fixes #88

Design notes

Why BaseServerMetadata (shared) rather than RemoteServerMetadata only? Stateless mode applies to both remote servers and container workloads — stacklok/toolhive#4515 explicitly supports both. Placing the field on BaseServerMetadata alongside Transport is consistent with how other transport-level properties are modeled. The trade-off is that ImageMetadata inherits a field that's irrelevant for stdio containers, but this mirrors existing fields like TargetPort and ProxyPort that only apply to HTTP transports.

Interface addition. GetStateless() is added to ServerMetadata, following the established pattern for all 14 existing BaseServerMetadata getters. Unlike ProxyPort (which predates the interface and is duplicated on both concrete types), Stateless follows the dominant pattern. No downstream repo implements ServerMetadata directly — all consumers use the concrete types, which inherit the getter through embedding.

Test plan

  • Unit tests: converter round-trip for stateless=true on both remote and image servers
  • Unit tests: YAML/JSON marshal/unmarshal preserves the field
  • Unit tests: nil receiver returns false
  • Unit tests: GetStateless() through ServerMetadata interface
  • Existing "all fields" round-trip test updated to include stateless
  • task lint-fix — 0 issues
  • task test — all pass with race detection
  • task license-check — all headers present

Generated with Claude Code

Registry entries cannot declare that a server is stateless
(POST-only, no SSE/GET). Users must pass --stateless manually
on every thv run invocation. Adding the field to the type
system lets registries declare this property so it applies
automatically.

Fixes stacklok#88

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Greg Katz <gkatz@indeed.com>
@gkatz2 gkatz2 force-pushed the fix/registry-stateless-field-88 branch from 532c262 to 4201eaf Compare April 21, 2026 22:28
@jerm-dro
Copy link
Copy Markdown

Hey @gkatz2, thanks for the thorough write-up and for following up on the --stateless work!

I've been thinking about this, and I'm hesitant to promote stateless to a first-class registry property. My concern is that stateless mode is really a runtime behavior of the server. Whether it accepts only POST and doesn't serve SSE on GET feels like something the proxy should be able to detect automatically rather than requiring explicit declaration.

For example, when thv run starts proxying a server, it could probe the server's behavior (e.g., attempt a GET and observe a 405 or lack of SSE response) and automatically enable stateless mode. This would mean:

  1. No --stateless flag needed on thv run
  2. No registry metadata needed
  3. It "just works" for any stateless server without users needing to know about the distinction

Before we add this to the type system, could you explore whether automatic detection at runtime is feasible for your use case?

@gkatz2
Copy link
Copy Markdown
Author

gkatz2 commented Apr 24, 2026

Thanks for the thoughtful feedback, @jerm-dro!

Auto-detection is a good idea and the spec is clear (MUST return 405 on GET for stateless servers), so it would work for compliant servers. Two complications make it insufficient as the sole mechanism: some frameworks don't return 405 by default when a route is only registered for POST (e.g., Express.js returns 404), and intermediary proxies can return their own responses before the request reaches the MCP server. In those cases you'd still need an explicit override.

The registry field covers all cases declaratively. The operator knows their server is stateless and declares it, same as transport type or OAuth config. Even if auto-detection lands later, the registry field gives operators a reliable override when detection gets it wrong.

What do you think?

@jerm-dro
Copy link
Copy Markdown

Thanks for the context @gkatz2. I had not considered the possibility that auto-detection would fail. For the Express.js example, would it be possible to fix address the root cause upstream rather than working around it here? Is that much effort?

I'm curious what @rdimitrov thinks about this. What's the cost/resistance to including this workaround?

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.

Add stateless field to registry server types

2 participants